From ea93053dd3e6585d79be7e5a87539f6dc7b87406 Mon Sep 17 00:00:00 2001 From: Toba Ojo Date: Wed, 19 Nov 2025 11:52:37 +0000 Subject: [PATCH 1/6] - sesstions start by default - added restart session button --- src/components/SessionForm/SessionCard.tsx | 28 ++++++++++++++++++- .../reducers/IntegrationsContextReducer.ts | 7 ++++- src/hooks/useGetOverviewSnapshot.ts | 26 +++++------------ 3 files changed, 40 insertions(+), 21 deletions(-) diff --git a/src/components/SessionForm/SessionCard.tsx b/src/components/SessionForm/SessionCard.tsx index d77931b..a79a9c7 100644 --- a/src/components/SessionForm/SessionCard.tsx +++ b/src/components/SessionForm/SessionCard.tsx @@ -4,7 +4,7 @@ import { useIntegrationsContext } from "../../context/IntegrationsContext"; import type { ReducedSightingType } from "../../types/types"; import { toast } from "sonner"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faFloppyDisk, faPause, faPlay, faStop } from "@fortawesome/free-solid-svg-icons"; +import { faFloppyDisk, faPause, faPlay, faStop, faArrowRotateRight } from "@fortawesome/free-solid-svg-icons"; import VehicleSessionItem from "../UI/VehicleSessionItem"; import { useCameraBlackboard } from "../../hooks/useCameraBlackboard"; @@ -70,6 +70,21 @@ const SessionCard = () => { if (result.reason === "OK") toast.success("Session saved"); }; + const handleRestartClick = async () => { + const result = await mutation.mutateAsync({ + operation: "INSERT", + path: "sessionStats", + value: [], + }); + await mutation.mutateAsync({ + operation: "SAVE", + path: "", + value: null, + }); + if (result.reason === "OK") toast.success("Session restarted"); + dispatch({ type: "SESSIONRESTART", payload: [] }); + }; + return ( @@ -85,6 +100,17 @@ const SessionCard = () => {

{sessionStarted ? "End Session" : "Start Session"}

+ {sessionStarted && ( + + )}
{sessionStarted && ( + + ))} + + ) : ( +
+
+ No Uploaded Hotlists +
+

+ Hotlists will appear here once there are uploaded. +

+
+ )} + + ); +}; + +export default HotlistList; diff --git a/src/components/SettingForms/NPED/NPEDHotlist.tsx b/src/components/SettingForms/NPED/NPEDHotlist.tsx index 4ae9325..766d0b2 100644 --- a/src/components/SettingForms/NPED/NPEDHotlist.tsx +++ b/src/components/SettingForms/NPED/NPEDHotlist.tsx @@ -5,6 +5,7 @@ import { CAM_BASE } from "../../../utils/config"; const NPEDHotlist = () => { const { uploadSettings } = useSystemConfig(); + const initialValue = { file: null, }; diff --git a/src/context/providers/IntegrationsContextProvider.tsx b/src/context/providers/IntegrationsContextProvider.tsx index b2b3e86..4a5bba3 100644 --- a/src/context/providers/IntegrationsContextProvider.tsx +++ b/src/context/providers/IntegrationsContextProvider.tsx @@ -2,6 +2,7 @@ import { useEffect, useReducer, type ReactNode } from "react"; import { IntegrationsContext } from "../IntegrationsContext"; import { useCameraBlackboard } from "../../hooks/useCameraBlackboard"; import { initialState, reducer } from "../reducers/IntegrationsContextReducer"; +import { useHotlistData } from "../../hooks/useHotListData"; type IntegrationsProviderType = { children: ReactNode; @@ -10,6 +11,7 @@ type IntegrationsProviderType = { export const IntegrationsProvider = ({ children }: IntegrationsProviderType) => { const [state, dispatch] = useReducer(reducer, initialState); const { mutation } = useCameraBlackboard(); + const { query } = useHotlistData(); useEffect(() => { let isMounted = true; @@ -50,6 +52,13 @@ export const IntegrationsProvider = ({ children }: IntegrationsProviderType) => }; }, []); + useEffect(() => { + const fetchHotlistData = async () => { + dispatch({ type: "SETHOTLISTS", payload: query?.data?.hotlists }); + }; + fetchHotlistData(); + }, [query?.data]); + return ( hotlist.filename !== action.payload), + }; default: return { ...state }; } diff --git a/src/hooks/useHotListData.ts b/src/hooks/useHotListData.ts new file mode 100644 index 0000000..7bd4684 --- /dev/null +++ b/src/hooks/useHotListData.ts @@ -0,0 +1,28 @@ +import { useMutation, useQuery } from "@tanstack/react-query"; +import { CAM_BASE } from "../utils/config"; + +const fetchHotlists = async () => { + const response = await fetch(`${CAM_BASE}/Hotlist-csv-metadata`); + if (!response.ok) throw new Error("Cannot reach hotlist endpoint"); + return response.json(); +}; + +const deleteHotlist = async (filename: string) => { + const response = await fetch(`${CAM_BASE}/Hotlist-csv-delete?filename=${filename}`); + if (!response.ok) throw new Error(`Cannot delte hotlist: ${filename}`); + return response.json(); +}; + +export const useHotlistData = () => { + const query = useQuery({ + queryKey: ["fetchHotlists"], + queryFn: fetchHotlists, + }); + + const mutation = useMutation({ + mutationKey: ["deleteHotlist"], + mutationFn: (filename: string) => deleteHotlist(filename), + }); + + return { query, mutation }; +}; diff --git a/src/pages/SystemSettings.tsx b/src/pages/SystemSettings.tsx index ea2941c..1538d2e 100644 --- a/src/pages/SystemSettings.tsx +++ b/src/pages/SystemSettings.tsx @@ -11,6 +11,7 @@ import { useNPEDAuth } from "../hooks/useNPEDAuth"; import SoundSettingsCard from "../components/SettingForms/Sound/SoundSettingsCard"; import SoundUploadCard from "../components/SettingForms/Sound/SoundUploadCard"; import NPEDCategoryPopup from "../components/PopupSettings/NPEDCategoryPopup"; +import HotlistList from "../components/HotlistList/HotlistList"; const SystemSettings = () => { useNPEDAuth(); @@ -40,6 +41,7 @@ const SystemSettings = () => { +
diff --git a/src/types/types.ts b/src/types/types.ts index 0f08692..c9a2105 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -417,6 +417,12 @@ export type QueuedHit = { export type DedupedSightings = ReducedSightingType[]; +export type HotlistFile = { + fileSizeBytes: number; + filename: string; + rowCount: number; +}; + export type NPEDSTATE = { sessionStarted: boolean; sessionList: ReducedSightingType[]; @@ -424,6 +430,7 @@ export type NPEDSTATE = { savedSightings: DedupedSightings; npedUser: NPEDUser; iscatEnabled: CategoryPopups; + hotlistFiles: HotlistFile[]; }; export type NPEDACTION = { -- 2.25.1 From 12cd0f9f37cd13e0e69adfc44fd04212b5eb4a9e Mon Sep 17 00:00:00 2001 From: Toba Ojo Date: Wed, 19 Nov 2025 15:03:20 +0000 Subject: [PATCH 3/6] - minor adjustments to modal --- src/components/SightingModal/SightingModal.tsx | 8 ++++---- src/components/UI/ModalComponent.tsx | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/SightingModal/SightingModal.tsx b/src/components/SightingModal/SightingModal.tsx index 26a270f..a8091a2 100644 --- a/src/components/SightingModal/SightingModal.tsx +++ b/src/components/SightingModal/SightingModal.tsx @@ -83,7 +83,7 @@ const SightingModal = ({ isSightingModalOpen, handleClose, sighting, onDelete }: return ( <> -
+

Sighting Details

@@ -134,7 +134,7 @@ const SightingModal = ({ isSightingModalOpen, handleClose, sighting, onDelete }: {isNPEDHitB && hotlistHit} {isNPEDHitC && hotlistHit}
- {hotlistNames && ( + {hotlistNames && hotlistNames.length > 0 && (

Hotlists

@@ -148,11 +148,11 @@ const SightingModal = ({ isSightingModalOpen, handleClose, sighting, onDelete }:
)} -
+
overview patch