From f275f50383408347f13da043d09e9f179a4d0ba1 Mon Sep 17 00:00:00 2001 From: Toba Ojo Date: Mon, 6 Oct 2025 14:21:56 +0100 Subject: [PATCH 1/2] Updated loading states and error states accross app --- .../CameraOverview/SnapshotContainer.tsx | 11 +- .../CameraSettings/CameraSettingFields.tsx | 37 ++-- .../CameraSettings/CameraSettings.tsx | 12 +- src/components/HistoryList/AlertItem.tsx | 3 +- .../SettingForms/NPED/NPEDFields.tsx | 1 - .../SettingForms/System/SettingSaveRecall.tsx | 16 +- .../System/SystemConfigFields.tsx | 8 +- .../SettingForms/WiFi&Modem/ModemSettings.tsx | 6 - .../WiFi&Modem/WiFiSettingsForm.tsx | 7 - .../SightingOverview/SightingOverview.tsx | 20 ++- .../SightingsWidget/SightingWidget.tsx | 8 + src/components/UI/ErrorState.tsx | 162 ++++++++++++++++++ src/components/UI/Loading.tsx | 14 ++ src/context/providers/AlertHitProvider.tsx | 4 - src/hooks/useCameraBlackboard.ts | 13 +- src/hooks/useCameraConfig.ts | 7 +- src/hooks/useCameraWifiandModem.ts | 34 +++- src/hooks/useCameraZoom.ts | 9 +- src/hooks/useGetOverviewSnapshot.ts | 12 +- src/hooks/useNPEDAuth.ts | 77 ++++++--- src/hooks/useSightingFeed.ts | 4 +- src/hooks/useSystemConfig.ts | 5 +- src/pages/Dashboard.tsx | 4 +- src/pages/Session.tsx | 2 + src/utils/utils.ts | 2 +- 25 files changed, 377 insertions(+), 101 deletions(-) create mode 100644 src/components/UI/ErrorState.tsx create mode 100644 src/components/UI/Loading.tsx diff --git a/src/components/CameraOverview/SnapshotContainer.tsx b/src/components/CameraOverview/SnapshotContainer.tsx index c7a26b9..87cb48f 100644 --- a/src/components/CameraOverview/SnapshotContainer.tsx +++ b/src/components/CameraOverview/SnapshotContainer.tsx @@ -3,6 +3,8 @@ 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"; type SnapshotContainerProps = { side: string; @@ -42,13 +44,16 @@ export const SnapshotContainer = ({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [zoomLevel]); - if (isError) return

An error occurred

; - if (isPending) return

Loading...

; - return (
+ {isError && } + {isPending && ( +
+ +
+ )} Promise | void; zoomLevel?: number; onZoomLevelChange?: (level: number) => void; + updateCameraConfigError: null | Error; }; const CameraSettingFields = ({ @@ -24,6 +25,7 @@ const CameraSettingFields = ({ updateCameraConfig, zoomLevel, onZoomLevelChange, + updateCameraConfigError, }: CameraSettingsProps) => { const [showPwd, setShowPwd] = useState(false); const cameraControllerSide = @@ -43,23 +45,20 @@ const CameraSettingFields = ({ 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 ?? "", @@ -70,6 +69,7 @@ const CameraSettingFields = ({ zoom: zoomLevel, }), + // eslint-disable-next-line react-hooks/exhaustive-deps [initialData?.id, initialData?.propURI?.value, zoomLevel] ); @@ -96,7 +96,6 @@ const CameraSettingFields = ({ mutation.mutate(zoomInOptions); }; const selectedZoom = zoomLevel ?? 1; - console.log(selectedZoom); return ( - {({ errors, touched }) => ( + {({ errors, touched, isSubmitting }) => (
@@ -184,7 +183,7 @@ const CameraSettingFields = ({
{zoomOptions.map((zoom) => ( -
+
- +
+ {updateCameraConfigError ? ( + + ) : ( + + )} +
)} diff --git a/src/components/CameraSettings/CameraSettings.tsx b/src/components/CameraSettings/CameraSettings.tsx index de79feb..2a0a68e 100644 --- a/src/components/CameraSettings/CameraSettings.tsx +++ b/src/components/CameraSettings/CameraSettings.tsx @@ -1,5 +1,4 @@ import { useFetchCameraConfig } from "../../hooks/useCameraConfig"; - import Card from "../UI/Card"; import CardHeader from "../UI/CardHeader"; import CameraSettingFields from "./CameraSettingFields"; @@ -16,22 +15,23 @@ const CameraSettings = ({ zoomLevel?: number; onZoomLevelChange?: (level: number) => void; }) => { - const { data, isError, isPending, updateCameraConfig } = + const { data, updateCameraConfig, updateCameraConfigError } = useFetchCameraConfig(side); + console.log(updateCameraConfigError); return ( - {isPending && <>Loading camera config} - {isError && <>Error fetching camera config}
- {!isPending && ( + + { - )} + }
); diff --git a/src/components/HistoryList/AlertItem.tsx b/src/components/HistoryList/AlertItem.tsx index ccdcb26..89838a2 100644 --- a/src/components/HistoryList/AlertItem.tsx +++ b/src/components/HistoryList/AlertItem.tsx @@ -15,7 +15,7 @@ type AlertItemProps = { const AlertItem = ({ item }: AlertItemProps) => { const [isModalOpen, setIsModalOpen] = useState(false); - const { dispatch } = useAlertHitContext(); + const { dispatch, isError } = useAlertHitContext(); // const {d} = useCameraBlackboard(); const motionAway = (item?.motion ?? "").toUpperCase() === "AWAY"; @@ -24,6 +24,7 @@ const AlertItem = ({ item }: AlertItemProps) => { const isNPEDHitB = item?.metadata?.npedJSON?.["NPED CATEGORY"] === "B"; const isNPEDHitC = item?.metadata?.npedJSON?.["NPED CATEGORY"] === "C"; + console.log(isError); const handleClick = () => { setIsModalOpen(true); }; diff --git a/src/components/SettingForms/NPED/NPEDFields.tsx b/src/components/SettingForms/NPED/NPEDFields.tsx index 0288916..6485a36 100644 --- a/src/components/SettingForms/NPED/NPEDFields.tsx +++ b/src/components/SettingForms/NPED/NPEDFields.tsx @@ -32,7 +32,6 @@ const NPEDFields = () => { ...values, }; signIn(valuesToSend); - toast.success("Signed into NPED Successfully"); }; const validateValues = (values: NPEDFieldType) => { diff --git a/src/components/SettingForms/System/SettingSaveRecall.tsx b/src/components/SettingForms/System/SettingSaveRecall.tsx index 83511b9..8d9b3e7 100644 --- a/src/components/SettingForms/System/SettingSaveRecall.tsx +++ b/src/components/SettingForms/System/SettingSaveRecall.tsx @@ -1,3 +1,4 @@ +import { toast } from "sonner"; import type { SystemValues } from "../../../types/types"; import { CAM_BASE } from "../../../utils/config"; @@ -35,7 +36,13 @@ export async function handleSystemSave(values: SystemValues) { ); } } catch (err) { - console.error(err); + if (err instanceof Error) { + toast.error(`Failed to save system settings: ${err.message}`); + console.error(err); + } else { + toast.error("An unexpected error occurred while saving."); + console.error("Unknown error:", err); + } } } @@ -79,7 +86,12 @@ export async function handleSystemRecall() { return { deviceName, sntpServer, sntpInterval, timeZone }; } catch (err) { - console.error(err); + if (err instanceof Error) { + toast.error(`Error: ${err.message}`); + } else { + toast.error("An unexpected error occurred"); + } + return null; } finally { clearTimeout(timeoutId); diff --git a/src/components/SettingForms/System/SystemConfigFields.tsx b/src/components/SettingForms/System/SystemConfigFields.tsx index cdc3f2e..a542212 100644 --- a/src/components/SettingForms/System/SystemConfigFields.tsx +++ b/src/components/SettingForms/System/SystemConfigFields.tsx @@ -7,7 +7,8 @@ import type { SystemValues, SystemValuesErrors } from "../../../types/types"; import { useSystemConfig } from "../../../hooks/useSystemConfig"; const SystemConfigFields = () => { - const { saveSystemSettings, systemSettingsData } = useSystemConfig(); + const { saveSystemSettings, systemSettingsData, saveSystemSettingsLoading } = + useSystemConfig(); const initialvalues: SystemValues = { deviceName: systemSettingsData?.deviceName ?? "", timeZone: systemSettingsData?.timeZone ?? "", @@ -37,7 +38,7 @@ const SystemConfigFields = () => { validateOnChange validateOnBlur > - {({ values, errors, touched }) => ( + {({ values, errors, touched, isSubmitting }) => (