diff --git a/public/NPED_Cat_D.svg b/public/NPED_Cat_D.svg new file mode 100644 index 0000000..40a235a --- /dev/null +++ b/public/NPED_Cat_D.svg @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/src/components/HistoryList/AlertItem.tsx b/src/components/HistoryList/AlertItem.tsx index 97df557..d02613d 100644 --- a/src/components/HistoryList/AlertItem.tsx +++ b/src/components/HistoryList/AlertItem.tsx @@ -8,6 +8,7 @@ import { useCameraBlackboard } from "../../hooks/useCameraBlackboard"; import NPED_CAT_A from "/NPED_Cat_A.svg"; import NPED_CAT_B from "/NPED_Cat_B.svg"; import NPED_CAT_C from "/NPED_Cat_C.svg"; +import NPED_CAT_D from "/NPED_Cat_D.svg"; import { checkIsHotListHit, formatAge, getNPEDCategory } from "../../utils/utils"; import { faX } from "@fortawesome/free-solid-svg-icons"; import { faClock } from "@fortawesome/free-regular-svg-icons"; @@ -30,6 +31,7 @@ const AlertItem = ({ item }: AlertItemProps) => { const isNPEDHitA = cat === "A"; const isNPEDHitB = cat === "B"; const isNPEDHitC = cat === "C"; + const isNPEDHitD = cat === "D"; const handleClick = () => { setIsModalOpen(true); @@ -69,6 +71,7 @@ const AlertItem = ({ item }: AlertItemProps) => { {isNPEDHitA && NPEDHITicon} {isNPEDHitB && NPEDHITicon} {isNPEDHitC && NPEDHITicon} + {isNPEDHitD && NPEDHITicon} diff --git a/src/components/HistoryList/HistoryList.tsx b/src/components/HistoryList/HistoryList.tsx index ae09490..44be467 100644 --- a/src/components/HistoryList/HistoryList.tsx +++ b/src/components/HistoryList/HistoryList.tsx @@ -31,9 +31,7 @@ const HistoryList = () => {
{state?.alertList?.length > 0 ? (
- {state?.alertList?.map((alertItem) => ( - - ))} + {state?.alertList?.map((alertItem) => ).reverse()}
) : (
diff --git a/src/components/PopupSettings/NPEDCategoryPopup.tsx b/src/components/PopupSettings/NPEDCategoryPopup.tsx index 8f5b279..c007714 100644 --- a/src/components/PopupSettings/NPEDCategoryPopup.tsx +++ b/src/components/PopupSettings/NPEDCategoryPopup.tsx @@ -10,6 +10,7 @@ import { toast } from "sonner"; const NPEDCategoryPopup = () => { const { state, dispatch } = useIntegrationsContext(); + const { mutation } = useCameraBlackboard(); const isCatAEnabled = state?.iscatEnabled?.catA; @@ -34,8 +35,8 @@ const NPEDCategoryPopup = () => { await mutation.mutateAsync({ operation: "SAVE", path: "", - value: null - }) + value: null, + }); if (result?.reason === "OK") toast.success("Pop up settings saved"); dispatch({ type: "NPEDCATENABLED", payload: values }); }; @@ -44,7 +45,7 @@ const NPEDCategoryPopup = () => {

Allows alerts to pop up to user.

- +
diff --git a/src/components/SessionForm/SessionCard.tsx b/src/components/SessionForm/SessionCard.tsx index a79a9c7..e0b5d7a 100644 --- a/src/components/SessionForm/SessionCard.tsx +++ b/src/components/SessionForm/SessionCard.tsx @@ -172,6 +172,11 @@ const SessionCard = () => { textColour="text-gray-300" vehicleTag={"Vehicles with NPED Cat C:"} /> +
diff --git a/src/components/SightingModal/SightingModal.tsx b/src/components/SightingModal/SightingModal.tsx index a8091a2..f2cd196 100644 --- a/src/components/SightingModal/SightingModal.tsx +++ b/src/components/SightingModal/SightingModal.tsx @@ -10,7 +10,8 @@ import HotListImg from "/Hotlist_Hit.svg"; import NPED_CAT_A from "/NPED_Cat_A.svg"; import NPED_CAT_B from "/NPED_Cat_B.svg"; import NPED_CAT_C from "/NPED_Cat_C.svg"; -import { checkIsHotListHit, getHotlistName, getNPEDCategory } from "../../utils/utils"; +import NPED_CAT_D from "/NPED_Cat_D.svg"; +import { checkIsHotListHit, getHotlistName, getNPEDCategory, getNPEDReason } from "../../utils/utils"; type SightingModalProps = { isSightingModalOpen: boolean; @@ -74,11 +75,19 @@ const SightingModal = ({ isSightingModalOpen, handleClose, sighting, onDelete }: }; const motionAway = (sighting?.motion ?? "").toUpperCase() === "AWAY"; + const isHotListHit = checkIsHotListHit(sighting); const cat = getNPEDCategory(sighting); const isNPEDHitA = cat === "A"; const isNPEDHitB = cat === "B"; const isNPEDHitC = cat === "C"; + const isNPEDHitD = cat === "D"; + + const reason = getNPEDReason(sighting); + + const insuranceStatus = reason ? reason["INSURANCE STATUS"] : null; + const motStatus = reason ? reason["MOT STATUS"] : null; + const taxStatus = reason ? reason["TAX STATUS"] : null; return ( <> @@ -133,6 +142,7 @@ const SightingModal = ({ isSightingModalOpen, handleClose, sighting, onDelete }: {isNPEDHitA && hotlistHit} {isNPEDHitB && hotlistHit} {isNPEDHitC && hotlistHit} + {isNPEDHitD && hotlistHit}
{hotlistNames && hotlistNames.length > 0 && (
@@ -158,44 +168,97 @@ const SightingModal = ({ isSightingModalOpen, handleClose, sighting, onDelete }:

Vehicle Info

-
VRM
-
{sighting?.vrm ?? "-"}
+
{sighting?.vrm ?? "-"}
+ {isNPEDHitA || isNPEDHitB || isNPEDHitC || isNPEDHitD ? ( + <> +
+
Insurance
+
+ {insuranceStatus ? ( + + YES + + ) : ( + + NO + + )} +
+
+
+
MOT
+
+ {motStatus ? ( + + VALID + + ) : ( + + EXPIRED + + )} +
+
+
+
Tax
+
+ {taxStatus ? ( + + VALID + + ) : ( + + EXPIRED + + )} +
+
+ + ) : ( + <> +
+
Motion
+
{sighting?.motion ?? "-"}
+
+
+
Seen Count
+
{sighting?.seenCount ?? "-"}
+
-
-
Motion
-
{sighting?.motion ?? "-"}
-
-
-
Seen Count
-
{sighting?.seenCount ?? "-"}
-
+ {sighting?.make && sighting.make.trim() && sighting.make.toLowerCase() !== "disabled" && ( +
+
Make
+
{sighting.make}
+
+ )} - {sighting?.make && sighting.make.trim() && sighting.make.toLowerCase() !== "disabled" && ( -
-
Make
-
{sighting.make}
-
+ {sighting?.model && sighting.model.trim() && sighting.model.toLowerCase() !== "disabled" && ( +
+
Model
+
{sighting.model}
+
+ )} + + {sighting?.color && sighting.color.trim() && sighting.color.toLowerCase() !== "disabled" && ( +
+
Colour
+
{sighting.color}
+
+ )} + +
+
Time
+
{sighting?.timeStamp ?? "-"}
+
+ )} - - {sighting?.model && sighting.model.trim() && sighting.model.toLowerCase() !== "disabled" && ( -
-
Model
-
{sighting.model}
-
- )} - - {sighting?.color && sighting.color.trim() && sighting.color.toLowerCase() !== "disabled" && ( -
-
Colour
-
{sighting.color}
-
- )} - -
-
Time
-
{sighting?.timeStamp ?? "-"}
-
diff --git a/src/components/SightingsWidget/SightingWidget.tsx b/src/components/SightingsWidget/SightingWidget.tsx index fe31fe7..4c35e38 100644 --- a/src/components/SightingsWidget/SightingWidget.tsx +++ b/src/components/SightingsWidget/SightingWidget.tsx @@ -12,14 +12,10 @@ import HotListImg from "/Hotlist_Hit.svg"; import NPED_CAT_A from "/NPED_Cat_A.svg"; import NPED_CAT_B from "/NPED_Cat_B.svg"; import NPED_CAT_C from "/NPED_Cat_C.svg"; -import popup from "../../assets/sounds/ui/popup_open.mp3"; -import notification from "../../assets/sounds/ui/notification.mp3"; -import { useSound } from "react-sounds"; +import NPED_CAT_D from "/NPED_Cat_D.svg"; import { useIntegrationsContext } from "../../context/IntegrationsContext"; -import { useSoundContext } from "../../context/SoundContext"; import Loading from "../UI/Loading"; import { checkIsHotListHit, getNPEDCategory } from "../../utils/utils"; -import { useCachedSoundSrc } from "../../hooks/usecachedSoundSrc"; function useNow(tickMs = 1000) { const [, setNow] = useState(() => Date.now()); @@ -41,14 +37,9 @@ type SightingHistoryProps = { export default function SightingHistoryWidget({ className, title }: SightingHistoryProps) { const [modalQueue, setModalQueue] = useState([]); + useNow(1000); - const { state } = useSoundContext(); - const { src: soundSrcHotlist } = useCachedSoundSrc(state?.hotlistSound, state?.soundOptions, notification); - const { src: soundSrcNped } = useCachedSoundSrc(state?.NPEDsound, state?.soundOptions, popup); - - const { play: npedSound } = useSound(soundSrcNped, { volume: state.NPEDsoundVolume }); - const { play: hotlistsound } = useSound(soundSrcHotlist, { volume: state.hotlistSoundVolume }); const { sightings, setSelectedSighting, @@ -73,18 +64,24 @@ export default function SightingHistoryWidget({ className, title }: SightingHist const isCatCEnabled = integrationState?.iscatEnabled?.catC; const isCatDEnabled = integrationState?.iscatEnabled?.catD; - const enqueue = useCallback((sighting: SightingType, kind: HitKind) => { - const id = sighting.vrm ?? sighting.ref; - if (processedRefs.current.has(id)) return; + const enqueue = useCallback( + (sighting: SightingType, kind: HitKind) => { + if (!sighting) return; - const inList = alertState?.alertList?.find((sighting) => sighting.vrm === id); - if (inList) { - return; - } - processedRefs.current.add(id); + const id = sighting.vrm ?? sighting.ref; + if (processedRefs.current.has(id)) return; - setModalQueue((q) => [...q, { id, sighting, kind }]); - }, []); + const inList = alertState?.alertList?.find((sighting) => sighting.vrm === id); + if (inList) { + return; + } + + processedRefs.current.add(id); + + setModalQueue((q) => [...q, { id, sighting, kind }]); + }, + [alertState?.alertList] + ); const reduceObject = (obj: SightingType): ReducedSightingType => { return { @@ -133,31 +130,16 @@ export default function SightingHistoryWidget({ className, title }: SightingHist enqueue(sighting, isNPED ? "NPED" : "HOTLIST"); // enqueue ONLY } } - }, [rows, enqueue]); - - useEffect(() => { - rows?.forEach((obj) => { - const cat = getNPEDCategory(obj); - const isNPEDHitA = cat === "A"; - const isNPEDHitB = cat === "B"; - const isNPEDHitC = cat === "C"; - if (isNPEDHitA || isNPEDHitB || isNPEDHitC) { - dispatch({ - type: "ADD", - payload: obj, - }); - } - }); - }, [dispatch]); + }, [rows, enqueue, isCatAEnabled, isCatBEnabled, isCatCEnabled, isCatDEnabled]); useEffect(() => { if (hasAutoOpenedRef.current || npedRef.current) return; const firstNPED = rows.find((r) => { const cat = getNPEDCategory(r); - const isNPEDHitA = cat === "A"; - const isNPEDHitB = cat === "B"; - const isNPEDHitC = cat === "C"; - const isNPEDHitD = cat === "D"; + const isNPEDHitA = cat === "A" && isCatAEnabled; + const isNPEDHitB = cat === "B" && isCatBEnabled; + const isNPEDHitC = cat === "C" && isCatCEnabled; + const isNPEDHitD = cat === "D" && isCatDEnabled; return isNPEDHitA || isNPEDHitB || isNPEDHitC || isNPEDHitD; }); const firstHot = rows?.find((r) => { @@ -176,20 +158,42 @@ export default function SightingHistoryWidget({ className, title }: SightingHist hasAutoOpenedRef.current = true; } - }, [enqueue, hotlistsound, npedSound, rows, setSelectedSighting, setSightingModalOpen]); + }, [ + enqueue, + rows, + setSelectedSighting, + setSightingModalOpen, + isCatAEnabled, + isCatBEnabled, + isCatCEnabled, + isCatDEnabled, + ]); useEffect(() => { if (!isSightingModalOpen && modalQueue.length > 0) { const next = modalQueue[0]; - - if (next.kind === "NPED") npedSound(); - else hotlistsound(); - setSelectedSighting(next.sighting); setSightingModalOpen(true); } - }, [isSightingModalOpen, npedSound, hotlistsound, setSelectedSighting, setSightingModalOpen, modalQueue]); + }, [isSightingModalOpen, setSelectedSighting, setSightingModalOpen, modalQueue]); + + useEffect(() => { + rows?.forEach((obj) => { + const cat = getNPEDCategory(obj); + const isNPEDHitA = cat === "A"; + const isNPEDHitB = cat === "B"; + const isNPEDHitC = cat === "C"; + const isNPEDHitD = cat === "D"; + if (isNPEDHitA || isNPEDHitB || isNPEDHitC || isNPEDHitD) { + console.log("first"); + dispatch({ + type: "ADD", + payload: obj, + }); + } + }); + }, [dispatch, rows]); const handleClose = () => { setSightingModalOpen(false); @@ -212,6 +216,7 @@ export default function SightingHistoryWidget({ className, title }: SightingHist const isNPEDHitA = cat === "A"; const isNPEDHitB = cat === "B"; const isNPEDHitC = cat === "C"; + const isNPEDHitD = cat === "D"; const motionAway = (obj?.motion ?? "").toUpperCase() === "AWAY"; const isHotListHit = checkIsHotListHit(obj); return ( @@ -230,6 +235,7 @@ export default function SightingHistoryWidget({ className, title }: SightingHist {isNPEDHitA && hotlistHit} {isNPEDHitB && hotlistHit} {isNPEDHitC && hotlistHit} + {isNPEDHitD && hotlistHit} diff --git a/src/context/providers/IntegrationsContextProvider.tsx b/src/context/providers/IntegrationsContextProvider.tsx index 4a5bba3..49e9301 100644 --- a/src/context/providers/IntegrationsContextProvider.tsx +++ b/src/context/providers/IntegrationsContextProvider.tsx @@ -36,10 +36,16 @@ export const IntegrationsProvider = ({ children }: IntegrationsProviderType) => }); if (!isMounted) return; - if (!result?.result || typeof result.result === "string") return; - dispatch({ type: "UPDATE", payload: result.result }); - dispatch({ type: "NPEDCATENABLED", payload: catResult.result }); + if (result?.result && typeof result.result !== "string") { + dispatch({ type: "UPDATE", payload: result.result }); + } + + if (catResult?.result) { + dispatch({ type: "NPEDCATENABLED", payload: catResult.result }); + } else { + console.log("Early return: catResult check failed"); + } } catch (error) { console.error("Error in fetchData:", error); } diff --git a/src/hooks/useSightingFeed.ts b/src/hooks/useSightingFeed.ts index 38eca48..e71e3c3 100644 --- a/src/hooks/useSightingFeed.ts +++ b/src/hooks/useSightingFeed.ts @@ -88,8 +88,14 @@ export function useSightingFeed(url: string | undefined) { const isNPEDHitA = cat === "A"; const isNPEDHitB = cat === "B"; const isNPEDHitC = cat === "C"; + const isNPEDHitD = cat === "D"; - if ((isNPEDHitA && audioArmed) || (isNPEDHitB && audioArmed) || (isNPEDHitC && audioArmed)) { + if ( + (isNPEDHitA && audioArmed) || + (isNPEDHitB && audioArmed) || + (isNPEDHitC && audioArmed) || + (isNPEDHitD && audioArmed) + ) { playNPEDHitSound(); } else if (isHotListHit && audioArmed) { playHotlistsound(); diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 7cdc0a8..57cd8fb 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -159,6 +159,8 @@ export function getHotlistName(obj: HotlistMatches | undefined) { export const getNPEDCategory = (r?: SightingType | null) => r?.metadata?.npedJSON?.["NPED CATEGORY"] as "A" | "B" | "C" | "D" | undefined; +export const getNPEDReason = (r?: SightingType | null) => r?.metadata?.npedJSON; + export const zoomMapping = (zoomLevel: number | undefined) => { switch (zoomLevel) { case 1: