From 6f2bc96ac7cfbe38af2c4f1db8ef2b458c72d4d5 Mon Sep 17 00:00:00 2001 From: Toba Ojo Date: Wed, 1 Oct 2025 10:59:10 +0100 Subject: [PATCH 1/5] Add camera zoom functionality and refactor blackboard data fetching - Introduced `useCameraZoom` hook for managing camera zoom operations. - Refactored `useCameraBlackboard` to improve data fetching function naming. - Updated `CameraSettingFields` to utilize new zoom functionality and handle zoom level changes. - Removed unnecessary console logs from `Dashboard`. --- .../CameraSettings/CameraSettingFields.tsx | 37 ++++++++++++++++--- src/hooks/useCameraBlackboard.ts | 4 +- src/hooks/useCameraZoom.ts | 22 +++++++++++ src/pages/Dashboard.tsx | 1 - src/types/types.ts | 5 +++ 5 files changed, 60 insertions(+), 9 deletions(-) create mode 100644 src/hooks/useCameraZoom.ts diff --git a/src/components/CameraSettings/CameraSettingFields.tsx b/src/components/CameraSettings/CameraSettingFields.tsx index 90cf47b..8b5c42e 100644 --- a/src/components/CameraSettings/CameraSettingFields.tsx +++ b/src/components/CameraSettings/CameraSettingFields.tsx @@ -3,12 +3,15 @@ import type { CameraConfig, CameraSettingErrorValues, CameraSettingValues, + ZoomInOptions, ZoomLevel, } from "../../types/types"; import { useMemo, useState } from "react"; 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 { useCameraBlackboard } from "../../hooks/useCameraBlackboard"; type CameraSettingsProps = { initialData: CameraConfig; @@ -24,7 +27,9 @@ const CameraSettingFields = ({ onZoomLevelChange, }: CameraSettingsProps) => { const [showPwd, setShowPwd] = useState(false); - console.log(initialData); + const { mutation } = useCameraZoom(); + const { mutation: blackboardMuation, query: blackboardQuery } = + useCameraBlackboard(); const initialValues = useMemo( () => ({ friendlyName: initialData?.id ?? "", @@ -32,6 +37,7 @@ const CameraSettingFields = ({ userName: "", password: "", id: initialData?.id, + //TODO: update zoomlevel to query data zoom: zoomLevel?.level ? zoomLevel.level : 1, }), [initialData?.id, initialData?.propURI?.value, zoomLevel?.level] @@ -41,23 +47,42 @@ const CameraSettingFields = ({ const errors: CameraSettingErrorValues = {}; if (!values.friendlyName) errors.friendlyName = "Required"; if (!values.cameraAddress) errors.cameraAddress = "Required"; - if (!values.userName) errors.userName = "Required"; - if (!values.password) errors.password = "Required"; - return errors; }; const handleSubmit = (values: CameraSettingValues) => { - console.log(values); updateCameraConfig(values); }; - const handleRadioButtonChange = (levelNumber: number) => { + const handleRadioButtonChange = async (levelNumber: number) => { if (!onZoomLevelChange || !zoomLevel) return; onZoomLevelChange({ ...zoomLevel, level: zoomLevel?.level !== levelNumber ? levelNumber : zoomLevel?.level, }); + const cameraControllerSide = + initialData?.id === "CameraA" ? "CameraControllerA" : "CameraControllerB"; + + const zoomInOptions: ZoomInOptions = { + camera: cameraControllerSide, + multiplier: levelNumber, + }; + + mutation.mutate(zoomInOptions); + + if (!blackboardQuery.data.cameraZoom) { + blackboardMuation.mutate({ + operation: "INSERT", + path: "cameraZoom", + value: zoomInOptions, + }); + } else { + blackboardMuation.mutate({ + operation: "APPEND", + path: "cameraZoom", + value: zoomInOptions, + }); + } }; return ( diff --git a/src/hooks/useCameraBlackboard.ts b/src/hooks/useCameraBlackboard.ts index d8cd31b..81c16a8 100644 --- a/src/hooks/useCameraBlackboard.ts +++ b/src/hooks/useCameraBlackboard.ts @@ -2,7 +2,7 @@ import { useMutation, useQuery } from "@tanstack/react-query"; import { CAM_BASE } from "../utils/config"; import type { CameraBlackBoardOptions } from "../types/types"; -const getBlackboardData = async () => { +const getAllBlackboardData = async () => { const response = await fetch(`${CAM_BASE}/api/blackboard`); if (!response.ok) { throw new Error("Failed to fetch blackboard data"); @@ -25,7 +25,7 @@ const viewBlackboardData = async (options: CameraBlackBoardOptions) => { export const useCameraBlackboard = () => { const query = useQuery({ queryKey: ["cameraBlackboard"], - queryFn: getBlackboardData, + queryFn: getAllBlackboardData, }); const mutation = useMutation({ diff --git a/src/hooks/useCameraZoom.ts b/src/hooks/useCameraZoom.ts new file mode 100644 index 0000000..474c29e --- /dev/null +++ b/src/hooks/useCameraZoom.ts @@ -0,0 +1,22 @@ +import { useMutation } from "@tanstack/react-query"; +import { CAM_BASE } from "../utils/config"; +import type { ZoomInOptions } from "../types/types"; + +async function zoomIn(options: ZoomInOptions) { + const response = await fetch( + `${CAM_BASE}/Ip${options.camera}-command?magnification=${options.multiplier}x` + ); + if (!response.ok) { + throw new Error("Cannot reach camera zoom endpoint"); + } + return; +} + +export const useCameraZoom = () => { + const mutation = useMutation({ + mutationKey: ["zoomIn"], + mutationFn: (options: ZoomInOptions) => zoomIn(options), + }); + + return { mutation }; +}; diff --git a/src/pages/Dashboard.tsx b/src/pages/Dashboard.tsx index b46ffe1..fb0182a 100644 --- a/src/pages/Dashboard.tsx +++ b/src/pages/Dashboard.tsx @@ -7,7 +7,6 @@ const Dashboard = () => { const mode = import.meta.env.MODE; const base_url = `${CAM_BASE}/SightingList/sightingSummary?mostRecentRef=`; console.log(mode); - console.log(base_url); return (
diff --git a/src/types/types.ts b/src/types/types.ts index e70d706..55e2d88 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -261,3 +261,8 @@ export type ZoomLevel = { py: number; level?: number; }; + +export type ZoomInOptions = { + camera: string; + multiplier: number; +}; From 4eeb3684847526ae967924a1b3af08f1d40a1fb5 Mon Sep 17 00:00:00 2001 From: Toba Ojo Date: Wed, 1 Oct 2025 11:30:06 +0100 Subject: [PATCH 2/5] Refactor SnapshotContainer to integrate camera zoom functionality and improve error handling --- .../CameraOverview/SnapshotContainer.tsx | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/components/CameraOverview/SnapshotContainer.tsx b/src/components/CameraOverview/SnapshotContainer.tsx index 5e1698f..7d85dad 100644 --- a/src/components/CameraOverview/SnapshotContainer.tsx +++ b/src/components/CameraOverview/SnapshotContainer.tsx @@ -1,6 +1,8 @@ import { useGetOverviewSnapshot } from "../../hooks/useGetOverviewSnapshot"; -import type { ZoomLevel } from "../../types/types"; +import type { ZoomInOptions, ZoomLevel } from "../../types/types"; import NavigationArrow from "../UI/NavigationArrow"; +import { useCameraZoom } from "../../hooks/useCameraZoom"; +import { useEffect } from "react"; type SnapshotContainerProps = { side: string; @@ -16,8 +18,9 @@ export const SnapshotContainer = ({ onZoomLevelChange, }: SnapshotContainerProps) => { const { canvasRef, isError, isPending } = useGetOverviewSnapshot(side); - if (isError) return

An error occurred

; - if (isPending) return

Loading...

; + const { mutation } = useCameraZoom(); + const cameraControllerSide = + side === "CameraA" ? "CameraControllerA" : "CameraControllerB"; const handleZoomClick = (event: React.MouseEvent) => { const bounds = canvasRef.current?.getBoundingClientRect(); @@ -45,8 +48,24 @@ export const SnapshotContainer = ({ py, level: newLevel, }); + + if (!zoomLevel?.level) return; }; + useEffect(() => { + if (zoomLevel?.level) { + const zoomInOptions: ZoomInOptions = { + camera: cameraControllerSide, + multiplier: zoomLevel.level, + }; + mutation.mutate(zoomInOptions); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [zoomLevel?.level]); + + if (isError) return

An error occurred

; + if (isPending) return

Loading...

; + return (
From 82ef562046c9ca226725d52f2cfe54a5e7d094e8 Mon Sep 17 00:00:00 2001 From: Toba Ojo Date: Thu, 2 Oct 2025 16:07:05 +0100 Subject: [PATCH 3/5] camera zoom handling across components; unify zoom level type and improve state management --- .../CameraOverview/SnapshotContainer.tsx | 43 ++--- .../CameraSettings/CameraSettingFields.tsx | 168 +++++++----------- .../CameraSettings/CameraSettings.tsx | 6 +- .../OverviewVideoContainer.tsx | 5 +- src/hooks/useCameraZoom.ts | 30 +++- src/pages/FrontCamera.tsx | 11 +- src/types/types.ts | 4 + 7 files changed, 111 insertions(+), 156 deletions(-) diff --git a/src/components/CameraOverview/SnapshotContainer.tsx b/src/components/CameraOverview/SnapshotContainer.tsx index 7d85dad..c7a26b9 100644 --- a/src/components/CameraOverview/SnapshotContainer.tsx +++ b/src/components/CameraOverview/SnapshotContainer.tsx @@ -1,5 +1,5 @@ import { useGetOverviewSnapshot } from "../../hooks/useGetOverviewSnapshot"; -import type { ZoomInOptions, ZoomLevel } from "../../types/types"; +import type { ZoomInOptions } from "../../types/types"; import NavigationArrow from "../UI/NavigationArrow"; import { useCameraZoom } from "../../hooks/useCameraZoom"; import { useEffect } from "react"; @@ -7,8 +7,8 @@ import { useEffect } from "react"; type SnapshotContainerProps = { side: string; settingsPage?: boolean; - zoomLevel?: ZoomLevel; - onZoomLevelChange?: (level: ZoomLevel) => void; + zoomLevel?: number; + onZoomLevelChange?: (level: number) => void; }; export const SnapshotContainer = ({ @@ -18,50 +18,29 @@ export const SnapshotContainer = ({ onZoomLevelChange, }: SnapshotContainerProps) => { const { canvasRef, isError, isPending } = useGetOverviewSnapshot(side); - const { mutation } = useCameraZoom(); const cameraControllerSide = side === "CameraA" ? "CameraControllerA" : "CameraControllerB"; + const { mutation } = useCameraZoom({ camera: cameraControllerSide }); - const handleZoomClick = (event: React.MouseEvent) => { - const bounds = canvasRef.current?.getBoundingClientRect(); - if (!bounds) return; - const left = bounds.left; - const top = bounds.top; - const x = event.pageX; - const y = event.pageY; - const cw = canvasRef.current?.clientWidth; - const ch = canvasRef.current?.clientHeight; - if (!cw || !ch) return; - const px = x / cw; - const py = y / ch; - - const baseLevel = zoomLevel?.level ?? 1; + const handleZoomClick = () => { + const baseLevel = zoomLevel ?? 1; const newLevel = baseLevel >= 8 ? 1 : baseLevel * 2; - if (onZoomLevelChange) - onZoomLevelChange({ - left, - top, - x, - y, - px, - py, - level: newLevel, - }); + if (onZoomLevelChange) onZoomLevelChange(newLevel); - if (!zoomLevel?.level) return; + if (!zoomLevel) return; }; useEffect(() => { - if (zoomLevel?.level) { + if (zoomLevel) { const zoomInOptions: ZoomInOptions = { camera: cameraControllerSide, - multiplier: zoomLevel.level, + multiplier: zoomLevel, }; mutation.mutate(zoomInOptions); } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [zoomLevel?.level]); + }, [zoomLevel]); if (isError) return

An error occurred

; if (isPending) return

Loading...

; diff --git a/src/components/CameraSettings/CameraSettingFields.tsx b/src/components/CameraSettings/CameraSettingFields.tsx index 8b5c42e..d530db3 100644 --- a/src/components/CameraSettings/CameraSettingFields.tsx +++ b/src/components/CameraSettings/CameraSettingFields.tsx @@ -4,20 +4,18 @@ import type { CameraSettingErrorValues, CameraSettingValues, ZoomInOptions, - ZoomLevel, } from "../../types/types"; -import { useMemo, useState } from "react"; +import { useEffect, useMemo, useState } from "react"; 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 { useCameraBlackboard } from "../../hooks/useCameraBlackboard"; type CameraSettingsProps = { initialData: CameraConfig; updateCameraConfig: (values: CameraSettingValues) => Promise | void; - zoomLevel?: ZoomLevel; - onZoomLevelChange?: (level: ZoomLevel) => void; + zoomLevel?: number; + onZoomLevelChange?: (level: number) => void; }; const CameraSettingFields = ({ @@ -27,9 +25,38 @@ const CameraSettingFields = ({ onZoomLevelChange, }: CameraSettingsProps) => { const [showPwd, setShowPwd] = useState(false); - const { mutation } = useCameraZoom(); - const { mutation: blackboardMuation, query: blackboardQuery } = - useCameraBlackboard(); + const cameraControllerSide = + initialData?.id === "CameraA" ? "CameraControllerA" : "CameraControllerB"; + const { mutation, query } = useCameraZoom({ camera: cameraControllerSide }); + const zoomOptions = [1, 2, 4, 8]; + + useEffect(() => { + if (!query.data) return; + const apiZoom = getZoomLevel(query.data); + onZoomLevelChange?.(apiZoom); + }, [query.data, onZoomLevelChange]); + + const getZoomLevel = (levelstring: string | undefined) => { + switch (levelstring) { + case "1x": + return 1; + break; + case "2x": + return 2; + break; + case "4x": + return 4; + break; + case "8x": + return 8; + default: + return 1; + } + }; + const level = getZoomLevel(query.data); + + console.log("level from get", level); + console.log("zoomLevel state", zoomLevel); const initialValues = useMemo( () => ({ friendlyName: initialData?.id ?? "", @@ -37,10 +64,10 @@ const CameraSettingFields = ({ userName: "", password: "", id: initialData?.id, - //TODO: update zoomlevel to query data - zoom: zoomLevel?.level ? zoomLevel.level : 1, + + zoom: zoomLevel, }), - [initialData?.id, initialData?.propURI?.value, zoomLevel?.level] + [initialData?.id, initialData?.propURI?.value, zoomLevel] ); const validateValues = (values: CameraSettingValues) => { @@ -56,12 +83,7 @@ const CameraSettingFields = ({ const handleRadioButtonChange = async (levelNumber: number) => { if (!onZoomLevelChange || !zoomLevel) return; - onZoomLevelChange({ - ...zoomLevel, - level: zoomLevel?.level !== levelNumber ? levelNumber : zoomLevel?.level, - }); - const cameraControllerSide = - initialData?.id === "CameraA" ? "CameraControllerA" : "CameraControllerB"; + onZoomLevelChange(levelNumber); const zoomInOptions: ZoomInOptions = { camera: cameraControllerSide, @@ -69,28 +91,16 @@ const CameraSettingFields = ({ }; mutation.mutate(zoomInOptions); - - if (!blackboardQuery.data.cameraZoom) { - blackboardMuation.mutate({ - operation: "INSERT", - path: "cameraZoom", - value: zoomInOptions, - }); - } else { - blackboardMuation.mutate({ - operation: "APPEND", - path: "cameraZoom", - value: zoomInOptions, - }); - } }; - + const selectedZoom = zoomLevel ?? 1; + console.log(selectedZoom); return ( {({ errors, touched }) => (
@@ -169,78 +179,28 @@ const CameraSettingFields = ({
-
-
- handleRadioButtonChange(1)} - /> - -
- -
- handleRadioButtonChange(2)} - /> - -
- -
- handleRadioButtonChange(4)} - /> - -
- -
- handleRadioButtonChange(8)} - /> - -
+
+ {zoomOptions.map((zoom) => ( +
+ handleRadioButtonChange(zoom)} + /> + +
+ ))}
-
+ ); }; diff --git a/src/components/SettingForms/WiFi&Modem/WiFiSettingsForm.tsx b/src/components/SettingForms/WiFi&Modem/WiFiSettingsForm.tsx new file mode 100644 index 0000000..3f81cd0 --- /dev/null +++ b/src/components/SettingForms/WiFi&Modem/WiFiSettingsForm.tsx @@ -0,0 +1,106 @@ +import { Field, Form, Formik } from "formik"; +import FormGroup from "../components/FormGroup"; +import type { WifiSettingValues } from "../../../types/types"; +import { useWifiAndModem } from "../../../hooks/useCameraWifiandModem"; +import { toast } from "sonner"; + +const WiFiSettingsForm = () => { + const { wifiQuery, wifiMutation } = useWifiAndModem(); + + const wifiSSID = wifiQuery?.data?.propSSID?.value; + const wifiPassword = wifiQuery?.data?.propPassword?.value; + + const initialValues = { + ssid: wifiSSID ?? "", + password: wifiPassword ?? "", + encryption: "WPA2", + }; + + const handleSubmit = (values: WifiSettingValues) => { + const wifiConfig = { + id: "ModemAndWifiManager-wifi", + configHash: "206890572", + propSSID: { + value: values.ssid, + datatype: "java.lang.String", + }, + propPassword: { + value: values.password, + datatype: "java.lang.String", + }, + }; + + wifiMutation.mutate(wifiConfig); + //todo: check what response is + toast.success("WiFi settings updated"); + }; + return ( + + {() => ( + + + + + + + + + + + + + + + + + + + + + )} + + ); +}; + +export default WiFiSettingsForm; diff --git a/src/hooks/useCameraWifiandModem.ts b/src/hooks/useCameraWifiandModem.ts new file mode 100644 index 0000000..e256080 --- /dev/null +++ b/src/hooks/useCameraWifiandModem.ts @@ -0,0 +1,45 @@ +import { useQuery, useMutation } from "@tanstack/react-query"; +import { CAM_BASE } from "../utils/config"; +import type { WifiConfig } from "../types/types"; + +const getWiFiSettings = async () => { + const response = await fetch( + `${CAM_BASE}/api/fetch-config?id=ModemAndWifiManager-wifi` + ); + if (!response.ok) { + throw new Error("Cannot fetch Wifi settings"); + } + return response.json(); +}; + +const updateWifiSettings = async (wifiConfig: WifiConfig) => { + const response = await fetch( + `${CAM_BASE}/api/update-config?id=ModemAndWifiManager-wifi`, + { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(wifiConfig), + } + ); + if (!response.ok) { + throw new Error("Cannot update wifi settings"); + } + return response.json(); +}; + +export const useWifiAndModem = () => { + const wifiQuery = useQuery({ + queryKey: ["getWifiSettings"], + queryFn: getWiFiSettings, + }); + + const wifiMutation = useMutation({ + mutationKey: ["updateWifiSettings"], + mutationFn: (wifiConfig: WifiConfig) => updateWifiSettings(wifiConfig), + }); + + return { + wifiQuery, + wifiMutation, + }; +}; diff --git a/src/types/types.ts b/src/types/types.ts index e70d706..cbe327b 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -261,3 +261,22 @@ export type ZoomLevel = { py: number; level?: number; }; + +export type WifiSettingValues = { + ssid: string; + password: string; + encryption: string; +}; + +export type WifiConfig = { + id: string; + configHash: string; + propSSID: { + value: string; + datatype: string; + }; + propPassword: { + value: string; + datatype: string; + }; +}; diff --git a/src/utils/config.ts b/src/utils/config.ts index f403ad1..3cd72f3 100644 --- a/src/utils/config.ts +++ b/src/utils/config.ts @@ -1,4 +1,4 @@ -const rawCamBase = import.meta.env.VITE_OUTSIDE_BASEURL; +const rawCamBase = import.meta.env.VITE_CAM_BASE; export const CAM_BASE = rawCamBase && rawCamBase.trim().length > 0 ? rawCamBase From a972234e226bce224c856662152dc941b427e6b1 Mon Sep 17 00:00:00 2001 From: Toba Ojo Date: Fri, 3 Oct 2025 10:19:49 +0100 Subject: [PATCH 5/5] modem settings management: integrate ModemSettings and ModemToggle components, update hooks for modem configuration, and enhance WiFiSettingsForm submission handling. --- .../SettingForms/WiFi&Modem/ModemCard.tsx | 89 +---------- .../SettingForms/WiFi&Modem/ModemSettings.tsx | 148 ++++++++++++++++++ .../SettingForms/WiFi&Modem/ModemToggle.tsx | 30 ++++ .../WiFi&Modem/WiFiSettingsForm.tsx | 23 +-- src/components/UI/Header.tsx | 2 +- src/hooks/useCameraWifiandModem.ts | 40 ++++- src/types/types.ts | 31 ++-- 7 files changed, 257 insertions(+), 106 deletions(-) create mode 100644 src/components/SettingForms/WiFi&Modem/ModemSettings.tsx create mode 100644 src/components/SettingForms/WiFi&Modem/ModemToggle.tsx diff --git a/src/components/SettingForms/WiFi&Modem/ModemCard.tsx b/src/components/SettingForms/WiFi&Modem/ModemCard.tsx index 79bcc52..dcc2dfc 100644 --- a/src/components/SettingForms/WiFi&Modem/ModemCard.tsx +++ b/src/components/SettingForms/WiFi&Modem/ModemCard.tsx @@ -1,96 +1,13 @@ import Card from "../../UI/Card"; import CardHeader from "../../UI/CardHeader"; -import { useState } from "react"; -import FormGroup from "../components/FormGroup"; +import ModemSettings from "./ModemSettings"; const ModemCard = () => { - const [apn, setApn] = useState(""); - const [username, setUsername] = useState(""); - const [password, setPassword] = useState(""); - const [authType, setAuthType] = useState("PAP"); - return ( - // TODO: Add switch for Auto vs Manual settings -
- - - setApn(e.target.value)} - /> - - - - setUsername(e.target.value)} - /> - - - - setPassword(e.target.value)} - /> - - - - - - -
+ +
); }; diff --git a/src/components/SettingForms/WiFi&Modem/ModemSettings.tsx b/src/components/SettingForms/WiFi&Modem/ModemSettings.tsx new file mode 100644 index 0000000..ccf6402 --- /dev/null +++ b/src/components/SettingForms/WiFi&Modem/ModemSettings.tsx @@ -0,0 +1,148 @@ +import { Formik, Form, Field } from "formik"; +import FormGroup from "../components/FormGroup"; +import type { ModemSettingsType } from "../../../types/types"; +import { useWifiAndModem } from "../../../hooks/useCameraWifiandModem"; +import { useEffect, useState } from "react"; +import ModemToggle from "./ModemToggle"; +import { toast } from "sonner"; + +const ModemSettings = () => { + const [showSettings, setShowSettings] = useState(false); + const { modemQuery, modemMutation } = useWifiAndModem(); + + const apn = modemQuery?.data?.propAPN?.value; + const username = modemQuery?.data?.propUsername.value; + const password = modemQuery?.data?.propPassword?.value; + const mode = modemQuery?.data?.propMode?.value; + + useEffect(() => { + setShowSettings(mode === "AUTO"); + }, [mode]); + + const inititalValues = { + apn: apn ?? "", + username: username ?? "", + password: password ?? "", + authenticationType: "PAP", + }; + + const handleSubmit = (values: ModemSettingsType) => { + const modemConfig = { + id: "ModemAndWifiManager-modem", + fields: [ + { + property: "propAPN", + value: values.apn, + }, + { + property: "propPassword", + value: values.password, + }, + { + property: "propUsername", + value: values.username, + }, + + { + property: "propMode", + value: showSettings ? "AUTO" : "MANUAL", + }, + ], + }; + modemMutation.mutate(modemConfig); + if (modemMutation.error) { + toast.error("Failed to update modem settings"); + return; + } + toast.success("Modem settings updated"); + }; + + return ( + <> + + {!showSettings && ( + +
+ + + + + + + + + + + + + + + + + + + + + +
+
+ )} + + ); +}; + +export default ModemSettings; diff --git a/src/components/SettingForms/WiFi&Modem/ModemToggle.tsx b/src/components/SettingForms/WiFi&Modem/ModemToggle.tsx new file mode 100644 index 0000000..dab4f41 --- /dev/null +++ b/src/components/SettingForms/WiFi&Modem/ModemToggle.tsx @@ -0,0 +1,30 @@ +type ModemToggleProps = { + showSettings: boolean; + onShowSettings: (showSettings: boolean) => void; +}; + +const ModemToggle = ({ showSettings, onShowSettings }: ModemToggleProps) => { + return ( +
+ +
+ ); +}; + +export default ModemToggle; diff --git a/src/components/SettingForms/WiFi&Modem/WiFiSettingsForm.tsx b/src/components/SettingForms/WiFi&Modem/WiFiSettingsForm.tsx index 3f81cd0..6d1588b 100644 --- a/src/components/SettingForms/WiFi&Modem/WiFiSettingsForm.tsx +++ b/src/components/SettingForms/WiFi&Modem/WiFiSettingsForm.tsx @@ -19,19 +19,24 @@ const WiFiSettingsForm = () => { const handleSubmit = (values: WifiSettingValues) => { const wifiConfig = { id: "ModemAndWifiManager-wifi", - configHash: "206890572", - propSSID: { - value: values.ssid, - datatype: "java.lang.String", - }, - propPassword: { - value: values.password, - datatype: "java.lang.String", - }, + fields: [ + { + property: "propSSID", + value: values.ssid, + }, + { + property: "propPassword", + value: values.password, + }, + ], }; wifiMutation.mutate(wifiConfig); //todo: check what response is + if (wifiMutation.error) { + toast.error("Failed to update WiFi settings"); + return; + } toast.success("WiFi settings updated"); }; return ( diff --git a/src/components/UI/Header.tsx b/src/components/UI/Header.tsx index 2de4734..daceab3 100644 --- a/src/components/UI/Header.tsx +++ b/src/components/UI/Header.tsx @@ -32,7 +32,7 @@ export default function Header() { }; return ( -
+
Logo diff --git a/src/hooks/useCameraWifiandModem.ts b/src/hooks/useCameraWifiandModem.ts index e256080..d501a6b 100644 --- a/src/hooks/useCameraWifiandModem.ts +++ b/src/hooks/useCameraWifiandModem.ts @@ -1,6 +1,6 @@ import { useQuery, useMutation } from "@tanstack/react-query"; import { CAM_BASE } from "../utils/config"; -import type { WifiConfig } from "../types/types"; +import type { ModemConfig, WifiConfig } from "../types/types"; const getWiFiSettings = async () => { const response = await fetch( @@ -27,6 +27,31 @@ const updateWifiSettings = async (wifiConfig: WifiConfig) => { return response.json(); }; +const getModemSettings = async () => { + const response = await fetch( + `${CAM_BASE}/api/fetch-config?id=ModemAndWifiManager-modem` + ); + if (!response.ok) { + throw new Error("Cannot fetch modem settings"); + } + return response.json(); +}; + +const updateModemSettings = async (modemConfig: ModemConfig) => { + const response = await fetch( + `${CAM_BASE}/api/update-config?id=ModemAndWifiManager-modem`, + { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(modemConfig), + } + ); + if (!response.ok) { + throw new Error("cannot update modem settings"); + } + return response.json(); +}; + export const useWifiAndModem = () => { const wifiQuery = useQuery({ queryKey: ["getWifiSettings"], @@ -36,10 +61,23 @@ export const useWifiAndModem = () => { const wifiMutation = useMutation({ mutationKey: ["updateWifiSettings"], mutationFn: (wifiConfig: WifiConfig) => updateWifiSettings(wifiConfig), + onError: (error) => console.log(error), + }); + + const modemQuery = useQuery({ + queryKey: ["getModemSettings"], + queryFn: getModemSettings, + }); + + const modemMutation = useMutation({ + mutationKey: ["updateModemSettings"], + mutationFn: (modemConfig: ModemConfig) => updateModemSettings(modemConfig), }); return { wifiQuery, wifiMutation, + modemQuery, + modemMutation, }; }; diff --git a/src/types/types.ts b/src/types/types.ts index 4add9a4..234d015 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -267,19 +267,25 @@ export type WifiSettingValues = { password: string; encryption: string; }; +export type ModemConfigPayload = { + property: string; + value: string; +}; +export type WifiConfigPayload = { + property: string; + value: string; +}; export type WifiConfig = { id: string; - configHash: string; - propSSID: { - value: string; - datatype: string; - }; - propPassword: { - value: string; - datatype: string; - }; + fields: WifiConfigPayload[]; }; + +export type ModemConfig = { + id: string; + fields: ModemConfigPayload[]; +}; + export type ZoomInOptions = { camera: string; multiplier: number; @@ -288,3 +294,10 @@ export type ZoomInOptions = { export type zoomConfig = { camera: string; }; + +export type ModemSettingsType = { + apn: string; + username: string; + password: string; + authenticationType: string; +};