From 61894c0c42b9fb23d364c7cc1f6c469c6effda7e Mon Sep 17 00:00:00 2001 From: Toba Ojo Date: Tue, 4 Nov 2025 13:38:06 +0000 Subject: [PATCH 01/10] - minor big fixes - default settings toggled -update camera zoom need to test --- .../CameraOverview/SnapshotContainer.tsx | 15 ++++++--------- .../CameraSettings/CameraSettingFields.tsx | 18 ++++++++++++------ src/components/PlateStack/NumberPlate.tsx | 8 ++------ .../Channel1-JSON/ChannelFields.tsx | 12 +++--------- .../SettingForms/SettingForms/SettingForms.tsx | 10 ---------- src/components/UI/NavigationArrow.tsx | 2 +- src/hooks/useCameraZoom.ts | 14 ++++---------- src/types/types.ts | 2 ++ src/utils/utils.ts | 13 +++++++++++++ 9 files changed, 43 insertions(+), 51 deletions(-) diff --git a/src/components/CameraOverview/SnapshotContainer.tsx b/src/components/CameraOverview/SnapshotContainer.tsx index 87cb48f..a59a44c 100644 --- a/src/components/CameraOverview/SnapshotContainer.tsx +++ b/src/components/CameraOverview/SnapshotContainer.tsx @@ -5,6 +5,7 @@ import { useCameraZoom } from "../../hooks/useCameraZoom"; import { useEffect } from "react"; import Loading from "../UI/Loading"; import ErrorState from "../UI/ErrorState"; +import { zoomMapping } from "../../utils/utils"; type SnapshotContainerProps = { side: string; @@ -13,20 +14,14 @@ type SnapshotContainerProps = { onZoomLevelChange?: (level: number) => void; }; -export const SnapshotContainer = ({ - side, - settingsPage, - zoomLevel, - onZoomLevelChange, -}: SnapshotContainerProps) => { +export const SnapshotContainer = ({ side, settingsPage, zoomLevel, onZoomLevelChange }: SnapshotContainerProps) => { const { canvasRef, isError, isPending } = useGetOverviewSnapshot(side); - const cameraControllerSide = - side === "CameraA" ? "CameraControllerA" : "CameraControllerB"; + const cameraControllerSide = side === "CameraA" ? "CameraControllerA" : "CameraControllerB"; const { mutation } = useCameraZoom({ camera: cameraControllerSide }); const handleZoomClick = () => { const baseLevel = zoomLevel ?? 1; - const newLevel = baseLevel >= 8 ? 1 : baseLevel * 2; + const newLevel = baseLevel >= 4 ? 1 : baseLevel * 2; if (onZoomLevelChange) onZoomLevelChange(newLevel); @@ -35,9 +30,11 @@ export const SnapshotContainer = ({ useEffect(() => { if (zoomLevel) { + const text = zoomMapping(zoomLevel); const zoomInOptions: ZoomInOptions = { camera: cameraControllerSide, multiplier: zoomLevel, + multiplierText: text, }; mutation.mutate(zoomInOptions); } diff --git a/src/components/CameraSettings/CameraSettingFields.tsx b/src/components/CameraSettings/CameraSettingFields.tsx index 1cb3786..1218236 100644 --- a/src/components/CameraSettings/CameraSettingFields.tsx +++ b/src/components/CameraSettings/CameraSettingFields.tsx @@ -5,7 +5,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faEye, faEyeSlash } from "@fortawesome/free-regular-svg-icons"; import CardHeader from "../UI/CardHeader"; import { useCameraZoom } from "../../hooks/useCameraZoom"; -import { parseRTSPUrl } from "../../utils/utils"; +import { parseRTSPUrl, zoomMapping } from "../../utils/utils"; type CameraSettingsProps = { initialData: CameraConfig; @@ -25,7 +25,12 @@ const CameraSettingFields = ({ const [showPwd, setShowPwd] = useState(false); const cameraControllerSide = initialData?.id === "CameraA" ? "CameraControllerA" : "CameraControllerB"; const { mutation, query } = useCameraZoom({ camera: cameraControllerSide }); - const zoomOptions = [1, 2, 4, 8]; + const zoomOptions = [1, 2, 4]; + // const zoomTextOptions = [ + // { label: "near", value: 4 }, + // { label: "medium", value: 2 }, + // { label: "far", value: 1 }, + // ]; const parsed = parseRTSPUrl(initialData?.propURI?.value); @@ -36,6 +41,7 @@ const CameraSettingFields = ({ }, [query?.data, onZoomLevelChange]); const getZoomLevel = (levelstring: string | undefined) => { + console.log(levelstring); switch (levelstring) { case "1x": return 1; @@ -46,8 +52,6 @@ const CameraSettingFields = ({ case "4x": return 4; - case "8x": - return 8; default: return 1; } @@ -80,11 +84,13 @@ const CameraSettingFields = ({ const handleRadioButtonChange = async (levelNumber: number) => { if (!onZoomLevelChange || !zoomLevel) return; + const text = zoomMapping(levelNumber); onZoomLevelChange(levelNumber); const zoomInOptions: ZoomInOptions = { camera: cameraControllerSide, multiplier: levelNumber, + multiplierText: text, }; mutation.mutate(zoomInOptions); @@ -169,7 +175,7 @@ const CameraSettingFields = ({
-
+
{zoomOptions.map((zoom) => (
- x{zoom} + {zoomMapping(zoom)}
))} diff --git a/src/components/PlateStack/NumberPlate.tsx b/src/components/PlateStack/NumberPlate.tsx index 3e359fd..d99eb60 100644 --- a/src/components/PlateStack/NumberPlate.tsx +++ b/src/components/PlateStack/NumberPlate.tsx @@ -40,9 +40,7 @@ const NumberPlate = ({ motion, vrm, size }: NumberPlateProps) => { return (
@@ -50,9 +48,7 @@ const NumberPlate = ({ motion, vrm, size }: NumberPlateProps) => {
-

- {vrm && formatNumberPlate(vrm)} -

+

{vrm && formatNumberPlate(vrm)}

); diff --git a/src/components/SettingForms/Channel1-JSON/ChannelFields.tsx b/src/components/SettingForms/Channel1-JSON/ChannelFields.tsx index 24cde7c..397b760 100644 --- a/src/components/SettingForms/Channel1-JSON/ChannelFields.tsx +++ b/src/components/SettingForms/Channel1-JSON/ChannelFields.tsx @@ -58,9 +58,7 @@ const ChannelFields = ({ touched, isSubmitting, format }: ChannelFieldsProps) => type="text" id="backoffice" placeholder="https://www.backoffice.com" - className={`p-1.5 border ${ - errors.backOfficeURL && touched.backOfficeURL ? "border-red-500" : "border-gray-400 " - } rounded-lg w-full md:w-60`} + className={`p-1.5 border border-gray-400 rounded-lg w-full md:w-60`} /> @@ -70,9 +68,7 @@ const ChannelFields = ({ touched, isSubmitting, format }: ChannelFieldsProps) => type="text" id="username" placeholder="Back office username" - className={`p-1.5 border ${ - errors.username && touched.username ? "border-red-500" : "border-gray-400 " - } rounded-lg w-full md:w-60`} + className={`p-1.5 border border-gray-400 rounded-lg w-full md:w-60`} /> @@ -159,7 +155,6 @@ const ChannelFields = ({ touched, isSubmitting, format }: ChannelFieldsProps) => id="timestampSource" className="p-2 border border-gray-400 rounded-lg text-white bg-[#253445] w-full md:w-60" > - @@ -172,9 +167,8 @@ const ChannelFields = ({ touched, isSubmitting, format }: ChannelFieldsProps) => id="GPSFormat" className="p-2 border border-gray-400 rounded-lg text-white bg-[#253445] w-full md:w-60" > - - + diff --git a/src/components/SettingForms/SettingForms/SettingForms.tsx b/src/components/SettingForms/SettingForms/SettingForms.tsx index f89b538..f8451d9 100644 --- a/src/components/SettingForms/SettingForms/SettingForms.tsx +++ b/src/components/SettingForms/SettingForms/SettingForms.tsx @@ -46,16 +46,6 @@ const SettingForms = () => { const validateValues = (values: InitialValuesForm): InitialValuesFormErrors => { const errors: InitialValuesFormErrors = {}; - const url = values.backOfficeURL?.trim(); - const username = values.username?.trim(); - const password = values.password?.trim(); - if (!url) { - errors.backOfficeURL = "Required"; - } - - if (!username) errors.username = "Required"; - if (!password) errors.password = "Required"; - const read = Number(values.readTimeoutSeconds); if (!Number.isFinite(read)) { errors.readTimeoutSeconds = "Must be a number"; diff --git a/src/components/UI/NavigationArrow.tsx b/src/components/UI/NavigationArrow.tsx index e133a88..92e3ee4 100644 --- a/src/components/UI/NavigationArrow.tsx +++ b/src/components/UI/NavigationArrow.tsx @@ -38,7 +38,7 @@ const NavigationArrow = ({ side, settingsPage }: NavigationArrowProps) => { icon={faArrowLeft} size="2xl" className="absolute top-[50%] left-[2%] backdrop-blur-md hover:cursor-pointer animate-bounce z-30" - onClick={() => navigationDest(side)} + onClick={() => navigationDest("Rear")} /> )} diff --git a/src/hooks/useCameraZoom.ts b/src/hooks/useCameraZoom.ts index fb02523..d37416f 100644 --- a/src/hooks/useCameraZoom.ts +++ b/src/hooks/useCameraZoom.ts @@ -1,8 +1,4 @@ -import { - useMutation, - useQuery, - type QueryFunctionContext, -} from "@tanstack/react-query"; +import { useMutation, useQuery, type QueryFunctionContext } from "@tanstack/react-query"; import { CAM_BASE } from "../utils/config"; import type { zoomConfig, ZoomInOptions } from "../types/types"; import { toast } from "sonner"; @@ -10,7 +6,7 @@ import { useEffect } from "react"; async function zoomIn(options: ZoomInOptions) { const response = await fetch( - `${CAM_BASE}/Ip${options.camera}-command?magnification=${options.multiplier}x`, + `${CAM_BASE}/Ip${options.camera}-command?magnification=${options.multiplierText?.toLowerCase()}`, { signal: AbortSignal.timeout(500), } @@ -22,11 +18,9 @@ async function zoomIn(options: ZoomInOptions) { return response.json(); } -async function fetchZoomInConfig({ - queryKey, -}: QueryFunctionContext<[string, zoomConfig]>) { +async function fetchZoomInConfig({ queryKey }: QueryFunctionContext<[string, zoomConfig]>) { const [, { camera }] = queryKey; - const response = await fetch(`${CAM_BASE}/Ip${camera}-inspect`, { + const response = await fetch(`${CAM_BASE}/Ip${camera}-command`, { signal: AbortSignal.timeout(500), }); if (!response.ok) { diff --git a/src/types/types.ts b/src/types/types.ts index 83d2a88..60c9994 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -374,6 +374,7 @@ export type ModemConfig = { export type ZoomInOptions = { camera: string; multiplier: number; + multiplierText?: string; }; export type zoomConfig = { @@ -407,5 +408,6 @@ export type NPEDSTATE = { export type NPEDACTION = { type: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any payload: any; }; diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 4f869e5..0a52ae3 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -158,3 +158,16 @@ 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 zoomMapping = (zoomLevel: number) => { + switch (zoomLevel) { + case 1: + return "Far"; + case 2: + return "Medium"; + case 4: + return "Close"; + default: + break; + } +}; From c127ce8a8c6cb0f83a9baf63311baf90400eafab Mon Sep 17 00:00:00 2001 From: Toba Ojo Date: Tue, 4 Nov 2025 15:29:48 +0000 Subject: [PATCH 02/10] - more addition bugfixes --- .../CameraOverview/SnapshotContainer.tsx | 12 +++--- .../CameraSettings/CameraSettingFields.tsx | 41 ++++++++----------- .../CameraSettings/CameraSettings.tsx | 2 +- .../Channel1-JSON/ChannelCard.tsx | 25 +++++++---- .../SettingForms/SettingForms.tsx | 38 ++++++++++------- src/hooks/useCameraZoom.ts | 6 +-- src/pages/FrontCamera.tsx | 2 +- src/pages/RearCamera.tsx | 2 +- src/utils/utils.ts | 21 ++++++++-- 9 files changed, 87 insertions(+), 62 deletions(-) diff --git a/src/components/CameraOverview/SnapshotContainer.tsx b/src/components/CameraOverview/SnapshotContainer.tsx index a59a44c..7500a46 100644 --- a/src/components/CameraOverview/SnapshotContainer.tsx +++ b/src/components/CameraOverview/SnapshotContainer.tsx @@ -5,7 +5,7 @@ import { useCameraZoom } from "../../hooks/useCameraZoom"; import { useEffect } from "react"; import Loading from "../UI/Loading"; import ErrorState from "../UI/ErrorState"; -import { zoomMapping } from "../../utils/utils"; +import { reverseZoomMapping, zoomMapping } from "../../utils/utils"; type SnapshotContainerProps = { side: string; @@ -17,7 +17,9 @@ type SnapshotContainerProps = { export const SnapshotContainer = ({ side, settingsPage, zoomLevel, onZoomLevelChange }: SnapshotContainerProps) => { const { canvasRef, isError, isPending } = useGetOverviewSnapshot(side); const cameraControllerSide = side === "CameraA" ? "CameraControllerA" : "CameraControllerB"; - const { mutation } = useCameraZoom({ camera: cameraControllerSide }); + const { mutation, query } = useCameraZoom({ camera: cameraControllerSide }); + const magnification = query?.data?.propMagnification?.value; + const apiZoom = reverseZoomMapping(magnification); const handleZoomClick = () => { const baseLevel = zoomLevel ?? 1; @@ -30,16 +32,16 @@ export const SnapshotContainer = ({ side, settingsPage, zoomLevel, onZoomLevelCh useEffect(() => { if (zoomLevel) { - const text = zoomMapping(zoomLevel); + const text = zoomMapping(apiZoom); const zoomInOptions: ZoomInOptions = { camera: cameraControllerSide, multiplier: zoomLevel, multiplierText: text, }; + console.log(zoomInOptions); mutation.mutate(zoomInOptions); } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [zoomLevel]); + }, [cameraControllerSide, apiZoom, zoomLevel]); return (
diff --git a/src/components/CameraSettings/CameraSettingFields.tsx b/src/components/CameraSettings/CameraSettingFields.tsx index 1218236..b9294c6 100644 --- a/src/components/CameraSettings/CameraSettingFields.tsx +++ b/src/components/CameraSettings/CameraSettingFields.tsx @@ -5,13 +5,13 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faEye, faEyeSlash } from "@fortawesome/free-regular-svg-icons"; import CardHeader from "../UI/CardHeader"; import { useCameraZoom } from "../../hooks/useCameraZoom"; -import { parseRTSPUrl, zoomMapping } from "../../utils/utils"; +import { parseRTSPUrl, reverseZoomMapping, zoomMapping } from "../../utils/utils"; type CameraSettingsProps = { initialData: CameraConfig; updateCameraConfig: (values: CameraSettingValues) => Promise | void; zoomLevel?: number; - onZoomLevelChange?: (level: number) => void; + onZoomLevelChange?: (level: number | undefined) => void; updateCameraConfigError: null | Error; }; @@ -26,36 +26,31 @@ const CameraSettingFields = ({ const cameraControllerSide = initialData?.id === "CameraA" ? "CameraControllerA" : "CameraControllerB"; const { mutation, query } = useCameraZoom({ camera: cameraControllerSide }); const zoomOptions = [1, 2, 4]; - // const zoomTextOptions = [ - // { label: "near", value: 4 }, - // { label: "medium", value: 2 }, - // { label: "far", value: 1 }, - // ]; - + const magnification = query?.data?.propMagnification?.value; + const apiZoom = reverseZoomMapping(magnification); const parsed = parseRTSPUrl(initialData?.propURI?.value); useEffect(() => { if (!query?.data) return; - const apiZoom = getZoomLevel(query.data); onZoomLevelChange?.(apiZoom); }, [query?.data, onZoomLevelChange]); - const getZoomLevel = (levelstring: string | undefined) => { - console.log(levelstring); - switch (levelstring) { - case "1x": - return 1; + // const getZoomLevel = (levelstring: string | undefined) => { + // console.log(levelstring); + // switch (levelstring) { + // case "1x": + // return 1; - case "2x": - return 2; + // case "2x": + // return 2; - case "4x": - return 4; + // case "4x": + // return 4; - default: - return 1; - } - }; + // default: + // return 1; + // } + // }; const initialValues = useMemo( () => ({ @@ -65,7 +60,7 @@ const CameraSettingFields = ({ password: parsed?.password ?? "", id: initialData?.id, - zoom: zoomLevel, + zoom: apiZoom, }), // eslint-disable-next-line react-hooks/exhaustive-deps [initialData?.id, initialData?.propURI?.value, zoomLevel] diff --git a/src/components/CameraSettings/CameraSettings.tsx b/src/components/CameraSettings/CameraSettings.tsx index c491f6c..2536374 100644 --- a/src/components/CameraSettings/CameraSettings.tsx +++ b/src/components/CameraSettings/CameraSettings.tsx @@ -13,7 +13,7 @@ const CameraSettings = ({ title: string; side: string; zoomLevel?: number; - onZoomLevelChange?: (level: number) => void; + onZoomLevelChange?: (level: number | undefined) => void; }) => { const { data, updateCameraConfig, updateCameraConfigError } = useFetchCameraConfig(side); diff --git a/src/components/SettingForms/Channel1-JSON/ChannelCard.tsx b/src/components/SettingForms/Channel1-JSON/ChannelCard.tsx index 3311e09..86f8879 100644 --- a/src/components/SettingForms/Channel1-JSON/ChannelCard.tsx +++ b/src/components/SettingForms/Channel1-JSON/ChannelCard.tsx @@ -9,14 +9,17 @@ import { useEffect, useMemo } from "react"; type ChannelCardProps = { touched: FormikTouched; isSubmitting: boolean; + isBof2ConstantsLoading: boolean; + isDispatcherLoading: boolean; }; -const ChannelCard = ({ touched, isSubmitting }: ChannelCardProps) => { +const ChannelCard = ({ touched, isSubmitting, isBof2ConstantsLoading, isDispatcherLoading }: ChannelCardProps) => { const { values, setFieldValue } = useFormikContext(); const { backOfficeQuery } = useCameraBackOfficeOutput(values?.format); + const isBackOfficeQueryLoading = backOfficeQuery?.isFetching; const mapped = useMemo(() => { - const d = backOfficeQuery.data; + const d = backOfficeQuery?.data; return { backOfficeURL: d?.propBackofficeURL?.value ?? "", username: d?.propUsername?.value ?? "", @@ -27,7 +30,7 @@ const ChannelCard = ({ touched, isSubmitting }: ChannelCardProps) => { }, [backOfficeQuery.data]); useEffect(() => { - if (!backOfficeQuery.isSuccess) return; + if (!backOfficeQuery?.isSuccess) return; for (const [key, value] of Object.entries(mapped)) { setFieldValue(key, value); } @@ -36,12 +39,16 @@ const ChannelCard = ({ touched, isSubmitting }: ChannelCardProps) => { return ( - + {!isBof2ConstantsLoading && !isDispatcherLoading && !isBackOfficeQueryLoading ? ( + + ) : ( + <>Loading... + )} ); }; diff --git a/src/components/SettingForms/SettingForms/SettingForms.tsx b/src/components/SettingForms/SettingForms/SettingForms.tsx index f8451d9..f3cd9be 100644 --- a/src/components/SettingForms/SettingForms/SettingForms.tsx +++ b/src/components/SettingForms/SettingForms/SettingForms.tsx @@ -27,6 +27,9 @@ const SettingForms = () => { const GPSFormat = bof2ConstantsQuery?.data?.propGpsFormat?.value; const timestampSource = bof2ConstantsQuery?.data?.propTimeZoneType?.value; + const isDispatcherLoading = dispatcherQuery?.isFetching; + const isBof2ConstantsLoading = bof2ConstantsQuery?.isFetching; + const initialValues: BearerTypeFieldType & InitialValuesForm & OptionalBOF2Constants = { format: format ?? "JSON", enabled: enabled === "true", @@ -63,9 +66,8 @@ const SettingForms = () => { }; const handleSubmit = async (values: BearerTypeFieldType & InitialValuesForm & OptionalBOF2Constants) => { - // if (formErrors && Object.entries(formErrors).length > 0) { - // return; - // } + const validResponse = await validateMutation.mutateAsync(values); + const dispatcherData = { format: values.format, enabled: values.enabled, @@ -75,23 +77,24 @@ const SettingForms = () => { if (result?.id) { qc.invalidateQueries({ queryKey: ["dispatcher"] }); qc.invalidateQueries({ queryKey: ["backoffice", values.format] }); - const validResponse = await validateMutation.mutateAsync(values); + if (validResponse?.reason === "OK") { await backOfficeMutation.mutateAsync(values); + + if (values.format.toLowerCase() === "bof2") { + const bof2ConstantsData: OptionalBOF2Constants = { + FFID: values.FFID, + SCID: values.SCID, + timestampSource: values.timestampSource, + GPSFormat: values.GPSFormat, + }; + await backOfficeDispatcherMutation.mutateAsync(bof2ConstantsData); + } } else { + console.log("error"); return; } } - - if (values.format.toLowerCase() === "bof2") { - const bof2ConstantsData: OptionalBOF2Constants = { - FFID: values.FFID, - SCID: values.SCID, - timestampSource: values.timestampSource, - GPSFormat: values.GPSFormat, - }; - await backOfficeDispatcherMutation.mutateAsync(bof2ConstantsData); - } }; return ( @@ -100,7 +103,12 @@ const SettingForms = () => {
- +
)} diff --git a/src/hooks/useCameraZoom.ts b/src/hooks/useCameraZoom.ts index d37416f..817217c 100644 --- a/src/hooks/useCameraZoom.ts +++ b/src/hooks/useCameraZoom.ts @@ -20,13 +20,13 @@ async function zoomIn(options: ZoomInOptions) { async function fetchZoomInConfig({ queryKey }: QueryFunctionContext<[string, zoomConfig]>) { const [, { camera }] = queryKey; - const response = await fetch(`${CAM_BASE}/Ip${camera}-command`, { + const response = await fetch(`${CAM_BASE}/api/fetch-config?id=Ip${camera}`, { signal: AbortSignal.timeout(500), }); if (!response.ok) { throw new Error("Cannot get camera zoom settings"); } - return response.text(); + return response.json(); } //change to string export const useCameraZoom = (options: zoomConfig) => { @@ -46,7 +46,7 @@ export const useCameraZoom = (options: zoomConfig) => { }); useEffect(() => { - if (query.isError) toast.error(query.error.message, { id: "hardReboot" }); + if (query.isError) toast.error(query.error.message, { id: "zoom" }); }, [query?.error?.message, query.isError]); return { mutation, query }; diff --git a/src/pages/FrontCamera.tsx b/src/pages/FrontCamera.tsx index 2e63620..b3ce215 100644 --- a/src/pages/FrontCamera.tsx +++ b/src/pages/FrontCamera.tsx @@ -4,7 +4,7 @@ import OverviewVideoContainer from "../components/FrontCameraSettings/OverviewVi import { Toaster } from "sonner"; const FrontCamera = () => { - const [zoomLevel, setZoomLevel] = useState(1); + const [zoomLevel, setZoomLevel] = useState(1); return (
{ - const [zoomLevel, setZoomLevel] = useState(1); + const [zoomLevel, setZoomLevel] = useState(1); return (
r?.metadata?.npedJSON?.["NPED CATEGORY"] as "A" | "B" | "C" | "D" | undefined; -export const zoomMapping = (zoomLevel: number) => { +export const zoomMapping = (zoomLevel: number | undefined) => { switch (zoomLevel) { case 1: - return "Far"; + return "Near"; case 2: - return "Medium"; + return "Mid"; case 4: - return "Close"; + return "Far"; + default: + break; + } +}; + +export const reverseZoomMapping = (magnification: string) => { + switch (magnification) { + case "near": + return 1; + case "mid": + return 2; + case "far": + return 4; default: break; } From 647fd201a3899464eaa5bffa6ed636de21357e00 Mon Sep 17 00:00:00 2001 From: Toba Ojo Date: Tue, 4 Nov 2025 16:09:24 +0000 Subject: [PATCH 03/10] - minor tweaks on zoom and navigation arrow --- src/App.tsx | 4 +- .../CameraOverview/SnapshotContainer.tsx | 23 +-- .../FrontCameraOverviewCard.tsx | 4 +- .../OverviewVideoContainer.tsx | 4 +- .../RearCameraOverviewCard.tsx | 2 +- .../SettingForms/WiFi&Modem/ModemSettings.tsx | 141 +++++++++--------- src/components/UI/NavigationArrow.tsx | 8 +- src/hooks/useCameraWifiandModem.ts | 9 +- src/hooks/useCameraZoom.ts | 1 + 9 files changed, 90 insertions(+), 106 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 980e322..5aaa5a7 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -19,8 +19,8 @@ function App() { }> } /> - } /> - } /> + } /> + } /> } /> } /> } /> diff --git a/src/components/CameraOverview/SnapshotContainer.tsx b/src/components/CameraOverview/SnapshotContainer.tsx index 7500a46..3065c3e 100644 --- a/src/components/CameraOverview/SnapshotContainer.tsx +++ b/src/components/CameraOverview/SnapshotContainer.tsx @@ -1,12 +1,8 @@ import { useGetOverviewSnapshot } from "../../hooks/useGetOverviewSnapshot"; -import type { ZoomInOptions } from "../../types/types"; import NavigationArrow from "../UI/NavigationArrow"; -import { useCameraZoom } from "../../hooks/useCameraZoom"; -import { useEffect } from "react"; + import Loading from "../UI/Loading"; import ErrorState from "../UI/ErrorState"; -import { reverseZoomMapping, zoomMapping } from "../../utils/utils"; - type SnapshotContainerProps = { side: string; settingsPage?: boolean; @@ -16,10 +12,6 @@ type SnapshotContainerProps = { export const SnapshotContainer = ({ side, settingsPage, zoomLevel, onZoomLevelChange }: SnapshotContainerProps) => { const { canvasRef, isError, isPending } = useGetOverviewSnapshot(side); - const cameraControllerSide = side === "CameraA" ? "CameraControllerA" : "CameraControllerB"; - const { mutation, query } = useCameraZoom({ camera: cameraControllerSide }); - const magnification = query?.data?.propMagnification?.value; - const apiZoom = reverseZoomMapping(magnification); const handleZoomClick = () => { const baseLevel = zoomLevel ?? 1; @@ -30,19 +22,6 @@ export const SnapshotContainer = ({ side, settingsPage, zoomLevel, onZoomLevelCh if (!zoomLevel) return; }; - useEffect(() => { - if (zoomLevel) { - const text = zoomMapping(apiZoom); - const zoomInOptions: ZoomInOptions = { - camera: cameraControllerSide, - multiplier: zoomLevel, - multiplierText: text, - }; - console.log(zoomInOptions); - mutation.mutate(zoomInOptions); - } - }, [cameraControllerSide, apiZoom, zoomLevel]); - return (
diff --git a/src/components/FrontCameraOverview/FrontCameraOverviewCard.tsx b/src/components/FrontCameraOverview/FrontCameraOverviewCard.tsx index 0aa1787..255c979 100644 --- a/src/components/FrontCameraOverview/FrontCameraOverviewCard.tsx +++ b/src/components/FrontCameraOverview/FrontCameraOverviewCard.tsx @@ -8,8 +8,8 @@ import SightingOverview from "../SightingOverview/SightingOverview"; const FrontCameraOverviewCard = () => { const navigate = useNavigate(); const handlers = useSwipeable({ - onSwipedRight: () => navigate("/camera-settings"), - onSwipedLeft: () => navigate("/rear-camera-settings"), + onSwipedRight: () => navigate("/a-camera-settings"), + onSwipedLeft: () => navigate("/b-camera-settings"), trackMouse: true, }); diff --git a/src/components/FrontCameraSettings/OverviewVideoContainer.tsx b/src/components/FrontCameraSettings/OverviewVideoContainer.tsx index 379f95b..3f0be06 100644 --- a/src/components/FrontCameraSettings/OverviewVideoContainer.tsx +++ b/src/components/FrontCameraSettings/OverviewVideoContainer.tsx @@ -20,11 +20,11 @@ const OverviewVideoContainer = ({ const location = useLocation(); const handlers = useSwipeable({ onSwipedLeft: () => { - if (location.pathname === "/rear-camera-settings") return; + if (location.pathname === "/b-camera-settings") return; navigate("/"); }, onSwipedRight: () => { - if (location.pathname === "/camera-settings") return; + if (location.pathname === "/a-camera-settings") return; navigate("/"); }, trackMouse: true, diff --git a/src/components/RearCameraOverview/RearCameraOverviewCard.tsx b/src/components/RearCameraOverview/RearCameraOverviewCard.tsx index 883d096..9fa608e 100644 --- a/src/components/RearCameraOverview/RearCameraOverviewCard.tsx +++ b/src/components/RearCameraOverview/RearCameraOverviewCard.tsx @@ -13,7 +13,7 @@ type CardProps = React.HTMLAttributes; const RearCameraOverviewCard = ({ className }: CardProps) => { const navigate = useNavigate(); const handlers = useSwipeable({ - onSwipedLeft: () => navigate("/rear-camera-settings"), + onSwipedLeft: () => navigate("/b-camera-settings"), trackMouse: true, }); const { mostRecent } = useSightingFeedContext(); diff --git a/src/components/SettingForms/WiFi&Modem/ModemSettings.tsx b/src/components/SettingForms/WiFi&Modem/ModemSettings.tsx index d84618f..56cc831 100644 --- a/src/components/SettingForms/WiFi&Modem/ModemSettings.tsx +++ b/src/components/SettingForms/WiFi&Modem/ModemSettings.tsx @@ -57,78 +57,81 @@ const ModemSettings = () => { return ( <> - {!showSettings && ( - - {({ isSubmitting }) => ( -
- - - - - - - - - - -
+ + + {({ isSubmitting }) => ( + + {!showSettings && ( + <> + + - setShowPwd((s) => !s)} - icon={showPwd ? faEyeSlash : faEye} + + + + -
-
- - - - - - - - - -
- )} -
- )} + + + +
+ + setShowPwd((s) => !s)} + icon={showPwd ? faEyeSlash : faEye} + /> +
+
+ + + + + + + + + + )} + + + )} + ); }; diff --git a/src/components/UI/NavigationArrow.tsx b/src/components/UI/NavigationArrow.tsx index 92e3ee4..f3011ae 100644 --- a/src/components/UI/NavigationArrow.tsx +++ b/src/components/UI/NavigationArrow.tsx @@ -17,9 +17,9 @@ const NavigationArrow = ({ side, settingsPage }: NavigationArrowProps) => { } if (side === "Front") { - navigate("/camera-settings"); + navigate("/a-camera-settings"); } else if (side === "Rear") { - navigate("/Rear-Camera-settings"); + navigate("/b-Camera-settings"); } }; @@ -31,14 +31,14 @@ const NavigationArrow = ({ side, settingsPage }: NavigationArrowProps) => { size="2xl" icon={faArrowRight} className="absolute top-[50%] right-[2%] backdrop-blur-lg hover:cursor-pointer animate-bounce z-30" - onClick={() => navigationDest("Front")} + onClick={() => navigationDest("a")} /> ) : ( navigationDest("Rear")} + onClick={() => navigationDest("b")} /> )} diff --git a/src/hooks/useCameraWifiandModem.ts b/src/hooks/useCameraWifiandModem.ts index 6e5edce..f881f54 100644 --- a/src/hooks/useCameraWifiandModem.ts +++ b/src/hooks/useCameraWifiandModem.ts @@ -3,9 +3,10 @@ import { CAM_BASE } from "../utils/config"; import type { ModemConfig, WifiConfig } from "../types/types"; import { useEffect } from "react"; import { toast } from "sonner"; +const camBase = import.meta.env.MODE !== "development" ? CAM_BASE : ""; const getWiFiSettings = async () => { - const response = await fetch(`${CAM_BASE}/api/fetch-config?id=ModemAndWifiManager-wifi`, { + const response = await fetch(`${camBase}/api/fetch-config?id=ModemAndWifiManager-wifi`, { signal: AbortSignal.timeout(500), }); if (!response.ok) { @@ -15,7 +16,7 @@ const getWiFiSettings = async () => { }; const updateWifiSettings = async (wifiConfig: WifiConfig) => { - const response = await fetch(`${CAM_BASE}/api/update-config?id=ModemAndWifiManager-wifi`, { + const response = await fetch(`${camBase}/api/update-config?id=ModemAndWifiManager-wifi`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(wifiConfig), @@ -27,7 +28,7 @@ const updateWifiSettings = async (wifiConfig: WifiConfig) => { }; const getModemSettings = async () => { - const response = await fetch(`${CAM_BASE}/api/fetch-config?id=ModemAndWifiManager-modem`, { + const response = await fetch(`${camBase}/api/fetch-config?id=ModemAndWifiManager-modem`, { signal: AbortSignal.timeout(500), }); if (!response.ok) { @@ -37,7 +38,7 @@ const getModemSettings = async () => { }; const updateModemSettings = async (modemConfig: ModemConfig) => { - const response = await fetch(`${CAM_BASE}/api/update-config?id=ModemAndWifiManager-modem`, { + const response = await fetch(`${camBase}/api/update-config?id=ModemAndWifiManager-modem`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(modemConfig), diff --git a/src/hooks/useCameraZoom.ts b/src/hooks/useCameraZoom.ts index 817217c..497812b 100644 --- a/src/hooks/useCameraZoom.ts +++ b/src/hooks/useCameraZoom.ts @@ -5,6 +5,7 @@ import { toast } from "sonner"; import { useEffect } from "react"; async function zoomIn(options: ZoomInOptions) { + console.log(options); const response = await fetch( `${CAM_BASE}/Ip${options.camera}-command?magnification=${options.multiplierText?.toLowerCase()}`, { From 861f2dd31dc68383ff4bba597f9effe661d5b01d Mon Sep 17 00:00:00 2001 From: Toba Ojo Date: Tue, 4 Nov 2025 17:04:19 +0000 Subject: [PATCH 04/10] - added endpoints for dns and other --- .../BearerType/BearerTypeCard.tsx | 2 +- .../Channel1-JSON/ChannelCard.tsx | 2 +- .../Channel1-JSON/ChannelFields.tsx | 133 +++++++++++------- .../SettingForms/SettingForms.tsx | 24 +++- .../SettingForms/System/SettingSaveRecall.tsx | 22 +-- .../System/SystemConfigFields.tsx | 41 +++++- src/hooks/useCameraOutput.ts | 45 +++++- src/hooks/useSystemConfig.ts | 55 +++++++- src/types/types.ts | 21 ++- 9 files changed, 261 insertions(+), 84 deletions(-) diff --git a/src/components/SettingForms/BearerType/BearerTypeCard.tsx b/src/components/SettingForms/BearerType/BearerTypeCard.tsx index 2e42a60..b5eaa02 100644 --- a/src/components/SettingForms/BearerType/BearerTypeCard.tsx +++ b/src/components/SettingForms/BearerType/BearerTypeCard.tsx @@ -4,7 +4,7 @@ import BearerTypeFields from "./BearerTypeFields"; const BearerTypeCard = () => { return ( - + diff --git a/src/components/SettingForms/Channel1-JSON/ChannelCard.tsx b/src/components/SettingForms/Channel1-JSON/ChannelCard.tsx index 86f8879..3d2e1a1 100644 --- a/src/components/SettingForms/Channel1-JSON/ChannelCard.tsx +++ b/src/components/SettingForms/Channel1-JSON/ChannelCard.tsx @@ -37,7 +37,7 @@ const ChannelCard = ({ touched, isSubmitting, isBof2ConstantsLoading, isDispatch }, [backOfficeQuery.isSuccess, mapped, setFieldValue]); return ( - + {!isBof2ConstantsLoading && !isDispatcherLoading && !isBackOfficeQueryLoading ? ( {format?.toLowerCase() === "bof2" && ( <> -
-

{values.format} Constants

+
+
+

{values.format} Constants

+
+ + + + + + + + + + + + + + + + + + + + + + +
+
+
+

{values.format} Lane ID Config

+
+ + + + + + + +
- - - - - - - - - - - - - - - - - - - - - - - - )}
diff --git a/src/components/SettingForms/SettingForms/SettingForms.tsx b/src/components/SettingForms/SettingForms/SettingForms.tsx index f3cd9be..e3db87c 100644 --- a/src/components/SettingForms/SettingForms/SettingForms.tsx +++ b/src/components/SettingForms/SettingForms/SettingForms.tsx @@ -7,6 +7,7 @@ import type { InitialValuesForm, InitialValuesFormErrors, OptionalBOF2Constants, + OptionalBOF2LaneIDs, } from "../../../types/types"; import { useQueryClient } from "@tanstack/react-query"; import { useUpdateBackOfficeConfig } from "../../../hooks/useBackOfficeConfig"; @@ -14,7 +15,8 @@ import { useFormVaidate } from "../../../hooks/useFormValidate"; const SettingForms = () => { const qc = useQueryClient(); - const { dispatcherQuery, dispatcherMutation, backOfficeDispatcherMutation } = useCameraOutput(); + const { dispatcherQuery, dispatcherMutation, backOfficeDispatcherMutation, bof2LandMutation, laneIdQuery } = + useCameraOutput(); const { backOfficeMutation } = useUpdateBackOfficeConfig(); const { bof2ConstantsQuery } = useGetDispatcherConfig(); const { validateMutation } = useFormVaidate(); @@ -22,6 +24,9 @@ const SettingForms = () => { const format = dispatcherQuery?.data?.propFormat?.value; const enabled = dispatcherQuery?.data?.propEnabled?.value; + const LID1 = laneIdQuery?.data?.propLaneID1?.value; + const LID2 = laneIdQuery?.data?.propLaneID2?.value; + const FFID = bof2ConstantsQuery?.data?.propFeedIdentifier?.value; const SCID = bof2ConstantsQuery?.data?.propSourceIdentifier?.value; const GPSFormat = bof2ConstantsQuery?.data?.propGpsFormat?.value; @@ -30,7 +35,7 @@ const SettingForms = () => { const isDispatcherLoading = dispatcherQuery?.isFetching; const isBof2ConstantsLoading = bof2ConstantsQuery?.isFetching; - const initialValues: BearerTypeFieldType & InitialValuesForm & OptionalBOF2Constants = { + const initialValues: BearerTypeFieldType & InitialValuesForm & OptionalBOF2Constants & OptionalBOF2LaneIDs = { format: format ?? "JSON", enabled: enabled === "true", backOfficeURL: "", @@ -44,6 +49,10 @@ const SettingForms = () => { SCID: SCID ?? "", timestampSource: timestampSource ?? "", GPSFormat: GPSFormat ?? "", + + //BOF2 - optional Lane IDs + LID1: LID1 ?? "", + LID2: LID2 ?? "", }; const validateValues = (values: InitialValuesForm): InitialValuesFormErrors => { @@ -65,7 +74,9 @@ const SettingForms = () => { return errors; }; - const handleSubmit = async (values: BearerTypeFieldType & InitialValuesForm & OptionalBOF2Constants) => { + const handleSubmit = async ( + values: BearerTypeFieldType & InitialValuesForm & OptionalBOF2Constants & OptionalBOF2LaneIDs + ) => { const validResponse = await validateMutation.mutateAsync(values); const dispatcherData = { @@ -88,6 +99,13 @@ const SettingForms = () => { timestampSource: values.timestampSource, GPSFormat: values.GPSFormat, }; + + const bof2LaneData: OptionalBOF2LaneIDs = { + LID1: values.LID1, + LID2: values.LID2, + LID3: values.LID3, + }; + await bof2LandMutation.mutateAsync(bof2LaneData); await backOfficeDispatcherMutation.mutateAsync(bof2ConstantsData); } } else { diff --git a/src/components/SettingForms/System/SettingSaveRecall.tsx b/src/components/SettingForms/System/SettingSaveRecall.tsx index 8d9b3e7..b2a3de4 100644 --- a/src/components/SettingForms/System/SettingSaveRecall.tsx +++ b/src/components/SettingForms/System/SettingSaveRecall.tsx @@ -2,6 +2,8 @@ import { toast } from "sonner"; import type { SystemValues } from "../../../types/types"; import { CAM_BASE } from "../../../utils/config"; +const camBase = import.meta.env.MODE !== "development" ? CAM_BASE : ""; + export async function handleSystemSave(values: SystemValues) { const payload = { // Build JSON @@ -18,7 +20,7 @@ export async function handleSystemSave(values: SystemValues) { }; try { - const response = await fetch(`${CAM_BASE}/api/update-config`, { + const response = await fetch(`${camBase}/api/update-config`, { method: "POST", headers: { "Content-Type": "application/json", @@ -29,11 +31,7 @@ export async function handleSystemSave(values: SystemValues) { if (!response.ok) { const text = await response.text().catch(() => ""); - throw new Error( - `HTTP ${response.status} ${response.statusText}${ - text ? ` - ${text}` : "" - }` - ); + throw new Error(`HTTP ${response.status} ${response.statusText}${text ? ` - ${text}` : ""}`); } } catch (err) { if (err instanceof Error) { @@ -47,7 +45,7 @@ export async function handleSystemSave(values: SystemValues) { } export async function handleSystemRecall() { - const url = `${CAM_BASE}/api/fetch-config?id=GLOBAL--Device`; + const url = `${camBase}/api/fetch-config?id=GLOBAL--Device`; const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 7000); @@ -61,11 +59,7 @@ export async function handleSystemRecall() { if (!response.ok) { const text = await response.text().catch(() => ""); - throw new Error( - `HTTP ${response.status} ${response.statusText}${ - text ? ` - ${text}` : "" - }` - ); + throw new Error(`HTTP ${response.status} ${response.statusText}${text ? ` - ${text}` : ""}`); } const data = await response.json(); @@ -76,9 +70,7 @@ export async function handleSystemRecall() { const sntpIntervalRaw = data?.propSNTPIntervalMinutes?.value; let sntpInterval = - typeof sntpIntervalRaw === "number" - ? sntpIntervalRaw - : Number.parseInt(String(sntpIntervalRaw).trim(), 10); + typeof sntpIntervalRaw === "number" ? sntpIntervalRaw : Number.parseInt(String(sntpIntervalRaw).trim(), 10); if (!Number.isFinite(sntpInterval)) { sntpInterval = 60; diff --git a/src/components/SettingForms/System/SystemConfigFields.tsx b/src/components/SettingForms/System/SystemConfigFields.tsx index 21a280e..93627e5 100644 --- a/src/components/SettingForms/System/SystemConfigFields.tsx +++ b/src/components/SettingForms/System/SystemConfigFields.tsx @@ -4,21 +4,30 @@ import { useReboots } from "../../../hooks/useReboots"; import { timezones } from "./timezones"; import SystemFileUpload from "./SystemFileUpload"; import type { SystemValues, SystemValuesErrors } from "../../../types/types"; -import { useSystemConfig } from "../../../hooks/useSystemConfig"; +import { useDNSSettings, useSystemConfig } from "../../../hooks/useSystemConfig"; const SystemConfigFields = () => { const { saveSystemSettings, systemSettingsData, saveSystemSettingsLoading } = useSystemConfig(); const { softRebootMutation, hardRebootMutation } = useReboots(); + const { dnsQuery, dnsMutation } = useDNSSettings(); + console.log(dnsQuery?.data); + const dnsPrimary = dnsQuery?.data?.propNameServerPrimary?.value; + const dnsSecondary = dnsQuery?.data?.propNameServerSecondary?.value; const initialvalues: SystemValues = { deviceName: systemSettingsData?.deviceName ?? "", timeZone: systemSettingsData?.timeZone ?? "", sntpServer: systemSettingsData?.sntpServer ?? "", sntpInterval: systemSettingsData?.sntpInterval ?? 60, + serverPrimary: dnsPrimary ?? "", + serverSecondary: dnsSecondary ?? "", softwareUpdate: null, }; - const handleSubmit = (values: SystemValues) => saveSystemSettings(values); + const handleSubmit = async (values: SystemValues) => { + saveSystemSettings(values); + await dnsMutation.mutateAsync(values); + }; const validateValues = (values: SystemValues) => { const errors: SystemValuesErrors = {}; @@ -102,6 +111,34 @@ const SystemConfigFields = () => { autoComplete="off" /> + + + + + + + + + +
-
+
+ +
+ + +
+
+ {/*
{updateCameraConfigError ? ( )} -
+
*/}
)} diff --git a/src/components/CameraSettings/CameraSettings.tsx b/src/components/CameraSettings/CameraSettings.tsx index 2536374..29fa40a 100644 --- a/src/components/CameraSettings/CameraSettings.tsx +++ b/src/components/CameraSettings/CameraSettings.tsx @@ -18,7 +18,7 @@ const CameraSettings = ({ const { data, updateCameraConfig, updateCameraConfigError } = useFetchCameraConfig(side); return ( - +
diff --git a/src/components/SettingForms/Channel1-JSON/ChannelFields.tsx b/src/components/SettingForms/Channel1-JSON/ChannelFields.tsx index c4ab990..36b505f 100644 --- a/src/components/SettingForms/Channel1-JSON/ChannelFields.tsx +++ b/src/components/SettingForms/Channel1-JSON/ChannelFields.tsx @@ -115,7 +115,35 @@ const ChannelFields = ({ touched, isSubmitting, format }: ChannelFieldsProps) => } rounded-lg w-full md:w-60`} /> - + {/* Overview quality and scale */} + + + + + + + + + {/* propOverviewImageScaleFactor cropSizeFactor */} + + + + + + + + + {format?.toLowerCase() === "bof2" && ( <>
@@ -176,7 +204,7 @@ const ChannelFields = ({ touched, isSubmitting, format }: ChannelFieldsProps) =>

{values.format} Lane ID Config

- + /> - + { const qc = useQueryClient(); @@ -20,10 +21,14 @@ const SettingForms = () => { const { backOfficeMutation } = useUpdateBackOfficeConfig(); const { bof2ConstantsQuery } = useGetDispatcherConfig(); const { validateMutation } = useFormVaidate(); + const { sightingAmendQuery, sightingAmendMutation } = useSightingAmend(); const format = dispatcherQuery?.data?.propFormat?.value; const enabled = dispatcherQuery?.data?.propEnabled?.value; + const sightingQuality = sightingAmendQuery?.data?.propOverviewQuality?.value; + const cropSizeFactor = sightingAmendQuery?.data?.propOverviewImageScaleFactor?.value; + const LID1 = laneIdQuery?.data?.propLaneID1?.value; const LID2 = laneIdQuery?.data?.propLaneID2?.value; @@ -43,6 +48,8 @@ const SettingForms = () => { password: "", connectTimeoutSeconds: Number(5), readTimeoutSeconds: Number(15), + overviewQuality: sightingQuality ?? "HIGH", + cropSizeFactor: cropSizeFactor ?? "3/4", // Bof2 - optional constants FFID: FFID ?? "", @@ -91,6 +98,7 @@ const SettingForms = () => { if (validResponse?.reason === "OK") { await backOfficeMutation.mutateAsync(values); + await sightingAmendMutation.mutateAsync(values); if (values.format.toLowerCase() === "bof2") { const bof2ConstantsData: OptionalBOF2Constants = { diff --git a/src/components/SettingForms/System/SystemConfigFields.tsx b/src/components/SettingForms/System/SystemConfigFields.tsx index 93627e5..7d8951f 100644 --- a/src/components/SettingForms/System/SystemConfigFields.tsx +++ b/src/components/SettingForms/System/SystemConfigFields.tsx @@ -8,9 +8,8 @@ import { useDNSSettings, useSystemConfig } from "../../../hooks/useSystemConfig" const SystemConfigFields = () => { const { saveSystemSettings, systemSettingsData, saveSystemSettingsLoading } = useSystemConfig(); - const { softRebootMutation, hardRebootMutation } = useReboots(); + const { hardRebootMutation } = useReboots(); const { dnsQuery, dnsMutation } = useDNSSettings(); - console.log(dnsQuery?.data); const dnsPrimary = dnsQuery?.data?.propNameServerPrimary?.value; const dnsSecondary = dnsQuery?.data?.propNameServerSecondary?.value; @@ -39,9 +38,9 @@ const SystemConfigFields = () => { return errors; }; - const handleSoftReboot = async () => { - await softRebootMutation.mutate(); - }; + // const handleSoftReboot = async () => { + // await softRebootMutation.mutate(); + // }; const handleHardReboot = async () => { await hardRebootMutation.mutate(); @@ -111,34 +110,7 @@ const SystemConfigFields = () => { autoComplete="off" /> - - - - - - - - - + + + + + + + + + +
- + */}
@@ -164,7 +142,6 @@ const CameraSettingFields = ({ type={showPwd ? "text" : "password"} className="p-2 border border-gray-400 rounded-lg w-full " placeholder="Enter password" - disabled />
-
- - +
+ {["day", "night"].map((el) => ( +
+ { + setFieldValue("mode", el); + await cameraModeMutation.mutateAsync({ camera: cameraControllerSide, mode: el }); + }} + /> + +
+ ))}
- {/*
- {updateCameraConfigError ? ( - - ) : ( - - )} -
*/} + } +
)} diff --git a/src/components/CameraSettings/CameraSettings.tsx b/src/components/CameraSettings/CameraSettings.tsx index 29fa40a..22156fc 100644 --- a/src/components/CameraSettings/CameraSettings.tsx +++ b/src/components/CameraSettings/CameraSettings.tsx @@ -18,10 +18,9 @@ const CameraSettings = ({ const { data, updateCameraConfig, updateCameraConfigError } = useFetchCameraConfig(side); return ( - +
- { { navigationDest("a")} /> ) : ( navigationDest("b")} /> )} @@ -49,14 +49,14 @@ const NavigationArrow = ({ side, settingsPage }: NavigationArrowProps) => { navigationDest("Front")} /> navigationDest("Rear")} /> diff --git a/src/hooks/useCameraConfig.ts b/src/hooks/useCameraConfig.ts index df4e30a..cd78a43 100644 --- a/src/hooks/useCameraConfig.ts +++ b/src/hooks/useCameraConfig.ts @@ -31,7 +31,7 @@ const updateCamerasideConfig = async (data: { id: string | number; friendlyName: method: "POST", body: JSON.stringify(updateConfigPayload), }); - if (!response.ok) throw new Error("Feature unavailable: Coming soon"); + if (!response.ok) throw new Error("Please make sure fields are filled in correctly"); }; export const useFetchCameraConfig = (cameraSide: string) => { diff --git a/src/hooks/useCameraZoom.ts b/src/hooks/useCameraZoom.ts index 7862f1f..e7e174a 100644 --- a/src/hooks/useCameraZoom.ts +++ b/src/hooks/useCameraZoom.ts @@ -11,6 +11,7 @@ const getCameraMode = async (options: { camera: string }) => { }; const updateCameraMode = async (options: { camera: string; mode: string }) => { + console.log(options); const dayNightPayload = { id: options.camera, fields: [ diff --git a/src/index.css b/src/index.css index 326a490..92bfa28 100644 --- a/src/index.css +++ b/src/index.css @@ -31,3 +31,9 @@ body { } } } + +.arrow-outline path { + stroke: black; /* outline color */ + stroke-width: 20px; /* thickness of outline (tweak this) */ + stroke-linejoin: round; +} diff --git a/src/pages/RearCamera.tsx b/src/pages/RearCamera.tsx index e73d7a4..1306908 100644 --- a/src/pages/RearCamera.tsx +++ b/src/pages/RearCamera.tsx @@ -6,7 +6,7 @@ import { useState } from "react"; const RearCamera = () => { const [zoomLevel, setZoomLevel] = useState(1); return ( -
+
>; From cac9a2167df347af099a4b0d0f0c122d953363f3 Mon Sep 17 00:00:00 2001 From: Toba Ojo Date: Mon, 10 Nov 2025 13:47:19 +0000 Subject: [PATCH 09/10] - tweaked timeouts --- src/components/SettingForms/System/SettingSaveRecall.tsx | 2 +- src/hooks/useCameraWifiandModem.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/SettingForms/System/SettingSaveRecall.tsx b/src/components/SettingForms/System/SettingSaveRecall.tsx index b2a3de4..9a240ed 100644 --- a/src/components/SettingForms/System/SettingSaveRecall.tsx +++ b/src/components/SettingForms/System/SettingSaveRecall.tsx @@ -48,7 +48,7 @@ export async function handleSystemRecall() { const url = `${camBase}/api/fetch-config?id=GLOBAL--Device`; const controller = new AbortController(); - const timeoutId = setTimeout(() => controller.abort(), 7000); + const timeoutId = setTimeout(() => controller.abort(), 70000); try { const response = await fetch(url, { diff --git a/src/hooks/useCameraWifiandModem.ts b/src/hooks/useCameraWifiandModem.ts index c099a63..13a15de 100644 --- a/src/hooks/useCameraWifiandModem.ts +++ b/src/hooks/useCameraWifiandModem.ts @@ -7,7 +7,7 @@ const camBase = import.meta.env.MODE !== "development" ? CAM_BASE : ""; const getWiFiSettings = async () => { const response = await fetch(`${camBase}/api/fetch-config?id=ModemAndWifiManager-wifi`, { - signal: AbortSignal.timeout(300000), + signal: AbortSignal.timeout(600000), }); if (!response.ok) { throw new Error("Cannot fetch Wifi settings"); @@ -29,7 +29,7 @@ const updateWifiSettings = async (wifiConfig: WifiConfig) => { const getModemSettings = async () => { const response = await fetch(`${camBase}/api/fetch-config?id=ModemAndWifiManager-modem`, { - signal: AbortSignal.timeout(300000), + signal: AbortSignal.timeout(600000), }); if (!response.ok) { throw new Error("Cannot fetch modem settings"); From f35e2f9fb5b2c6d49ce1649eb82980c16a46f9b1 Mon Sep 17 00:00:00 2001 From: Toba Ojo Date: Tue, 11 Nov 2025 10:43:14 +0000 Subject: [PATCH 10/10] - added store and forward - amended sighting ammend endpoint --- .../SettingForms/SettingForms.tsx | 7 ++++- .../SettingForms/Store/StoreCard.tsx | 14 +++++++++ .../SettingForms/Store/StoreFields.tsx | 29 +++++++++++++++++++ src/hooks/useCameraOutput.ts | 2 +- src/hooks/useSightingAmend.ts | 4 +-- src/hooks/useStoreDispatch.ts | 19 ++++++++++++ 6 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 src/components/SettingForms/Store/StoreCard.tsx create mode 100644 src/components/SettingForms/Store/StoreFields.tsx create mode 100644 src/hooks/useStoreDispatch.ts diff --git a/src/components/SettingForms/SettingForms/SettingForms.tsx b/src/components/SettingForms/SettingForms/SettingForms.tsx index 858b367..42b89fd 100644 --- a/src/components/SettingForms/SettingForms/SettingForms.tsx +++ b/src/components/SettingForms/SettingForms/SettingForms.tsx @@ -13,6 +13,7 @@ import { useQueryClient } from "@tanstack/react-query"; import { useUpdateBackOfficeConfig } from "../../../hooks/useBackOfficeConfig"; import { useFormVaidate } from "../../../hooks/useFormValidate"; import { useSightingAmend } from "../../../hooks/useSightingAmend"; +import StoreCard from "../Store/StoreCard"; const SettingForms = () => { const qc = useQueryClient(); @@ -130,7 +131,11 @@ const SettingForms = () => { {({ isSubmitting, touched }) => (
- +
+ + +
+ { + return ( + + + + + ); +}; + +export default StoreCard; diff --git a/src/components/SettingForms/Store/StoreFields.tsx b/src/components/SettingForms/Store/StoreFields.tsx new file mode 100644 index 0000000..3426032 --- /dev/null +++ b/src/components/SettingForms/Store/StoreFields.tsx @@ -0,0 +1,29 @@ +import { useStoreDispatch } from "../../../hooks/useStoreDispatch"; +import VehicleSessionItem from "../../UI/VehicleSessionItem"; + +const StoreFields = () => { + const { storeQuery } = useStoreDispatch(); + + const totalPending = storeQuery?.data?.totalPending; + const totalActive = storeQuery?.data?.totalActive; + const totalSent = storeQuery?.data?.totalSent; + const totalReceived = storeQuery?.data?.totalReceived; + const totalLost = storeQuery?.data?.totalLost; + + if (storeQuery.isLoading) return
Loading store data...
; + if (storeQuery.error) return
Error: {storeQuery.error.message}
; + + return ( +
+
    + + + + + +
+
+ ); +}; + +export default StoreFields; diff --git a/src/hooks/useCameraOutput.ts b/src/hooks/useCameraOutput.ts index 641c4ac..4bdb9ca 100644 --- a/src/hooks/useCameraOutput.ts +++ b/src/hooks/useCameraOutput.ts @@ -92,7 +92,7 @@ const updateBOF2LaneId = async (data: OptionalBOF2LaneIDs) => { }; const getBOF2LaneId = async () => { - const response = await fetch(`${CAM_BASE}/api/fetch-config?id=SightingAmmend-lane-ids`); + const response = await fetch(`${CAM_BASE}/api/fetch-config?id=SightingAmmendA-lane-ids`); if (!response.ok) throw new Error("Canot get Lane Ids"); return response.json(); }; diff --git a/src/hooks/useSightingAmend.ts b/src/hooks/useSightingAmend.ts index c85a7cf..4115efa 100644 --- a/src/hooks/useSightingAmend.ts +++ b/src/hooks/useSightingAmend.ts @@ -3,14 +3,14 @@ import { CAM_BASE } from "../utils/config"; import type { InitialValuesForm } from "../types/types"; const getSightingAmend = async () => { - const response = await fetch(`${CAM_BASE}/api/fetch-config?id=SightingAmmend`); + const response = await fetch(`${CAM_BASE}/api/fetch-config?id=SightingAmmendA`); if (!response.ok) throw new Error("Cannot reach sighting amend endpoint"); return response.json(); }; const updateSightingAmend = async (data: InitialValuesForm) => { const updateSightingAmendPayload = { - id: "SightingAmmend", + id: "SightingAmmendA", fields: [ { property: "propOverviewQuality", diff --git a/src/hooks/useStoreDispatch.ts b/src/hooks/useStoreDispatch.ts new file mode 100644 index 0000000..b3c181c --- /dev/null +++ b/src/hooks/useStoreDispatch.ts @@ -0,0 +1,19 @@ +import { useQuery } from "@tanstack/react-query"; +import { CAM_BASE } from "../utils/config"; + +const getStoreData = async () => { + const response = await fetch(`${CAM_BASE}/Store/diagnostics-json`); + if (!response.ok) throw new Error("Cannot get store data"); + + return response.json(); +}; + +export const useStoreDispatch = () => { + const storeQuery = useQuery({ + queryKey: ["getStoreData"], + queryFn: getStoreData, + refetchInterval: 1000, + refetchOnWindowFocus: true, + }); + return { storeQuery }; +};