diff --git a/src/app/config/cameraConfig.ts b/src/app/config/cameraConfig.ts new file mode 100644 index 0000000..3ace17d --- /dev/null +++ b/src/app/config/cameraConfig.ts @@ -0,0 +1,12 @@ +// Camera configuration - add more cameras here as needed +export const CAMERA_IDS = ["A", "B", "C"] as const; + +export type CameraID = (typeof CAMERA_IDS)[number]; + +export const DEFAULT_REGIONS = [ + { name: "Bay 1", brushColour: "#ff0000" }, + { name: "Bay 2", brushColour: "#00ff00" }, + { name: "Bay 3", brushColour: "#0400ff" }, + { name: "Bay 4", brushColour: "#ffff00" }, + { name: "Bay 5", brushColour: "#fc35db" }, +]; diff --git a/src/app/context/WebSocketContext.ts b/src/app/context/WebSocketContext.ts index 551e006..a73516b 100644 --- a/src/app/context/WebSocketContext.ts +++ b/src/app/context/WebSocketContext.ts @@ -17,9 +17,7 @@ type CameraSocketState = { export type WebSocketConextValue = { info: InfoSocketState; - cameraFeedA: CameraSocketState; - cameraFeedB: CameraSocketState; - cameraFeedC: CameraSocketState; + cameraFeed: CameraSocketState; }; export const WebsocketContext = createContext(null); @@ -31,6 +29,4 @@ const useWebSocketContext = () => { }; export const useInfoSocket = () => useWebSocketContext().info; -export const useCameraFeedASocket = () => useWebSocketContext().cameraFeedA; -export const useCameraFeedBSocket = () => useWebSocketContext().cameraFeedB; -export const useCameraFeedCSocket = () => useWebSocketContext().cameraFeedC; +export const useCameraFeedSocket = () => useWebSocketContext().cameraFeed; diff --git a/src/app/providers/CameraFeedProvider.tsx b/src/app/providers/CameraFeedProvider.tsx index 5c0b39e..16eee91 100644 --- a/src/app/providers/CameraFeedProvider.tsx +++ b/src/app/providers/CameraFeedProvider.tsx @@ -3,13 +3,12 @@ import { CameraFeedContext } from "../context/CameraFeedContext"; import { initialState, reducer } from "../reducers/cameraFeedReducer"; import { useBlackBoard } from "../../hooks/useBlackBoard"; import type { CameraFeedState } from "../../types/types"; -import { useCameraZoom } from "../../features/cameras/hooks/useCameraZoom"; + +import { CAMERA_IDS } from "../config/cameraConfig"; +import CameraZoomFetcher from "./CameraZoomFetcher"; export const CameraFeedProvider = ({ children }: { children: ReactNode }) => { const { blackboardMutation } = useBlackBoard(); - const { cameraZoomQuery: cameraZoomQueryA } = useCameraZoom("A"); - const { cameraZoomQuery: cameraZoomQueryB } = useCameraZoom("B"); - const { cameraZoomQuery: cameraZoomQueryC } = useCameraZoom("C"); const [state, dispatch] = useReducer(reducer, initialState); @@ -23,52 +22,25 @@ export const CameraFeedProvider = ({ children }: { children: ReactNode }) => { const cameraFeedData: CameraFeedState = result.result; const recontructedState = { ...cameraFeedData, - paintedCells: { - A: new Map(cameraFeedData.paintedCells.A), - B: new Map(cameraFeedData.paintedCells.B), - C: new Map(cameraFeedData.paintedCells.C), - }, + paintedCells: CAMERA_IDS.reduce( + (acc, id) => { + acc[id] = new Map(cameraFeedData.paintedCells[id]); + return acc; + }, + {} as typeof cameraFeedData.paintedCells, + ), }; dispatch({ type: "SET_CAMERA_FEED_DATA", cameraState: recontructedState }); }; fetchBlackBoardData(); }, []); - useEffect(() => { - const fetchZoomLevels = async () => { - const [resultA, resultB, resultC] = await Promise.all([ - cameraZoomQueryA.refetch(), - cameraZoomQueryB.refetch(), - cameraZoomQueryC.refetch(), - ]); - - const zoomLevelAnumber = parseFloat(resultA.data?.propPhysCurrent?.value); - const zoomLevelBnumber = parseFloat(resultB.data?.propPhysCurrent?.value); - const zoomLevelCnumber = parseFloat(resultC.data?.propPhysCurrent?.value); - - if (resultA.data) { - dispatch({ - type: "SET_ZOOM_LEVEL", - payload: { cameraFeedID: "A", zoomLevel: zoomLevelAnumber }, - }); - } - - if (resultB.data) { - dispatch({ - type: "SET_ZOOM_LEVEL", - payload: { cameraFeedID: "B", zoomLevel: zoomLevelBnumber }, - }); - } - - if (resultC.data) { - dispatch({ - type: "SET_ZOOM_LEVEL", - payload: { cameraFeedID: "C", zoomLevel: zoomLevelCnumber }, - }); - } - }; - fetchZoomLevels(); - }, []); - - return {children}; + return ( + + {CAMERA_IDS.map((cameraId) => ( + + ))} + {children} + + ); }; diff --git a/src/app/providers/CameraZoomFetcher.tsx b/src/app/providers/CameraZoomFetcher.tsx new file mode 100644 index 0000000..e0c2157 --- /dev/null +++ b/src/app/providers/CameraZoomFetcher.tsx @@ -0,0 +1,31 @@ +import { useEffect } from "react"; +import { useCameraZoom } from "../../features/cameras/hooks/useCameraZoom"; +import type { CameraFeedAction } from "../../types/types"; +import type { CameraID } from "../config/cameraConfig"; + +type CameraZoomFetcherProps = { + cameraId: CameraID; + dispatch: (action: CameraFeedAction) => void; +}; + +const CameraZoomFetcher = ({ cameraId, dispatch }: CameraZoomFetcherProps) => { + const { cameraZoomQuery } = useCameraZoom(cameraId); + + useEffect(() => { + const fetchZoomLevel = async () => { + const result = await cameraZoomQuery.refetch(); + if (result.data && typeof result.data.zoomLevel === "number") { + dispatch({ + type: "SET_ZOOM_LEVEL", + payload: { cameraFeedID: cameraId, zoomLevel: result.data.zoomLevel }, + }); + } + }; + + fetchZoomLevel(); + }, [cameraId, cameraZoomQuery, dispatch]); + + return null; +}; + +export default CameraZoomFetcher; diff --git a/src/app/providers/WebSocketProvider.tsx b/src/app/providers/WebSocketProvider.tsx index 66ce180..b2aa0c1 100644 --- a/src/app/providers/WebSocketProvider.tsx +++ b/src/app/providers/WebSocketProvider.tsx @@ -3,18 +3,28 @@ import { WebsocketContext, type WebSocketConextValue } from "../context/WebSocke import useWebSocket from "react-use-websocket"; import { wsConfig } from "../config/wsconfig"; import type { CameraZoomData, InfoBarData } from "../../types/types"; +import { CAMERA_IDS } from "../config/cameraConfig"; +import { CAMBASE_WS } from "../../utils/config"; +import { useCameraFeedContext } from "../context/CameraFeedContext"; type WebSocketProviderProps = { children: ReactNode; }; export const WebSocketProvider = ({ children }: WebSocketProviderProps) => { + const { state } = useCameraFeedContext(); const [systemData, setSystemData] = useState(null); const [socketData, setSocketData] = useState(null); const infoSocket = useWebSocket(wsConfig.infoBar, { share: true, shouldReconnect: () => true }); - const cameraFeedASocket = useWebSocket(wsConfig.cameraFeedA, { share: true, shouldReconnect: () => true }); - const cameraFeedBSocket = useWebSocket(wsConfig.cameraFeedB, { share: true, shouldReconnect: () => true }); - const cameraFeedCSocket = useWebSocket(wsConfig.cameraFeedC, { share: true, shouldReconnect: () => true }); + const sockets = CAMERA_IDS.reduce( + (acc, id) => { + acc[id] = `${CAMBASE_WS}/websocket-Camera${id}-live-video`; + return acc; + }, + {} as Record, + ); + const cameraFeedID = state.cameraFeedID; + const cameraFeed = useWebSocket(sockets[cameraFeedID], { share: true, shouldReconnect: () => true }); useEffect(() => { async function parseData() { @@ -23,20 +33,15 @@ export const WebSocketProvider = ({ children }: WebSocketProviderProps) => { const data = JSON.parse(text); setSystemData(data); } - if (cameraFeedASocket.lastMessage || cameraFeedBSocket.lastMessage || cameraFeedCSocket.lastMessage) { - const message = cameraFeedASocket.lastMessage || cameraFeedBSocket.lastMessage || cameraFeedCSocket.lastMessage; + if (cameraFeed.lastMessage) { + const message = cameraFeed.lastMessage; const data = await message?.data.text(); const parsedData: CameraZoomData = JSON.parse(data || ""); setSocketData(parsedData); } } parseData(); - }, [ - cameraFeedASocket.lastMessage, - cameraFeedBSocket.lastMessage, - cameraFeedCSocket.lastMessage, - infoSocket.lastMessage, - ]); + }, [cameraFeed.lastMessage, infoSocket.lastMessage]); const value = useMemo( () => ({ @@ -45,32 +50,16 @@ export const WebSocketProvider = ({ children }: WebSocketProviderProps) => { readyState: infoSocket.readyState, sendJson: infoSocket.sendJsonMessage, }, - cameraFeedA: { + cameraFeed: { data: socketData, - readyState: cameraFeedASocket.readyState, + readyState: cameraFeed.readyState, - send: cameraFeedASocket.sendMessage, - }, - cameraFeedB: { - data: socketData, - readyState: cameraFeedBSocket.readyState, - - send: cameraFeedBSocket.sendMessage, - }, - cameraFeedC: { - data: socketData, - readyState: cameraFeedCSocket.readyState, - - send: cameraFeedCSocket.sendMessage, + send: cameraFeed.sendMessage, }, }), [ - cameraFeedASocket.readyState, - cameraFeedASocket.sendMessage, - cameraFeedBSocket.readyState, - cameraFeedBSocket.sendMessage, - cameraFeedCSocket.readyState, - cameraFeedCSocket.sendMessage, + cameraFeed.readyState, + cameraFeed.sendMessage, infoSocket.readyState, infoSocket.sendJsonMessage, socketData, diff --git a/src/app/reducers/cameraFeedReducer.ts b/src/app/reducers/cameraFeedReducer.ts index 898435b..9903f51 100644 --- a/src/app/reducers/cameraFeedReducer.ts +++ b/src/app/reducers/cameraFeedReducer.ts @@ -1,47 +1,38 @@ import type { CameraFeedAction, CameraFeedState, PaintedCell } from "../../types/types"; +import { CAMERA_IDS, DEFAULT_REGIONS, type CameraID } from "../config/cameraConfig"; export const initialState: CameraFeedState = { - cameraFeedID: "A", - paintedCells: { - A: new Map(), - B: new Map(), - C: new Map(), - }, - regionsByCamera: { - A: [ - { name: "Bay 1", brushColour: "#ff0000" }, - { name: "Bay 2", brushColour: "#00ff00" }, - { name: "Bay 3", brushColour: "#0400ff" }, - { name: "Bay 4", brushColour: "#ffff00" }, - { name: "Bay 5", brushColour: "#fc35db" }, - ], - B: [ - { name: "Bay 1", brushColour: "#ff0000" }, - { name: "Bay 2", brushColour: "#00ff00" }, - { name: "Bay 3", brushColour: "#0400ff" }, - { name: "Bay 4", brushColour: "#ffff00" }, - { name: "Bay 5", brushColour: "#fc35db" }, - ], - C: [ - { name: "Bay 1", brushColour: "#ff0000" }, - { name: "Bay 2", brushColour: "#00ff00" }, - { name: "Bay 3", brushColour: "#0400ff" }, - { name: "Bay 4", brushColour: "#ffff00" }, - { name: "Bay 5", brushColour: "#fc35db" }, - ], - }, + cameraFeedID: CAMERA_IDS[0], + paintedCells: CAMERA_IDS.reduce( + (acc, id) => { + acc[id] = new Map(); + return acc; + }, + {} as Record>, + ), + regionsByCamera: CAMERA_IDS.reduce( + (acc, id) => { + acc[id] = DEFAULT_REGIONS; + return acc; + }, + {} as Record, + ), selectedRegionIndex: 0, - modeByCamera: { - A: "painter", - B: "painter", - C: "painter", - }, - zoomLevel: { - A: 1, - B: 1, - C: 1, - }, + modeByCamera: CAMERA_IDS.reduce( + (acc, id) => { + acc[id] = "painter"; + return acc; + }, + {} as Record, + ), + zoomLevel: CAMERA_IDS.reduce( + (acc, id) => { + acc[id] = 1; + return acc; + }, + {} as Record, + ), }; export function reducer(state: CameraFeedState, action: CameraFeedAction) { diff --git a/src/features/cameras/components/CameraSettings/CameraPanel.tsx b/src/features/cameras/components/CameraSettings/CameraPanel.tsx index d1899bc..7a4f779 100644 --- a/src/features/cameras/components/CameraSettings/CameraPanel.tsx +++ b/src/features/cameras/components/CameraSettings/CameraPanel.tsx @@ -28,6 +28,7 @@ const CameraPanel = ({ tabIndex, isResetAllModalOpen, handleClose, setIsResetMod return "B"; case 2: return "C"; + //Add more cases if more cameras are added default: return "A"; } diff --git a/src/features/cameras/components/CameraSettings/CameraSettings.tsx b/src/features/cameras/components/CameraSettings/CameraSettings.tsx index 55242ba..5ff3bd9 100644 --- a/src/features/cameras/components/CameraSettings/CameraSettings.tsx +++ b/src/features/cameras/components/CameraSettings/CameraSettings.tsx @@ -2,6 +2,7 @@ import Card from "../../../../ui/Card"; import { Tab, Tabs, TabList, TabPanel } from "react-tabs"; import "react-tabs/style/react-tabs.css"; import CameraPanel from "./CameraPanel"; +import { CAMERA_IDS } from "../../../../app/config/cameraConfig"; type CameraSettingsProps = { setTabIndex: (tabIndex: number) => void; @@ -12,7 +13,6 @@ type CameraSettingsProps = { }; const CameraSettings = ({ - tabIndex, setTabIndex, isResetAllModalOpen, handleClose, @@ -26,34 +26,20 @@ const CameraSettings = ({ onSelect={(index) => setTabIndex(index)} > - Camera A - Camera B - Camera C + {CAMERA_IDS.map((id) => ( + Camera {id} + ))} - - - - - - - - - + {CAMERA_IDS.map((id, index) => ( + + + + ))} ); diff --git a/src/features/cameras/components/CameraSettings/RegionSelector.tsx b/src/features/cameras/components/CameraSettings/RegionSelector.tsx index b4b4aeb..2577341 100644 --- a/src/features/cameras/components/CameraSettings/RegionSelector.tsx +++ b/src/features/cameras/components/CameraSettings/RegionSelector.tsx @@ -4,17 +4,14 @@ import { useCameraFeedContext } from "../../../../app/context/CameraFeedContext" import { useColourDectection } from "../../hooks/useColourDetection"; import { useBlackBoard } from "../../../../hooks/useBlackBoard"; import { toast } from "sonner"; -import { - useCameraFeedASocket, - useCameraFeedBSocket, - useCameraFeedCSocket, -} from "../../../../app/context/WebSocketContext"; +import { useCameraFeedSocket } from "../../../../app/context/WebSocketContext"; +import type { CameraID } from "../../../../app/config/cameraConfig"; type RegionSelectorProps = { regions: Region[]; selectedRegionIndex: number; mode: string; - cameraFeedID: "A" | "B" | "C"; + cameraFeedID: CameraID; isResetAllModalOpen: boolean; handleClose: () => void; setIsResetModalOpen: React.Dispatch>; @@ -33,26 +30,24 @@ const RegionSelector = ({ const { state, dispatch } = useCameraFeedContext(); const { blackboardMutation } = useBlackBoard(); const paintedCells = state.paintedCells[cameraFeedID]; - const cameraASocket = useCameraFeedASocket(); - const cameraBSocket = useCameraFeedBSocket(); - const cameraCSocket = useCameraFeedCSocket(); + const cameraSocket = useCameraFeedSocket(); const getCurrentSocket = () => { switch (cameraFeedID) { case "A": - return cameraASocket; + return cameraSocket; case "B": - return cameraBSocket; + return cameraSocket; case "C": - return cameraCSocket; + return cameraSocket; } }; const socket = getCurrentSocket(); const getMagnificationLevel = () => { - const test = socket.data; - if (!socket.data) return null; + const test = socket?.data; + if (!socket?.data) return null; console.log(test); if (!test || !test.magnificationLevel) return "1x"; return test?.magnificationLevel; diff --git a/src/features/cameras/components/CameraSettings/cameraControls/CameraControls.tsx b/src/features/cameras/components/CameraSettings/cameraControls/CameraControls.tsx index dcfb408..0e4187d 100644 --- a/src/features/cameras/components/CameraSettings/cameraControls/CameraControls.tsx +++ b/src/features/cameras/components/CameraSettings/cameraControls/CameraControls.tsx @@ -1,10 +1,11 @@ +import type { CameraID } from "../../../../../app/config/cameraConfig"; import { useCameraFeedContext } from "../../../../../app/context/CameraFeedContext"; import SliderComponent from "../../../../../ui/SliderComponent"; import { useCameraZoom } from "../../../hooks/useCameraZoom"; import { useDebouncedCallback } from "use-debounce"; type CameraControlsProps = { - cameraFeedID: "A" | "B" | "C"; + cameraFeedID: CameraID; }; const CameraControls = ({ cameraFeedID }: CameraControlsProps) => { diff --git a/src/features/cameras/components/Video/VideoFeedGridPainter.tsx b/src/features/cameras/components/Video/VideoFeedGridPainter.tsx index 8d65a8e..7386495 100644 --- a/src/features/cameras/components/Video/VideoFeedGridPainter.tsx +++ b/src/features/cameras/components/Video/VideoFeedGridPainter.tsx @@ -3,13 +3,10 @@ import { Stage, Layer, Image, Shape } from "react-konva"; import type { KonvaEventObject } from "konva/lib/Node"; import { useCreateVideoSnapshot } from "../../hooks/useGetvideoSnapshots"; import { useCameraFeedContext } from "../../../../app/context/CameraFeedContext"; -import { - useCameraFeedASocket, - useCameraFeedBSocket, - useCameraFeedCSocket, -} from "../../../../app/context/WebSocketContext"; +import { useCameraFeedSocket } from "../../../../app/context/WebSocketContext"; import { ReadyState } from "react-use-websocket"; import { toast } from "sonner"; +import type { CameraID } from "../../../../app/config/cameraConfig"; const BACKEND_WIDTH = 640; const BACKEND_HEIGHT = 360; @@ -41,22 +38,20 @@ const VideoFeedGridPainter = () => { const currentScale = stageSize.width / BACKEND_WIDTH; const size = BACKEND_CELL_SIZE * currentScale; - const cameraASocket = useCameraFeedASocket(); - const cameraBSocket = useCameraFeedBSocket(); - const cameraCSocket = useCameraFeedCSocket(); + const cameraSocket = useCameraFeedSocket(); const getCurrentSocket = () => { switch (cameraFeedID) { case "A": - return cameraASocket; + return cameraSocket; case "B": - return cameraBSocket; + return cameraSocket; case "C": - return cameraCSocket; + return cameraSocket; } }; - const handleZoomClick = (e: KonvaEventObject, cameraFeedID: "A" | "B" | "C") => { + const handleZoomClick = (e: KonvaEventObject, cameraFeedID: CameraID) => { if (mode !== "zoom") return; const socket = getCurrentSocket(); const stage = e.target.getStage(); diff --git a/src/features/cameras/hooks/useCameraZoom.ts b/src/features/cameras/hooks/useCameraZoom.ts index 9235f8e..1fe6c1e 100644 --- a/src/features/cameras/hooks/useCameraZoom.ts +++ b/src/features/cameras/hooks/useCameraZoom.ts @@ -1,6 +1,7 @@ import { useQuery, useMutation } from "@tanstack/react-query"; import { CAMBASE } from "../../../utils/config"; import type { CameraZoomConfig } from "../../../types/types"; +import type { CameraID } from "../../../app/config/cameraConfig"; const fetchZoomLevel = async (cameraFeedID: string) => { const response = await fetch(`${CAMBASE}/api/fetch-config?id=Camera${cameraFeedID}-onvif-controller`); @@ -34,7 +35,7 @@ const postZoomLevel = async (zoomConfig: CameraZoomConfig) => { return response.json(); }; -export const useCameraZoom = (cameraFeedID: "A" | "B" | "C") => { +export const useCameraZoom = (cameraFeedID: CameraID) => { const cameraZoomQuery = useQuery({ queryKey: ["cameraZoom", cameraFeedID], queryFn: () => fetchZoomLevel(cameraFeedID), diff --git a/src/features/dashboard/components/DashboardGrid.tsx b/src/features/dashboard/components/DashboardGrid.tsx index c5c5635..e434421 100644 --- a/src/features/dashboard/components/DashboardGrid.tsx +++ b/src/features/dashboard/components/DashboardGrid.tsx @@ -3,6 +3,7 @@ import { useGetSystemHealth } from "../hooks/useGetSystemHealth"; import CameraStatus from "./cameraStatus/CameraStatus"; import SystemHealthCard from "./systemHealth/SystemHealthCard"; import SystemStatusCard from "./systemStatus/SystemStatusCard"; +import { CAMERA_IDS } from "../../../app/config/cameraConfig"; const DashboardGrid = () => { const { query } = useGetSystemHealth(); @@ -26,30 +27,35 @@ const DashboardGrid = () => { channelA: [], channelB: [], channelC: [], + // todo: check if more cameras will be added later default: [], }, ); - const categoryA = statusCategories?.channelA ?? []; - const categoryB = statusCategories?.channelB ?? []; - const categoryC = statusCategories?.channelC ?? []; - return (
- - -
- - - +
+ + +
+ +
+ {CAMERA_IDS.map((cameraID) => ( + + ))}
); diff --git a/src/features/dashboard/components/systemHealth/SystemHealthCard.tsx b/src/features/dashboard/components/systemHealth/SystemHealthCard.tsx index 22cc9a0..a9743ed 100644 --- a/src/features/dashboard/components/systemHealth/SystemHealthCard.tsx +++ b/src/features/dashboard/components/systemHealth/SystemHealthCard.tsx @@ -25,7 +25,7 @@ const SystemHealthCard = ({ refetch, }: SystemOverviewProps) => { return ( - + { ); } return ( - + {stats ? (
diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts index 2ce97f6..a9e515b 100644 --- a/src/routeTree.gen.ts +++ b/src/routeTree.gen.ts @@ -11,7 +11,7 @@ import { Route as rootRouteImport } from './routes/__root' import { Route as SettingsRouteImport } from './routes/settings' import { Route as OutputRouteImport } from './routes/output' -import { Route as BaywatchRouteImport } from './routes/baywatch' +import { Route as CamerasRouteImport } from './routes/cameras' import { Route as AboutRouteImport } from './routes/about' import { Route as IndexRouteImport } from './routes/index' @@ -25,9 +25,9 @@ const OutputRoute = OutputRouteImport.update({ path: '/output', getParentRoute: () => rootRouteImport, } as any) -const BaywatchRoute = BaywatchRouteImport.update({ - id: '/baywatch', - path: '/baywatch', +const CamerasRoute = CamerasRouteImport.update({ + id: '/cameras', + path: '/cameras', getParentRoute: () => rootRouteImport, } as any) const AboutRoute = AboutRouteImport.update({ @@ -44,14 +44,14 @@ const IndexRoute = IndexRouteImport.update({ export interface FileRoutesByFullPath { '/': typeof IndexRoute '/about': typeof AboutRoute - '/baywatch': typeof BaywatchRoute + '/cameras': typeof CamerasRoute '/output': typeof OutputRoute '/settings': typeof SettingsRoute } export interface FileRoutesByTo { '/': typeof IndexRoute '/about': typeof AboutRoute - '/baywatch': typeof BaywatchRoute + '/cameras': typeof CamerasRoute '/output': typeof OutputRoute '/settings': typeof SettingsRoute } @@ -59,22 +59,22 @@ export interface FileRoutesById { __root__: typeof rootRouteImport '/': typeof IndexRoute '/about': typeof AboutRoute - '/baywatch': typeof BaywatchRoute + '/cameras': typeof CamerasRoute '/output': typeof OutputRoute '/settings': typeof SettingsRoute } export interface FileRouteTypes { fileRoutesByFullPath: FileRoutesByFullPath - fullPaths: '/' | '/about' | '/baywatch' | '/output' | '/settings' + fullPaths: '/' | '/about' | '/cameras' | '/output' | '/settings' fileRoutesByTo: FileRoutesByTo - to: '/' | '/about' | '/baywatch' | '/output' | '/settings' - id: '__root__' | '/' | '/about' | '/baywatch' | '/output' | '/settings' + to: '/' | '/about' | '/cameras' | '/output' | '/settings' + id: '__root__' | '/' | '/about' | '/cameras' | '/output' | '/settings' fileRoutesById: FileRoutesById } export interface RootRouteChildren { IndexRoute: typeof IndexRoute AboutRoute: typeof AboutRoute - BaywatchRoute: typeof BaywatchRoute + CamerasRoute: typeof CamerasRoute OutputRoute: typeof OutputRoute SettingsRoute: typeof SettingsRoute } @@ -95,11 +95,11 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof OutputRouteImport parentRoute: typeof rootRouteImport } - '/baywatch': { - id: '/baywatch' - path: '/baywatch' - fullPath: '/baywatch' - preLoaderRoute: typeof BaywatchRouteImport + '/cameras': { + id: '/cameras' + path: '/cameras' + fullPath: '/cameras' + preLoaderRoute: typeof CamerasRouteImport parentRoute: typeof rootRouteImport } '/about': { @@ -122,7 +122,7 @@ declare module '@tanstack/react-router' { const rootRouteChildren: RootRouteChildren = { IndexRoute: IndexRoute, AboutRoute: AboutRoute, - BaywatchRoute: BaywatchRoute, + CamerasRoute: CamerasRoute, OutputRoute: OutputRoute, SettingsRoute: SettingsRoute, } diff --git a/src/routes/baywatch.tsx b/src/routes/cameras.tsx similarity index 82% rename from src/routes/baywatch.tsx rename to src/routes/cameras.tsx index 4fbcf5b..3a63ce6 100644 --- a/src/routes/baywatch.tsx +++ b/src/routes/cameras.tsx @@ -1,7 +1,7 @@ import { createFileRoute } from "@tanstack/react-router"; import CameraGrid from "../features/cameras/components/CameraGrid"; -export const Route = createFileRoute("/baywatch")({ +export const Route = createFileRoute("/cameras")({ component: RouteComponent, }); diff --git a/src/types/types.ts b/src/types/types.ts index 90541ad..536ef8a 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -1,3 +1,5 @@ +import type { CameraID } from "../app/config/cameraConfig"; + export type WebSocketContextValue = { connected: boolean; send?: (msg: unknown) => void; @@ -128,57 +130,42 @@ export type OptionalBOF2LaneIDs = { }; export type CameraFeedState = { - cameraFeedID: "A" | "B" | "C"; - paintedCells: { - A: Map; - B: Map; - C: Map; - }; - regionsByCamera: { - A: Region[]; - B: Region[]; - C: Region[]; - }; + cameraFeedID: CameraID; + paintedCells: Record>; + + regionsByCamera: Record; selectedRegionIndex: number; - modeByCamera: { - A: string; - B: string; - C: string; - }; + modeByCamera: Record; tabIndex?: number; - zoomLevel: { - A: number; - B: number; - C: number; - }; + zoomLevel: Record; }; export type CameraFeedAction = | { type: "SET_CAMERA_FEED"; - payload: "A" | "B" | "C"; + payload: CameraID; } | { type: "CHANGE_MODE"; - payload: { cameraFeedID: "A" | "B" | "C"; mode: string }; + payload: { cameraFeedID: CameraID; mode: string }; } | { type: "SET_SELECTED_REGION_INDEX"; payload: number } | { type: "SET_SELECTED_REGION_COLOUR"; - payload: { cameraFeedID: "A" | "B" | "C"; regionName: string; newColour: string }; + payload: { cameraFeedID: CameraID; regionName: string; newColour: string }; } | { type: "ADD_NEW_REGION"; - payload: { cameraFeedID: "A" | "B" | "C"; regionName: string; brushColour: string }; + payload: { cameraFeedID: CameraID; regionName: string; brushColour: string }; } | { type: "REMOVE_REGION"; - payload: { cameraFeedID: "A" | "B" | "C"; regionName: string }; + payload: { cameraFeedID: CameraID; regionName: string }; } | { type: "RESET_PAINTED_CELLS"; - payload: { cameraFeedID: "A" | "B" | "C"; paintedCells: Map }; + payload: { cameraFeedID: CameraID; paintedCells: Map }; } | { type: "SET_CAMERA_FEED_DATA"; @@ -189,7 +176,7 @@ export type CameraFeedAction = } | { type: "SET_ZOOM_LEVEL"; - payload: { cameraFeedID: "A" | "B" | "C"; zoomLevel: number }; + payload: { cameraFeedID: CameraID; zoomLevel: number }; }; export type DecodeReading = { @@ -211,7 +198,7 @@ export type ColourData = { }; export type ColourDetectionPayload = { - cameraFeedID: "A" | "B" | "C"; + cameraFeedID: CameraID; regions: ColourData[]; }; diff --git a/src/ui/Header.tsx b/src/ui/Header.tsx index 296ad65..918a147 100644 --- a/src/ui/Header.tsx +++ b/src/ui/Header.tsx @@ -33,7 +33,7 @@ const Header = () => { Cameras @@ -58,7 +58,7 @@ const Header = () => { {/* */} Dashboard - + {/* */} Cameras