62 lines
2.1 KiB
TypeScript
62 lines
2.1 KiB
TypeScript
'use client';
|
|
|
|
import {VStack} from '@astryxdesign/core/Layout';
|
|
import {Breadcrumbs, BreadcrumbItem} from '@astryxdesign/core/Breadcrumbs';
|
|
import {PageHeader} from '@/shared/components/primitives/PageHeader';
|
|
import {AsyncBoundary} from '@/shared/components/data/AsyncBoundary';
|
|
import {SkeletonCardGrid} from '@/shared/components/patterns/LoadingState';
|
|
import {EmptyPanel} from '@/shared/components/patterns/EmptyPanel';
|
|
import {useSites} from '@/features/stores/hooks/useSites';
|
|
import {ShopSection} from '@/features/stores/components/ShopSection';
|
|
|
|
/**
|
|
* Live cameras — the estate, from GET /api/sites.
|
|
*
|
|
* Reached from the "Live cameras" button on the Store page. Every shop, its
|
|
* cameras, and the shop PC that watches them: live view, health check,
|
|
* enrolment and camera management all live here, so the Store page itself can
|
|
* open on performance.
|
|
*
|
|
* Health fields are nullable and rendered as "—" when the platform does not
|
|
* report them. A deployment that sends no camera health is not a deployment
|
|
* with zero cameras up, and printing "0/0" for "not reported" makes a working
|
|
* estate look broken.
|
|
*/
|
|
export default function LiveCamerasPage() {
|
|
const sites = useSites();
|
|
|
|
return (
|
|
<VStack gap={5}>
|
|
<Breadcrumbs variant="supporting">
|
|
<BreadcrumbItem href="/stores">Store</BreadcrumbItem>
|
|
<BreadcrumbItem isCurrent>Live cameras</BreadcrumbItem>
|
|
</Breadcrumbs>
|
|
|
|
<PageHeader
|
|
title="Live cameras"
|
|
description="Every shop, its cameras, and the shop PC that watches them."
|
|
/>
|
|
|
|
<AsyncBoundary
|
|
resource={sites}
|
|
loading={<SkeletonCardGrid count={4} height={170} />}
|
|
empty={
|
|
<EmptyPanel
|
|
icon="stores"
|
|
title="No stores yet"
|
|
description="Shops appear here once they are registered on the platform."
|
|
/>
|
|
}
|
|
>
|
|
{(rows) => (
|
|
<VStack gap={6}>
|
|
{rows.map((site) => (
|
|
<ShopSection key={site.id} site={site} />
|
|
))}
|
|
</VStack>
|
|
)}
|
|
</AsyncBoundary>
|
|
</VStack>
|
|
);
|
|
}
|