import { Card, Descriptions, Tabs, Table, Tag, Typography, Button, Space, Spin, Result } from 'antd'; import type { ColumnsType } from 'antd/es/table'; import { ArrowLeftOutlined } from '@ant-design/icons'; import { useQuery } from '@tanstack/react-query'; import { useNavigate, useParams } from 'react-router-dom'; import { fetchFleetCustomerDetail, type FleetSite, type FleetDevice, type FleetRecentMeasurement, type FleetIngestEvent, } from '../api/fleet'; const { Text } = Typography; export function AdminCustomerDetailPage() { const { id = '' } = useParams<{ id: string }>(); const navigate = useNavigate(); const { data, isLoading, error } = useQuery({ queryKey: ['fleet-customer', id], queryFn: () => fetchFleetCustomerDetail(id), refetchInterval: 30_000, }); if (isLoading) return
; if (error || !data) { return navigate('/admin/customers')}>Back} />; } const siteCols: ColumnsType = [ { title: 'Name', dataIndex: 'name', key: 'name' }, { title: 'Address', dataIndex: 'address', key: 'addr', render: v => v ?? }, { title: 'Active', dataIndex: 'isActive', key: 'a', render: (v: boolean) => v ? Active : Inactive }, ]; const deviceCols: ColumnsType = [ { title: 'Name', dataIndex: 'name', key: 'name' }, { title: 'External ID', dataIndex: 'externalId', key: 'ext', render: v => {v} }, { title: 'Description', dataIndex: 'description', key: 'desc', render: v => v ?? }, { title: 'Active', dataIndex: 'isActive', key: 'a', render: (v: boolean) => v ? Active : Inactive }, ]; const measCols: ColumnsType = [ { title: 'Time (UTC)', dataIndex: 'time', key: 't', render: (v: string) => new Date(v).toISOString().replace('T', ' ').slice(0, 19) }, { title: 'Device', dataIndex: 'deviceName', key: 'd' }, { title: 'Active power (kW)', dataIndex: 'activePowerKw', key: 'p', render: (v: number) => v.toFixed(3) }, { title: 'kWh imported (cumulative)', dataIndex: 'energyImportedKwh', key: 'e', render: (v: number | null) => v == null ? '—' : v.toFixed(2) }, ]; const eventCols: ColumnsType = [ { title: 'Received (UTC)', dataIndex: 'receivedAt', key: 'r', render: (v: string) => new Date(v).toISOString().replace('T', ' ').slice(0, 19) }, { title: 'Type', dataIndex: 'batchType', key: 'bt' }, { title: 'Accepted', dataIndex: 'rowsAccepted', key: 'a' }, { title: 'Rejected', dataIndex: 'rowsRejected', key: 'rj', render: (v: number) => v > 0 ? {v} : v }, { title: 'Bytes', dataIndex: 'batchBytes', key: 'b' }, { title: 'Time spread', dataIndex: 'timeSpread', key: 'ts', render: (v: string | null) => v ?? '—' }, { title: 'Error', dataIndex: 'error', key: 'e', render: (v: string | null) => v ? {v} : '—' }, ]; return ( {data.code} · {data.name} {data.isActive ? Active : Disabled} {data.id} {new Date(data.createdAt).toLocaleString()} {data.firstSeenAt ? new Date(data.firstSeenAt).toLocaleString() : Never} {data.lastSeenAt ? new Date(data.lastSeenAt).toLocaleString() : Never} rowKey="receivedAt" columns={eventCols} dataSource={data.recentIngestEvents} pagination={false} size="small" />, }, { key: 'measurements', label: `Recent measurements (${data.recentMeasurements.length})`, children: rowKey={(r) => `${r.time}-${r.deviceId}`} columns={measCols} dataSource={data.recentMeasurements} pagination={false} size="small" />, }, { key: 'sites', label: `Sites (${data.sites.length})`, children: rowKey="id" columns={siteCols} dataSource={data.sites} pagination={false} size="small" />, }, { key: 'devices', label: `Devices (${data.devices.length})`, children: rowKey="id" columns={deviceCols} dataSource={data.devices} pagination={false} size="small" />, }, ]} /> ); }