more enhancements to loading and error feedback
This commit is contained in:
@@ -27,11 +27,11 @@ const NPEDFields = () => {
|
|||||||
rearId: "NPED",
|
rearId: "NPED",
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmit = (values: NPEDFieldType) => {
|
const handleSubmit = async (values: NPEDFieldType) => {
|
||||||
const valuesToSend = {
|
const valuesToSend = {
|
||||||
...values,
|
...values,
|
||||||
};
|
};
|
||||||
signIn(valuesToSend);
|
await signIn(valuesToSend);
|
||||||
};
|
};
|
||||||
|
|
||||||
const validateValues = (values: NPEDFieldType) => {
|
const validateValues = (values: NPEDFieldType) => {
|
||||||
@@ -54,7 +54,7 @@ const NPEDFields = () => {
|
|||||||
validate={validateValues}
|
validate={validateValues}
|
||||||
enableReinitialize
|
enableReinitialize
|
||||||
>
|
>
|
||||||
{({ errors, touched }) => (
|
{({ errors, touched, isSubmitting }) => (
|
||||||
<Form className="flex flex-col space-y-5 px-2">
|
<Form className="flex flex-col space-y-5 px-2">
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<label htmlFor="username">Username</label>
|
<label htmlFor="username">Username</label>
|
||||||
@@ -112,7 +112,7 @@ const NPEDFields = () => {
|
|||||||
type="submit"
|
type="submit"
|
||||||
className="w-1/4 text-white bg-green-700 hover:bg-green-800 font-small rounded-lg text-sm px-2 py-2.5 hover:cursor-pointer"
|
className="w-1/4 text-white bg-green-700 hover:bg-green-800 font-small rounded-lg text-sm px-2 py-2.5 hover:cursor-pointer"
|
||||||
>
|
>
|
||||||
Login
|
{isSubmitting ? "Logging in..." : "Login"}
|
||||||
</button>
|
</button>
|
||||||
) : (
|
) : (
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ const ModemSettings = () => {
|
|||||||
authenticationType: "PAP",
|
authenticationType: "PAP",
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmit = (values: ModemSettingsType) => {
|
const handleSubmit = async (values: ModemSettingsType) => {
|
||||||
const modemConfig = {
|
const modemConfig = {
|
||||||
id: "ModemAndWifiManager-modem",
|
id: "ModemAndWifiManager-modem",
|
||||||
fields: [
|
fields: [
|
||||||
@@ -48,7 +48,7 @@ const ModemSettings = () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
modemMutation.mutate(modemConfig);
|
await modemMutation.mutateAsync(modemConfig);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -63,76 +63,80 @@ const ModemSettings = () => {
|
|||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
enableReinitialize
|
enableReinitialize
|
||||||
>
|
>
|
||||||
<Form className="flex flex-col space-y-5 px-2">
|
{({ isSubmitting }) => (
|
||||||
<FormGroup>
|
<Form className="flex flex-col space-y-5 px-2">
|
||||||
<label
|
<FormGroup>
|
||||||
htmlFor="apn"
|
<label
|
||||||
className="font-medium whitespace-nowrap md:w-2/3"
|
htmlFor="apn"
|
||||||
|
className="font-medium whitespace-nowrap md:w-2/3"
|
||||||
|
>
|
||||||
|
APN
|
||||||
|
</label>
|
||||||
|
<Field
|
||||||
|
placeholder="Enter APN"
|
||||||
|
name="apn"
|
||||||
|
id="apn"
|
||||||
|
type="text"
|
||||||
|
className="p-1.5 border border-gray-400 rounded-lg"
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup>
|
||||||
|
<label
|
||||||
|
htmlFor="username"
|
||||||
|
className="font-medium whitespace-nowrap md:w-2/3"
|
||||||
|
>
|
||||||
|
Username
|
||||||
|
</label>
|
||||||
|
<Field
|
||||||
|
placeholder="Enter Username"
|
||||||
|
name="username"
|
||||||
|
id="username"
|
||||||
|
type="text"
|
||||||
|
className="p-1.5 border border-gray-400 rounded-lg"
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup>
|
||||||
|
<label
|
||||||
|
htmlFor="password"
|
||||||
|
className="font-medium whitespace-nowrap md:w-2/3"
|
||||||
|
>
|
||||||
|
Password
|
||||||
|
</label>
|
||||||
|
<Field
|
||||||
|
placeholder="Enter Password"
|
||||||
|
name="password"
|
||||||
|
id="password"
|
||||||
|
type="text"
|
||||||
|
className="p-1.5 border border-gray-400 rounded-lg"
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
<FormGroup>
|
||||||
|
<label
|
||||||
|
htmlFor="password"
|
||||||
|
className="font-medium whitespace-nowrap md:w-2/3"
|
||||||
|
>
|
||||||
|
Password
|
||||||
|
</label>
|
||||||
|
<Field
|
||||||
|
name="authenticationType"
|
||||||
|
as="select"
|
||||||
|
className="p-2 border border-gray-400 rounded-lg text-white bg-[#253445] flex-1 w-2/3"
|
||||||
|
>
|
||||||
|
<option value="PAP">PAP</option>
|
||||||
|
<option value="CHAP">CHAP</option>
|
||||||
|
<option value="none">None</option>
|
||||||
|
</Field>
|
||||||
|
</FormGroup>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
className="bg-[#26B170] text-white px-4 py-2 rounded hover:bg-green-700 transition w-full md:w-[50%]"
|
||||||
>
|
>
|
||||||
APN
|
{isSubmitting || modemMutation.isPending
|
||||||
</label>
|
? "Saving..."
|
||||||
<Field
|
: "Save Modem settings"}
|
||||||
placeholder="Enter APN"
|
</button>
|
||||||
name="apn"
|
</Form>
|
||||||
id="apn"
|
)}
|
||||||
type="text"
|
|
||||||
className="p-1.5 border border-gray-400 rounded-lg"
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
<FormGroup>
|
|
||||||
<label
|
|
||||||
htmlFor="username"
|
|
||||||
className="font-medium whitespace-nowrap md:w-2/3"
|
|
||||||
>
|
|
||||||
Username
|
|
||||||
</label>
|
|
||||||
<Field
|
|
||||||
placeholder="Enter Username"
|
|
||||||
name="username"
|
|
||||||
id="username"
|
|
||||||
type="text"
|
|
||||||
className="p-1.5 border border-gray-400 rounded-lg"
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
<FormGroup>
|
|
||||||
<label
|
|
||||||
htmlFor="password"
|
|
||||||
className="font-medium whitespace-nowrap md:w-2/3"
|
|
||||||
>
|
|
||||||
Password
|
|
||||||
</label>
|
|
||||||
<Field
|
|
||||||
placeholder="Enter Password"
|
|
||||||
name="password"
|
|
||||||
id="password"
|
|
||||||
type="text"
|
|
||||||
className="p-1.5 border border-gray-400 rounded-lg"
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
<FormGroup>
|
|
||||||
<label
|
|
||||||
htmlFor="password"
|
|
||||||
className="font-medium whitespace-nowrap md:w-2/3"
|
|
||||||
>
|
|
||||||
Password
|
|
||||||
</label>
|
|
||||||
<Field
|
|
||||||
name="authenticationType"
|
|
||||||
as="select"
|
|
||||||
className="p-2 border border-gray-400 rounded-lg text-white bg-[#253445] flex-1 w-2/3"
|
|
||||||
>
|
|
||||||
<option value="PAP">PAP</option>
|
|
||||||
<option value="CHAP">CHAP</option>
|
|
||||||
<option value="none">None</option>
|
|
||||||
</Field>
|
|
||||||
</FormGroup>
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
className="bg-[#26B170] text-white px-4 py-2 rounded hover:bg-green-700 transition w-full md:w-[50%]"
|
|
||||||
>
|
|
||||||
Save Modem settings
|
|
||||||
</button>
|
|
||||||
</Form>
|
|
||||||
</Formik>
|
</Formik>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ const WiFiSettingsForm = () => {
|
|||||||
encryption: "WPA2",
|
encryption: "WPA2",
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmit = (values: WifiSettingValues) => {
|
const handleSubmit = async (values: WifiSettingValues) => {
|
||||||
const wifiConfig = {
|
const wifiConfig = {
|
||||||
id: "ModemAndWifiManager-wifi",
|
id: "ModemAndWifiManager-wifi",
|
||||||
fields: [
|
fields: [
|
||||||
@@ -34,7 +34,7 @@ const WiFiSettingsForm = () => {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
wifiMutation.mutate(wifiConfig);
|
await wifiMutation.mutateAsync(wifiConfig);
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<Formik
|
<Formik
|
||||||
@@ -42,7 +42,7 @@ const WiFiSettingsForm = () => {
|
|||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
enableReinitialize
|
enableReinitialize
|
||||||
>
|
>
|
||||||
{() => (
|
{({ isSubmitting }) => (
|
||||||
<Form className="flex flex-col space-y-5 px-2">
|
<Form className="flex flex-col space-y-5 px-2">
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<label
|
<label
|
||||||
@@ -103,7 +103,9 @@ const WiFiSettingsForm = () => {
|
|||||||
type="submit"
|
type="submit"
|
||||||
className="bg-[#26B170] text-white px-4 py-2 rounded hover:bg-green-700 transition w-full md:w-[50%]"
|
className="bg-[#26B170] text-white px-4 py-2 rounded hover:bg-green-700 transition w-full md:w-[50%]"
|
||||||
>
|
>
|
||||||
Save WiFi settings
|
{isSubmitting || wifiMutation.isPending
|
||||||
|
? "Saving..."
|
||||||
|
: " Save WiFi settings"}
|
||||||
</button>
|
</button>
|
||||||
</Form>
|
</Form>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
import { useLatestSighting } from "../../hooks/useLatestSighting";
|
|
||||||
|
|
||||||
const SightingCanvas = () => {
|
|
||||||
const { canvasRef } = useLatestSighting();
|
|
||||||
return (
|
|
||||||
<div className="w-70 flex flex-col">
|
|
||||||
<canvas
|
|
||||||
ref={canvasRef}
|
|
||||||
className="items-center w-full h-10 object-contain block"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default SightingCanvas;
|
|
||||||
@@ -41,12 +41,15 @@ export const useCameraBlackboard = () => {
|
|||||||
value: options?.value,
|
value: options?.value,
|
||||||
}),
|
}),
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
toast.error(`cannot get data: ${error.message}`);
|
toast.error(`cannot get data: ${error.message}`, {
|
||||||
|
id: "viewBlackboardData",
|
||||||
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (query.isError) toast.error(query.error.message);
|
if (query.isError)
|
||||||
|
toast.error(query.error.message, { id: "viewBlackboardData" });
|
||||||
}, [query?.error?.message, query.isError]);
|
}, [query?.error?.message, query.isError]);
|
||||||
|
|
||||||
return { query, mutation };
|
return { query, mutation };
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ import { CAM_BASE } from "../utils/config";
|
|||||||
|
|
||||||
const base_url = `${CAM_BASE}/api`;
|
const base_url = `${CAM_BASE}/api`;
|
||||||
|
|
||||||
const fetch_url = `http://100.82.205.44/api/fetch-config?id=Colour`;
|
|
||||||
console.log(fetch_url);
|
|
||||||
const fetchCameraSideConfig = async ({ queryKey }: { queryKey: string[] }) => {
|
const fetchCameraSideConfig = async ({ queryKey }: { queryKey: string[] }) => {
|
||||||
const [, cameraSide] = queryKey;
|
const [, cameraSide] = queryKey;
|
||||||
const fetchUrl = `${base_url}/fetch-config?id=${cameraSide}`;
|
const fetchUrl = `${base_url}/fetch-config?id=${cameraSide}`;
|
||||||
|
|||||||
@@ -70,11 +70,13 @@ export const useWifiAndModem = () => {
|
|||||||
mutationKey: ["updateWifiSettings"],
|
mutationKey: ["updateWifiSettings"],
|
||||||
mutationFn: (wifiConfig: WifiConfig) => updateWifiSettings(wifiConfig),
|
mutationFn: (wifiConfig: WifiConfig) => updateWifiSettings(wifiConfig),
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
toast.error("Failed to update WiFi settings");
|
toast.error("Failed to update WiFi settings", { id: "wiFiSettings" });
|
||||||
console.error(error);
|
console.error(error);
|
||||||
},
|
},
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
toast.success("WiFi settings updated successfully");
|
toast.success("WiFi settings updated successfully", {
|
||||||
|
id: "wiFiSettings",
|
||||||
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -87,20 +89,24 @@ export const useWifiAndModem = () => {
|
|||||||
mutationKey: ["updateModemSettings"],
|
mutationKey: ["updateModemSettings"],
|
||||||
mutationFn: (modemConfig: ModemConfig) => updateModemSettings(modemConfig),
|
mutationFn: (modemConfig: ModemConfig) => updateModemSettings(modemConfig),
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
toast.error("Failed to update Modem settings");
|
toast.error("Failed to update Modem settings", { id: "modemSettings" });
|
||||||
console.error(error);
|
console.error(error);
|
||||||
},
|
},
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
toast.success("Modem settings updated successfully");
|
toast.success("Modem settings updated successfully", {
|
||||||
|
id: "modemSettings",
|
||||||
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (wifiQuery.isError) toast.error("Cannot get WiFi settings");
|
if (wifiQuery.isError)
|
||||||
|
toast.error("Cannot get WiFi settings", { id: "wiFiSettings" });
|
||||||
}, [wifiQuery?.error?.message, wifiQuery.isError]);
|
}, [wifiQuery?.error?.message, wifiQuery.isError]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (modemQuery.isError) toast.error("Cannot get Modem settings");
|
if (modemQuery.isError)
|
||||||
|
toast.error("Cannot get Modem settings", { id: "modemSettings" });
|
||||||
}, [modemQuery?.error?.message, modemQuery.isError]);
|
}, [modemQuery?.error?.message, modemQuery.isError]);
|
||||||
return {
|
return {
|
||||||
wifiQuery,
|
wifiQuery,
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {
|
|||||||
} from "@tanstack/react-query";
|
} from "@tanstack/react-query";
|
||||||
import { CAM_BASE } from "../utils/config";
|
import { CAM_BASE } from "../utils/config";
|
||||||
import type { zoomConfig, ZoomInOptions } from "../types/types";
|
import type { zoomConfig, ZoomInOptions } from "../types/types";
|
||||||
|
import { toast } from "sonner";
|
||||||
|
|
||||||
async function zoomIn(options: ZoomInOptions) {
|
async function zoomIn(options: ZoomInOptions) {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
@@ -37,6 +38,9 @@ export const useCameraZoom = (options: zoomConfig) => {
|
|||||||
const mutation = useMutation({
|
const mutation = useMutation({
|
||||||
mutationKey: ["zoomIn"],
|
mutationKey: ["zoomIn"],
|
||||||
mutationFn: (options: ZoomInOptions) => zoomIn(options),
|
mutationFn: (options: ZoomInOptions) => zoomIn(options),
|
||||||
|
onError: () => {
|
||||||
|
toast.error("Failed to update zoom settings", { id: "zoom" });
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const query = useQuery({
|
const query = useQuery({
|
||||||
|
|||||||
@@ -1,60 +0,0 @@
|
|||||||
import { useQuery } from "@tanstack/react-query";
|
|
||||||
import { useCallback, useEffect, useRef } from "react";
|
|
||||||
|
|
||||||
async function fetchSighting() {
|
|
||||||
const response = await fetch(
|
|
||||||
// `http://100.82.205.44/api`
|
|
||||||
`http://192.168.75.11/mergedHistory/sightingSummary?mostRecentRef=-1`
|
|
||||||
);
|
|
||||||
if (!response.ok) throw new Error("Failed to fetch sighting");
|
|
||||||
return response.json();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useLatestSighting() {
|
|
||||||
const latestUrlRef = useRef<string | null>(null);
|
|
||||||
const canvasRef = useRef<HTMLCanvasElement | null>(null);
|
|
||||||
const sightingImageRef = useRef<HTMLImageElement | null>(null);
|
|
||||||
|
|
||||||
const drawImage = useCallback(() => {
|
|
||||||
const canvas = canvasRef.current;
|
|
||||||
const ctx = canvas?.getContext("2d");
|
|
||||||
const img2 = sightingImageRef.current;
|
|
||||||
|
|
||||||
if (!img2 || !canvas) return;
|
|
||||||
|
|
||||||
canvas.width = canvas.clientWidth;
|
|
||||||
canvas.height = canvas.clientHeight;
|
|
||||||
|
|
||||||
ctx?.drawImage(img2, 0, 0, 200, 50);
|
|
||||||
}, [sightingImageRef]);
|
|
||||||
|
|
||||||
const { data } = useQuery({
|
|
||||||
queryKey: ["latestSighting"],
|
|
||||||
queryFn: fetchSighting,
|
|
||||||
refetchInterval: 100,
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const img = new Image();
|
|
||||||
sightingImageRef.current = img;
|
|
||||||
|
|
||||||
img.onload = () => {
|
|
||||||
drawImage();
|
|
||||||
};
|
|
||||||
img.src = data?.plateUrlColour;
|
|
||||||
|
|
||||||
if (latestUrlRef.current) {
|
|
||||||
URL.revokeObjectURL(latestUrlRef.current);
|
|
||||||
}
|
|
||||||
latestUrlRef.current = img.src;
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
if (latestUrlRef.current) {
|
|
||||||
URL.revokeObjectURL(latestUrlRef.current);
|
|
||||||
latestUrlRef.current = null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}, [data?.plateUrlColour, drawImage]);
|
|
||||||
|
|
||||||
return { data, sightingImageRef, canvasRef };
|
|
||||||
}
|
|
||||||
@@ -5,25 +5,43 @@ import {
|
|||||||
handleSystemSave,
|
handleSystemSave,
|
||||||
handleSystemRecall,
|
handleSystemRecall,
|
||||||
} from "../components/SettingForms/System/SettingSaveRecall";
|
} from "../components/SettingForms/System/SettingSaveRecall";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
|
||||||
export const useSystemConfig = () => {
|
export const useSystemConfig = () => {
|
||||||
const uploadSettingsMutation = useMutation({
|
const uploadSettingsMutation = useMutation({
|
||||||
mutationKey: ["uploadSettings"],
|
mutationKey: ["uploadSettings"],
|
||||||
mutationFn: sendBlobFileUpload,
|
mutationFn: sendBlobFileUpload,
|
||||||
onError: (error) => toast.error(error.message),
|
onError: (error) =>
|
||||||
onSuccess: (test) => toast(test),
|
toast.error(error.message, {
|
||||||
|
id: "uploadSettings",
|
||||||
|
}),
|
||||||
|
onSuccess: (test) =>
|
||||||
|
toast(test, {
|
||||||
|
id: "uploadSettings",
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const saveSystemSettings = useMutation({
|
const saveSystemSettings = useMutation({
|
||||||
mutationKey: ["systemSaveSettings"],
|
mutationKey: ["systemSaveSettings"],
|
||||||
mutationFn: handleSystemSave,
|
mutationFn: handleSystemSave,
|
||||||
onError: (error) => console.error(error.message),
|
onError: (error) =>
|
||||||
|
toast.error(error.message, {
|
||||||
|
id: "systemSettings",
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const getSystemSettings = useQuery({
|
const getSystemSettings = useQuery({
|
||||||
queryKey: ["getSystemSettings"],
|
queryKey: ["getSystemSettings"],
|
||||||
queryFn: handleSystemRecall,
|
queryFn: handleSystemRecall,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (getSystemSettings.isError)
|
||||||
|
toast.error(getSystemSettings.error.message, {
|
||||||
|
id: "systemSettings",
|
||||||
|
});
|
||||||
|
}, [getSystemSettings?.error?.message, getSystemSettings.isError]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
uploadSettings: uploadSettingsMutation.mutate,
|
uploadSettings: uploadSettingsMutation.mutate,
|
||||||
saveSystemSettings: saveSystemSettings.mutate,
|
saveSystemSettings: saveSystemSettings.mutate,
|
||||||
|
|||||||
Reference in New Issue
Block a user