import { Button, Card, Col, Row, Space, Statistic, Table, Tag, Typography, Empty } from 'antd'; import type { ColumnsType } from 'antd/es/table'; import { ApartmentOutlined, ThunderboltOutlined, TeamOutlined, CheckCircleOutlined, DollarOutlined, DownloadOutlined, } from '@ant-design/icons'; import { useQuery } from '@tanstack/react-query'; import { useNavigate } from 'react-router-dom'; import { fetchFleetDashboard, type FleetCustomerSummary } from '../api/fleet'; import { downloadFleetDashboardXlsx } from '../api/dashboard'; const { Text } = Typography; export function AdminFleetDashboardPage() { const navigate = useNavigate(); const { data, isLoading } = useQuery({ queryKey: ['fleet-dashboard'], queryFn: fetchFleetDashboard, refetchInterval: 30_000, }); const columns: ColumnsType = [ { title: 'Code', dataIndex: 'code', key: 'code', render: (v) => {v} }, { title: 'Name', dataIndex: 'name', key: 'name' }, { title: 'Status', dataIndex: 'isActive', key: 'active', render: (v: boolean) => v ? Active : Disabled, }, { title: 'Last push', dataIndex: 'lastSeenAt', key: 'last', render: (v: string | null) => (v ? lagDescription(v) : Never), }, { title: 'Sites', dataIndex: 'sites', key: 'sites' }, { title: 'Devices', dataIndex: 'devices', key: 'devices' }, { title: 'Today (rows)', dataIndex: 'measurementsToday', key: 'mt', render: (n: number) => n.toLocaleString(), }, { title: 'Today (kWh imp.)', dataIndex: 'kwhImportedToday', key: 'kwh', render: (v: number | null) => (v == null ? '—' : v.toFixed(2)), }, { title: 'Today (cost)', dataIndex: 'costToday', key: 'cost', render: (v: number | null) => v == null ? : {v.toFixed(2)}, }, ]; return (
} loading={isLoading} /> } loading={isLoading} /> } loading={isLoading} /> } loading={isLoading} /> } valueStyle={{ color: '#3f8600' }} loading={isLoading} /> } > {data && data.customers.length === 0 ? ( ) : ( rowKey="id" columns={columns} dataSource={data?.customers ?? []} loading={isLoading} pagination={{ pageSize: 25 }} onRow={(record) => ({ onClick: () => navigate(`/admin/customers/${record.id}`), style: { cursor: 'pointer' }, })} /> )}
); } function lagDescription(iso: string): React.ReactNode { const ts = new Date(iso).getTime(); const ageMs = Date.now() - ts; const ageMin = Math.floor(ageMs / 60_000); if (ageMin < 1) return just now; if (ageMin < 5) return {ageMin}m ago; if (ageMin < 60) return {ageMin}m ago; const ageHr = Math.floor(ageMin / 60); if (ageHr < 24) return {ageHr}h ago; return {Math.floor(ageHr / 24)}d ago; }