more enhancements to loading and error feedback
This commit is contained in:
@@ -27,11 +27,11 @@ const NPEDFields = () => {
|
||||
rearId: "NPED",
|
||||
};
|
||||
|
||||
const handleSubmit = (values: NPEDFieldType) => {
|
||||
const handleSubmit = async (values: NPEDFieldType) => {
|
||||
const valuesToSend = {
|
||||
...values,
|
||||
};
|
||||
signIn(valuesToSend);
|
||||
await signIn(valuesToSend);
|
||||
};
|
||||
|
||||
const validateValues = (values: NPEDFieldType) => {
|
||||
@@ -54,7 +54,7 @@ const NPEDFields = () => {
|
||||
validate={validateValues}
|
||||
enableReinitialize
|
||||
>
|
||||
{({ errors, touched }) => (
|
||||
{({ errors, touched, isSubmitting }) => (
|
||||
<Form className="flex flex-col space-y-5 px-2">
|
||||
<FormGroup>
|
||||
<label htmlFor="username">Username</label>
|
||||
@@ -112,7 +112,7 @@ const NPEDFields = () => {
|
||||
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"
|
||||
>
|
||||
Login
|
||||
{isSubmitting ? "Logging in..." : "Login"}
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
|
||||
@@ -25,7 +25,7 @@ const ModemSettings = () => {
|
||||
authenticationType: "PAP",
|
||||
};
|
||||
|
||||
const handleSubmit = (values: ModemSettingsType) => {
|
||||
const handleSubmit = async (values: ModemSettingsType) => {
|
||||
const modemConfig = {
|
||||
id: "ModemAndWifiManager-modem",
|
||||
fields: [
|
||||
@@ -48,7 +48,7 @@ const ModemSettings = () => {
|
||||
},
|
||||
],
|
||||
};
|
||||
modemMutation.mutate(modemConfig);
|
||||
await modemMutation.mutateAsync(modemConfig);
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -63,76 +63,80 @@ const ModemSettings = () => {
|
||||
onSubmit={handleSubmit}
|
||||
enableReinitialize
|
||||
>
|
||||
<Form className="flex flex-col space-y-5 px-2">
|
||||
<FormGroup>
|
||||
<label
|
||||
htmlFor="apn"
|
||||
className="font-medium whitespace-nowrap md:w-2/3"
|
||||
{({ isSubmitting }) => (
|
||||
<Form className="flex flex-col space-y-5 px-2">
|
||||
<FormGroup>
|
||||
<label
|
||||
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
|
||||
</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%]"
|
||||
>
|
||||
Save Modem settings
|
||||
</button>
|
||||
</Form>
|
||||
{isSubmitting || modemMutation.isPending
|
||||
? "Saving..."
|
||||
: "Save Modem settings"}
|
||||
</button>
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -19,7 +19,7 @@ const WiFiSettingsForm = () => {
|
||||
encryption: "WPA2",
|
||||
};
|
||||
|
||||
const handleSubmit = (values: WifiSettingValues) => {
|
||||
const handleSubmit = async (values: WifiSettingValues) => {
|
||||
const wifiConfig = {
|
||||
id: "ModemAndWifiManager-wifi",
|
||||
fields: [
|
||||
@@ -34,7 +34,7 @@ const WiFiSettingsForm = () => {
|
||||
],
|
||||
};
|
||||
|
||||
wifiMutation.mutate(wifiConfig);
|
||||
await wifiMutation.mutateAsync(wifiConfig);
|
||||
};
|
||||
return (
|
||||
<Formik
|
||||
@@ -42,7 +42,7 @@ const WiFiSettingsForm = () => {
|
||||
onSubmit={handleSubmit}
|
||||
enableReinitialize
|
||||
>
|
||||
{() => (
|
||||
{({ isSubmitting }) => (
|
||||
<Form className="flex flex-col space-y-5 px-2">
|
||||
<FormGroup>
|
||||
<label
|
||||
@@ -103,7 +103,9 @@ const WiFiSettingsForm = () => {
|
||||
type="submit"
|
||||
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>
|
||||
</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,
|
||||
}),
|
||||
onError: (error) => {
|
||||
toast.error(`cannot get data: ${error.message}`);
|
||||
toast.error(`cannot get data: ${error.message}`, {
|
||||
id: "viewBlackboardData",
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (query.isError) toast.error(query.error.message);
|
||||
if (query.isError)
|
||||
toast.error(query.error.message, { id: "viewBlackboardData" });
|
||||
}, [query?.error?.message, query.isError]);
|
||||
|
||||
return { query, mutation };
|
||||
|
||||
@@ -4,8 +4,6 @@ import { CAM_BASE } from "../utils/config";
|
||||
|
||||
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 [, cameraSide] = queryKey;
|
||||
const fetchUrl = `${base_url}/fetch-config?id=${cameraSide}`;
|
||||
|
||||
@@ -70,11 +70,13 @@ export const useWifiAndModem = () => {
|
||||
mutationKey: ["updateWifiSettings"],
|
||||
mutationFn: (wifiConfig: WifiConfig) => updateWifiSettings(wifiConfig),
|
||||
onError: (error) => {
|
||||
toast.error("Failed to update WiFi settings");
|
||||
toast.error("Failed to update WiFi settings", { id: "wiFiSettings" });
|
||||
console.error(error);
|
||||
},
|
||||
onSuccess: () => {
|
||||
toast.success("WiFi settings updated successfully");
|
||||
toast.success("WiFi settings updated successfully", {
|
||||
id: "wiFiSettings",
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -87,20 +89,24 @@ export const useWifiAndModem = () => {
|
||||
mutationKey: ["updateModemSettings"],
|
||||
mutationFn: (modemConfig: ModemConfig) => updateModemSettings(modemConfig),
|
||||
onError: (error) => {
|
||||
toast.error("Failed to update Modem settings");
|
||||
toast.error("Failed to update Modem settings", { id: "modemSettings" });
|
||||
console.error(error);
|
||||
},
|
||||
onSuccess: () => {
|
||||
toast.success("Modem settings updated successfully");
|
||||
toast.success("Modem settings updated successfully", {
|
||||
id: "modemSettings",
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
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]);
|
||||
|
||||
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]);
|
||||
return {
|
||||
wifiQuery,
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
} from "@tanstack/react-query";
|
||||
import { CAM_BASE } from "../utils/config";
|
||||
import type { zoomConfig, ZoomInOptions } from "../types/types";
|
||||
import { toast } from "sonner";
|
||||
|
||||
async function zoomIn(options: ZoomInOptions) {
|
||||
const response = await fetch(
|
||||
@@ -37,6 +38,9 @@ export const useCameraZoom = (options: zoomConfig) => {
|
||||
const mutation = useMutation({
|
||||
mutationKey: ["zoomIn"],
|
||||
mutationFn: (options: ZoomInOptions) => zoomIn(options),
|
||||
onError: () => {
|
||||
toast.error("Failed to update zoom settings", { id: "zoom" });
|
||||
},
|
||||
});
|
||||
|
||||
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,
|
||||
handleSystemRecall,
|
||||
} from "../components/SettingForms/System/SettingSaveRecall";
|
||||
import { useEffect } from "react";
|
||||
|
||||
export const useSystemConfig = () => {
|
||||
const uploadSettingsMutation = useMutation({
|
||||
mutationKey: ["uploadSettings"],
|
||||
mutationFn: sendBlobFileUpload,
|
||||
onError: (error) => toast.error(error.message),
|
||||
onSuccess: (test) => toast(test),
|
||||
onError: (error) =>
|
||||
toast.error(error.message, {
|
||||
id: "uploadSettings",
|
||||
}),
|
||||
onSuccess: (test) =>
|
||||
toast(test, {
|
||||
id: "uploadSettings",
|
||||
}),
|
||||
});
|
||||
|
||||
const saveSystemSettings = useMutation({
|
||||
mutationKey: ["systemSaveSettings"],
|
||||
mutationFn: handleSystemSave,
|
||||
onError: (error) => console.error(error.message),
|
||||
onError: (error) =>
|
||||
toast.error(error.message, {
|
||||
id: "systemSettings",
|
||||
}),
|
||||
});
|
||||
|
||||
const getSystemSettings = useQuery({
|
||||
queryKey: ["getSystemSettings"],
|
||||
queryFn: handleSystemRecall,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (getSystemSettings.isError)
|
||||
toast.error(getSystemSettings.error.message, {
|
||||
id: "systemSettings",
|
||||
});
|
||||
}, [getSystemSettings?.error?.message, getSystemSettings.isError]);
|
||||
|
||||
return {
|
||||
uploadSettings: uploadSettingsMutation.mutate,
|
||||
saveSystemSettings: saveSystemSettings.mutate,
|
||||
|
||||
Reference in New Issue
Block a user