'use client'; import {useState} from 'react'; import {proportional, pixel} from '@astryxdesign/core/Table'; import type {TableColumn} from '@astryxdesign/core/Table'; import {VStack, HStack} from '@astryxdesign/core/Layout'; import {Text} from '@astryxdesign/core/Text'; import {Button} from '@astryxdesign/core/Button'; import {StatusDot} from '@astryxdesign/core/StatusDot'; import {DropdownMenu} from '@astryxdesign/core/DropdownMenu'; import {Icon} from '@astryxdesign/core/Icon'; import {useToast} from '@astryxdesign/core/Toast'; import {PanelCard} from '@/shared/components/patterns/PanelCard'; import {ResponsiveTable} from '@/shared/components/patterns/ResponsiveTable'; import {SkeletonRows} from '@/shared/components/patterns/LoadingState'; import {EmptyPanel} from '@/shared/components/patterns/EmptyPanel'; import {useWorkspace} from '@/shared/providers/WorkspaceProvider'; import {useSession} from '@/features/auth/providers/SessionProvider'; import {hasRole} from '@/features/auth/services/roles'; import {useSites} from '@/features/stores/hooks/useSites'; import {OpenShopDialog} from '@/features/stores/components/OpenShopDialog'; import {RenameShopDialog} from '@/features/stores/components/RenameShopDialog'; import {RemoveShopDialog} from '@/features/stores/components/RemoveShopDialog'; import type {Site} from '@/features/stores/types/site'; type SiteRow = Site & Record; /** * The company's shops, from the platform — open, rename, remove. * * This screen used to be a hardcoded list of five Bengaluru shops held in * local state: adding one "worked" until the page reloaded. It now reads * GET /api/sites and writes through POST / PATCH / DELETE on the same * resource, and every write re-reads rather than splicing local state. * * Who is offered what mirrors the platform's own rules — opening and removing * a shop is the owner's, renaming is a manager's too — but the platform is * what enforces them; hiding a button is courtesy, not security. * * Cameras and the shop PC are set up per shop on the Store page, not here: * this is the directory, that is the equipment. */ export function StoreManagement() { const toast = useToast(); const sites = useSites(); const {refreshStores} = useWorkspace(); const {user} = useSession(); const isOwner = hasRole(user?.role, 'owner'); const isManager = hasRole(user?.role, 'manager'); const [opening, setOpening] = useState(false); const [renaming, setRenaming] = useState(null); const [removing, setRemoving] = useState(null); /** The settings table and the global switcher each hold a copy; refresh both. */ function reload() { sites.refetch(); refreshStores(); } const columns: TableColumn[] = [ { key: 'name', header: 'Shop', width: proportional(2), renderCell: (row) => ( {row.name} {row.id} ), }, { key: 'timezone', header: 'Timezone', width: proportional(1.2), renderCell: (row) => ( {row.timezone || '—'} ), }, { key: 'isOnline', header: 'Shop PC', width: pixel(150), renderCell: (row) => ( {row.isOnline === null ? 'Not reported' : row.isOnline ? 'Online' : 'Offline'} ), }, { key: 'camerasUp', header: 'Cameras', width: pixel(110), renderCell: (row) => ( {row.camerasUp === null || row.camerasTotal === null ? '—' : `${row.camerasUp}/${row.camerasTotal} up`} ), }, { key: 'actions', header: 'Actions', align: 'center', width: pixel(140), renderCell: (row) => isManager ? ( , }} menuWidth={180} items={[ {label: 'Rename', onClick: () => setRenaming(row)}, ...(isOwner ? [ {type: 'divider' as const}, {label: 'Remove shop', onClick: () => setRemoving(row)}, ] : []), ]} /> ) : null, }, ]; return ( setOpening(true)} /> ) : undefined } resource={sites} loading={} empty={ } > {(rows) => ( )} {opening ? ( setOpening(false)} onOpened={() => { setOpening(false); toast({body: 'Shop opened. Add its cameras on the Store page.'}); reload(); }} /> ) : null} {renaming ? ( setRenaming(null)} onSaved={() => { setRenaming(null); toast({body: 'Shop updated'}); reload(); }} /> ) : null} {removing ? ( setRemoving(null)} onRemoved={() => { setRemoving(null); toast({body: 'Shop removed'}); reload(); }} /> ) : null} ); }