From ddb1fa1bf10f6036eead5c1bdeba45189602fadf Mon Sep 17 00:00:00 2001 From: Toba Ojo Date: Fri, 28 Nov 2025 12:58:42 +0000 Subject: [PATCH] Refactor camera feed components and add sighting tables - Updated mode settings in camera feed reducer to use "painter" - Renamed PlatePatch component to SightingPatch and updated imports - Removed obsolete PlatePatch component - Added SightingEntryTable and SightingExitTable components for displaying sighting data - Implemented useSightingEntryAndExit hook for fetching entry and exit sightings - Adjusted VideoFeedGridPainter for improved width calculation - Introduced DecodeReading type for better typing --- src/app/reducers/cameraFeedReducer.ts | 7 ++- .../cameras/components/CameraGrid.tsx | 2 +- .../components/PlatePatch/PlatePatch.tsx | 7 --- .../PlatePatch/SightingEntryTable.tsx | 44 +++++++++++++++++++ .../PlatePatch/SightingExitTable.tsx | 44 +++++++++++++++++++ .../components/PlatePatch/SightingPatch.tsx | 27 ++++++++++++ .../components/Video/VideoFeedGridPainter.tsx | 2 +- .../cameras/hooks/useSightingEntryAndExit.ts | 28 ++++++++++++ src/types/types.ts | 12 +++++ 9 files changed, 160 insertions(+), 13 deletions(-) delete mode 100644 src/features/cameras/components/PlatePatch/PlatePatch.tsx create mode 100644 src/features/cameras/components/PlatePatch/SightingEntryTable.tsx create mode 100644 src/features/cameras/components/PlatePatch/SightingExitTable.tsx create mode 100644 src/features/cameras/components/PlatePatch/SightingPatch.tsx create mode 100644 src/features/cameras/hooks/useSightingEntryAndExit.ts diff --git a/src/app/reducers/cameraFeedReducer.ts b/src/app/reducers/cameraFeedReducer.ts index eca19d0..5a2b4f6 100644 --- a/src/app/reducers/cameraFeedReducer.ts +++ b/src/app/reducers/cameraFeedReducer.ts @@ -22,9 +22,9 @@ export const initialState: CameraFeedState = { selectedRegionIndex: 0, modeByCamera: { - A: "brush", - B: "brush", - C: "brush", + A: "painter", + B: "painter", + C: "painter", }, }; @@ -70,7 +70,6 @@ export function reducer(state: CameraFeedState, action: CameraFeedAction) { }, }; case "REMOVE_REGION": - console.log(action.payload); return { ...state, regionsByCamera: { diff --git a/src/features/cameras/components/CameraGrid.tsx b/src/features/cameras/components/CameraGrid.tsx index fc430aa..07fc554 100644 --- a/src/features/cameras/components/CameraGrid.tsx +++ b/src/features/cameras/components/CameraGrid.tsx @@ -3,7 +3,7 @@ import { useState } from "react"; import VideoFeedGridPainter from "./Video/VideoFeedGridPainter"; import CameraSettings from "./CameraSettings/CameraSettings"; -import PlatePatch from "./PlatePatch/PlatePatch"; +import PlatePatch from "./PlatePatch/SightingPatch"; const CameraGrid = () => { const [tabIndex, setTabIndex] = useState(0); diff --git a/src/features/cameras/components/PlatePatch/PlatePatch.tsx b/src/features/cameras/components/PlatePatch/PlatePatch.tsx deleted file mode 100644 index 0feb48b..0000000 --- a/src/features/cameras/components/PlatePatch/PlatePatch.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import Card from "../../../../ui/Card"; - -const PlatePatch = () => { - return PlatePatch; -}; - -export default PlatePatch; diff --git a/src/features/cameras/components/PlatePatch/SightingEntryTable.tsx b/src/features/cameras/components/PlatePatch/SightingEntryTable.tsx new file mode 100644 index 0000000..21cdb99 --- /dev/null +++ b/src/features/cameras/components/PlatePatch/SightingEntryTable.tsx @@ -0,0 +1,44 @@ +import { useCameraFeedContext } from "../../../../app/context/CameraFeedContext"; +import type { DecodeReading } from "../../../../types/types"; +import { useSightingEntryAndExit } from "../../hooks/useSightingEntryAndExit"; + +const SightingEntryTable = () => { + const { state } = useCameraFeedContext(); + const cameraFeedID = state.cameraFeedID; + const { entryQuery } = useSightingEntryAndExit(cameraFeedID); + + const isLoading = entryQuery?.isFetching; + const readings = entryQuery?.data?.decodes; + + if (isLoading) return Loading Sighting data…; + return ( +
+
+ + + + + + + + + + + + {readings?.map((reading: DecodeReading) => ( + + + + + + + + ))} + +
VRMLane IDSeen CountFirst SeenLast Seen
{reading?.vrm}{reading?.laneID}{reading?.seenCount}{reading?.firstSeenTimeHumane}{reading?.lastSeenTimeHumane}
+
+
+ ); +}; + +export default SightingEntryTable; diff --git a/src/features/cameras/components/PlatePatch/SightingExitTable.tsx b/src/features/cameras/components/PlatePatch/SightingExitTable.tsx new file mode 100644 index 0000000..7ca806c --- /dev/null +++ b/src/features/cameras/components/PlatePatch/SightingExitTable.tsx @@ -0,0 +1,44 @@ +import { useCameraFeedContext } from "../../../../app/context/CameraFeedContext"; +import type { DecodeReading } from "../../../../types/types"; +import { useSightingEntryAndExit } from "../../hooks/useSightingEntryAndExit"; + +const SightingExitTable = () => { + const { state } = useCameraFeedContext(); + const cameraFeedID = state.cameraFeedID; + const { exitQuery } = useSightingEntryAndExit(cameraFeedID); + + const isLoading = exitQuery?.isFetching; + const readings = exitQuery?.data?.decodes; + + if (isLoading) return Loading Sighting data…; + return ( +
+
+ + + + + + + + + + + + {readings?.map((reading: DecodeReading) => ( + + + + + + + + ))} + +
VRMLane IDSeen CountFirst SeenLast Seen
{reading?.vrm}{reading?.laneID}{reading?.seenCount}{reading?.firstSeenTimeHumane}{reading?.lastSeenTimeHumane}
+
+
+ ); +}; + +export default SightingExitTable; diff --git a/src/features/cameras/components/PlatePatch/SightingPatch.tsx b/src/features/cameras/components/PlatePatch/SightingPatch.tsx new file mode 100644 index 0000000..052e72b --- /dev/null +++ b/src/features/cameras/components/PlatePatch/SightingPatch.tsx @@ -0,0 +1,27 @@ +import { Tab, Tabs, TabList, TabPanel } from "react-tabs"; +import Card from "../../../../ui/Card"; +import CardHeader from "../../../../ui/CardHeader"; +import SightingEntryTable from "./SightingEntryTable"; +import SightingExitTable from "./SightingExitTable"; + +const PlatePatch = () => { + return ( + + + + + Entry Sightings + Exit Sightings + + + + + + + + + + ); +}; + +export default PlatePatch; diff --git a/src/features/cameras/components/Video/VideoFeedGridPainter.tsx b/src/features/cameras/components/Video/VideoFeedGridPainter.tsx index 6aa48ef..e909df5 100644 --- a/src/features/cameras/components/Video/VideoFeedGridPainter.tsx +++ b/src/features/cameras/components/Video/VideoFeedGridPainter.tsx @@ -88,7 +88,7 @@ const VideoFeedGridPainter = () => { const width = window.innerWidth; const aspectRatio = 740 / 460; - const newWidth = width * 0.36; + const newWidth = width * 0.39; const newHeight = newWidth / aspectRatio; setStageSize({ width: newWidth, height: newHeight }); }; diff --git a/src/features/cameras/hooks/useSightingEntryAndExit.ts b/src/features/cameras/hooks/useSightingEntryAndExit.ts new file mode 100644 index 0000000..88860b3 --- /dev/null +++ b/src/features/cameras/hooks/useSightingEntryAndExit.ts @@ -0,0 +1,28 @@ +import { useQuery } from "@tanstack/react-query"; +import { CAMBASE } from "../../../utils/config"; + +const fetchEntrySightings = async (cameraFeedID: string) => { + const response = await fetch(`${CAMBASE}/EntrySightingCreator${cameraFeedID}-list-proto-sightings`); + if (!response.ok) throw new Error("Cannot reach sighing entry endpoint"); + return response.json(); +}; + +const fetchExitSightings = async (cameraFeedID: string) => { + const response = await fetch(`${CAMBASE}/ExitSightingCreator${cameraFeedID}-list-proto-sightings`); + if (!response.ok) throw new Error("Cannot reach sighing exit endpoint"); + return response.json(); +}; + +export const useSightingEntryAndExit = (cameraFeedID: string) => { + const entryQuery = useQuery({ + queryKey: ["Entry Sightings", cameraFeedID], + queryFn: () => fetchEntrySightings(cameraFeedID), + }); + + const exitQuery = useQuery({ + queryKey: ["Exit Sightings", cameraFeedID], + queryFn: () => fetchExitSightings(cameraFeedID), + }); + + return { entryQuery, exitQuery }; +}; diff --git a/src/types/types.ts b/src/types/types.ts index e012fca..d59e1ad 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -144,3 +144,15 @@ export type CameraFeedAction = type: "RESET_PAINTED_CELLS"; payload: { cameraFeedID: "A" | "B" | "C"; paintedCells: Map }; }; + +export type DecodeReading = { + id: number; + vrm: string; + laneID: number; + seenCount: number; + firstSeenTime?: number; + lastSeenTime?: number; + duplicate?: true; + firstSeenTimeHumane: string; + lastSeenTimeHumane: string; +};