Compare commits
14 Commits
5dc1d13e25
...
bugfix/fee
| Author | SHA1 | Date | |
|---|---|---|---|
| ac9b3cc1ea | |||
| 79e759d811 | |||
| b79fde777d | |||
| a8ef18d2b9 | |||
| 6a1d63d98a | |||
| 24ea41205f | |||
| 5b188747a5 | |||
| 1c760cb2a8 | |||
| 26e9238518 | |||
| 29e9086d5a | |||
| 555330991d | |||
| cae652477e | |||
| 8b635101de | |||
| 696a36ba92 |
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "in-car-system-fe",
|
||||
"private": true,
|
||||
"version": "1.0.16",
|
||||
"version": "1.0.23",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
@@ -31,6 +31,7 @@
|
||||
"react-swipeable": "^7.0.2",
|
||||
"react-tabs": "^6.1.0",
|
||||
"react-use": "^17.6.0",
|
||||
"react-use-websocket": "^4.13.0",
|
||||
"sonner": "^2.0.7",
|
||||
"tailwindcss": "^4.1.11",
|
||||
"use-debounce": "^10.0.6"
|
||||
|
||||
11
public/NPED_Cat_D.svg
Normal file
11
public/NPED_Cat_D.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 29 KiB |
31
src/App.tsx
31
src/App.tsx
@@ -9,25 +9,28 @@ import { IntegrationsProvider } from "./context/providers/IntegrationsContextPro
|
||||
import { AlertHitProvider } from "./context/providers/AlertHitProvider";
|
||||
import { SoundProvider } from "react-sounds";
|
||||
import SoundContextProvider from "./context/providers/SoundContextProvider";
|
||||
import WebSocketProvider from "./context/providers/WebSocketProvider";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<SoundContextProvider>
|
||||
<SoundProvider initialEnabled={true}>
|
||||
<IntegrationsProvider>
|
||||
<AlertHitProvider>
|
||||
<Routes>
|
||||
<Route path="/" element={<Container />}>
|
||||
<Route index element={<Dashboard />} />
|
||||
<Route path="a-camera-settings" element={<FrontCamera />} />
|
||||
<Route path="b-camera-settings" element={<RearCamera />} />
|
||||
<Route path="system-settings" element={<SystemSettings />} />
|
||||
<Route path="session-settings" element={<Session />} />
|
||||
<Route path="*" element={<Navigate to="/" replace />} />
|
||||
</Route>
|
||||
</Routes>
|
||||
</AlertHitProvider>
|
||||
</IntegrationsProvider>
|
||||
<WebSocketProvider>
|
||||
<IntegrationsProvider>
|
||||
<AlertHitProvider>
|
||||
<Routes>
|
||||
<Route path="/" element={<Container />}>
|
||||
<Route index element={<Dashboard />} />
|
||||
<Route path="a-camera-settings" element={<FrontCamera />} />
|
||||
<Route path="b-camera-settings" element={<RearCamera />} />
|
||||
<Route path="system-settings" element={<SystemSettings />} />
|
||||
<Route path="session-settings" element={<Session />} />
|
||||
<Route path="*" element={<Navigate to="/" replace />} />
|
||||
</Route>
|
||||
</Routes>
|
||||
</AlertHitProvider>
|
||||
</IntegrationsProvider>
|
||||
</WebSocketProvider>
|
||||
</SoundProvider>
|
||||
</SoundContextProvider>
|
||||
);
|
||||
|
||||
@@ -22,7 +22,6 @@ const CameraSettingFields = ({
|
||||
onZoomLevelChange,
|
||||
}: CameraSettingsProps) => {
|
||||
const [showPwd, setShowPwd] = useState(false);
|
||||
|
||||
const cameraControllerSide = initialData?.id === "CameraA" ? "CameraControllerA" : "CameraControllerB";
|
||||
const { mutation, query } = useCameraZoom({ camera: cameraControllerSide });
|
||||
const { cameraModeQuery, cameraModeMutation } = useCameraMode({ camera: cameraControllerSide });
|
||||
@@ -44,7 +43,7 @@ const CameraSettingFields = ({
|
||||
userName: parsed?.username ?? "",
|
||||
password: parsed?.password ?? "",
|
||||
id: initialData?.id,
|
||||
mode: cameraMode ?? "day",
|
||||
mode: cameraMode ?? "",
|
||||
zoom: apiZoom,
|
||||
}),
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import { useCameraBlackboard } from "../../hooks/useCameraBlackboard";
|
||||
import NPED_CAT_A from "/NPED_Cat_A.svg";
|
||||
import NPED_CAT_B from "/NPED_Cat_B.svg";
|
||||
import NPED_CAT_C from "/NPED_Cat_C.svg";
|
||||
import NPED_CAT_D from "/NPED_Cat_D.svg";
|
||||
import { checkIsHotListHit, formatAge, getNPEDCategory } from "../../utils/utils";
|
||||
import { faX } from "@fortawesome/free-solid-svg-icons";
|
||||
import { faClock } from "@fortawesome/free-regular-svg-icons";
|
||||
@@ -30,6 +31,7 @@ const AlertItem = ({ item }: AlertItemProps) => {
|
||||
const isNPEDHitA = cat === "A";
|
||||
const isNPEDHitB = cat === "B";
|
||||
const isNPEDHitC = cat === "C";
|
||||
const isNPEDHitD = cat === "D";
|
||||
|
||||
const handleClick = () => {
|
||||
setIsModalOpen(true);
|
||||
@@ -69,6 +71,7 @@ const AlertItem = ({ item }: AlertItemProps) => {
|
||||
{isNPEDHitA && <img src={NPED_CAT_A} alt="NPEDHITicon" className="h-20 object-contain rounded-md" />}
|
||||
{isNPEDHitB && <img src={NPED_CAT_B} alt="NPEDHITicon" className="h-20 object-contain rounded-md" />}
|
||||
{isNPEDHitC && <img src={NPED_CAT_C} alt="NPEDHITicon" className="h-20 object-contain rounded-md" />}
|
||||
{isNPEDHitD && <img src={NPED_CAT_D} alt="NPEDHITicon" className="h-20 object-contain rounded-md" />}
|
||||
<div className={`border p-1 hidden md:block`}>
|
||||
<img src={item?.plateUrlColour} height={48} width={200} alt="colour patch" />
|
||||
</div>
|
||||
|
||||
@@ -31,9 +31,7 @@ const HistoryList = () => {
|
||||
<div className="flex flex-col gap-1 px-2">
|
||||
{state?.alertList?.length > 0 ? (
|
||||
<div className="mt-3 grid grid-cols-1 gap-3">
|
||||
{state?.alertList?.map((alertItem) => (
|
||||
<AlertItem item={alertItem} key={alertItem.vrm} />
|
||||
))}
|
||||
{state?.alertList?.map((alertItem) => <AlertItem item={alertItem} key={alertItem.vrm} />).reverse()}
|
||||
</div>
|
||||
) : (
|
||||
<div className="mt-4 flex flex-col items-center justify-center rounded-2xl border border-slate-800 bg-slate-900/40 p-10 text-center">
|
||||
|
||||
@@ -10,6 +10,7 @@ import { toast } from "sonner";
|
||||
|
||||
const NPEDCategoryPopup = () => {
|
||||
const { state, dispatch } = useIntegrationsContext();
|
||||
|
||||
const { mutation } = useCameraBlackboard();
|
||||
|
||||
const isCatAEnabled = state?.iscatEnabled?.catA;
|
||||
@@ -34,8 +35,8 @@ const NPEDCategoryPopup = () => {
|
||||
await mutation.mutateAsync({
|
||||
operation: "SAVE",
|
||||
path: "",
|
||||
value: null
|
||||
})
|
||||
value: null,
|
||||
});
|
||||
if (result?.reason === "OK") toast.success("Pop up settings saved");
|
||||
dispatch({ type: "NPEDCATENABLED", payload: values });
|
||||
};
|
||||
@@ -44,7 +45,7 @@ const NPEDCategoryPopup = () => {
|
||||
<Card className="p-4">
|
||||
<CardHeader title={"Alert Pop ups"} />
|
||||
<p className="italic my-2">Allows alerts to pop up to user.</p>
|
||||
<Formik initialValues={initialValues} onSubmit={handleSubmit}>
|
||||
<Formik initialValues={initialValues} onSubmit={handleSubmit} enableReinitialize>
|
||||
<Form className="flex flex-col space-y-5 px-2">
|
||||
<FormGroup>
|
||||
<NPEDCatToggle name={"catA"} label="NPED Category A" />
|
||||
|
||||
@@ -172,6 +172,11 @@ const SessionCard = () => {
|
||||
textColour="text-gray-300"
|
||||
vehicleTag={"Vehicles with NPED Cat C:"}
|
||||
/>
|
||||
<VehicleSessionItem
|
||||
sessionNumber={vehicles.npedCatD.length}
|
||||
textColour="text-gray-300"
|
||||
vehicleTag={"Vehicles with NPED Cat D:"}
|
||||
/>
|
||||
</ul>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
@@ -5,13 +5,13 @@ import { useSoundContext } from "../../../context/SoundContext";
|
||||
import { toast } from "sonner";
|
||||
import { useCameraBlackboard } from "../../../hooks/useCameraBlackboard";
|
||||
import { useFileUpload } from "../../../hooks/useFileUpload";
|
||||
import { useEffect, useRef } from "react";
|
||||
|
||||
const SoundUpload = () => {
|
||||
const { state, dispatch } = useSoundContext();
|
||||
const { mutation } = useCameraBlackboard();
|
||||
const { mutation: fileMutation } = useFileUpload({
|
||||
queryKey: state.sightingSound ? [state.sightingSound] : undefined,
|
||||
});
|
||||
const currentUrlRef = useRef<string | null>(null);
|
||||
const { mutation: fileMutation } = useFileUpload();
|
||||
|
||||
const initialValues: SoundUploadValue = {
|
||||
name: "",
|
||||
@@ -43,6 +43,10 @@ const SoundUpload = () => {
|
||||
value: updatedValues,
|
||||
});
|
||||
await fileMutation.mutateAsync(values.soundFile);
|
||||
if (currentUrlRef.current) {
|
||||
URL.revokeObjectURL(currentUrlRef.current);
|
||||
currentUrlRef.current = null;
|
||||
}
|
||||
if (result.reason !== "OK") {
|
||||
toast.error("Cannot update sound settings");
|
||||
}
|
||||
@@ -54,6 +58,14 @@ const SoundUpload = () => {
|
||||
dispatch({ type: "ADD", payload: values });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (currentUrlRef.current) {
|
||||
URL.revokeObjectURL(currentUrlRef.current);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Formik initialValues={initialValues} onSubmit={handleSubmit} enableReinitialize>
|
||||
{({ setFieldValue, errors, setFieldError }) => (
|
||||
@@ -69,14 +81,26 @@ const SoundUpload = () => {
|
||||
accept="audio/mpeg"
|
||||
className="mt-4 w-full flex flex-col items-center justify-center rounded-2xl border border-slate-800 bg-slate-900/40 p-10 text-center file:px-3 file:border file:border-gray-500 file:rounded-lg file:bg-blue-800 file:mr-5"
|
||||
onChange={(e) => {
|
||||
if (e.target?.files && e.target?.files[0]?.type === "audio/mpeg") {
|
||||
const url = URL.createObjectURL(e.target.files[0]);
|
||||
if (currentUrlRef.current) {
|
||||
URL.revokeObjectURL(currentUrlRef.current);
|
||||
}
|
||||
const files = e.target?.files;
|
||||
if (
|
||||
files &&
|
||||
(files[0]?.type === "audio/mp3" ||
|
||||
files[0]?.type === "audio/mpeg" ||
|
||||
files[0]?.name.endsWith(".wav"))
|
||||
) {
|
||||
const file = e.target?.files;
|
||||
if(file === null) return;
|
||||
currentUrlRef.current = URL.createObjectURL(file[0]);
|
||||
const url = currentUrlRef.current;
|
||||
setFieldValue("soundUrl", url);
|
||||
setFieldValue("name", e.target.files[0].name);
|
||||
setFieldValue("soundFileName", e.target.files[0].name);
|
||||
setFieldValue("soundFile", e.target.files[0]);
|
||||
setFieldValue("name", file[0].name);
|
||||
setFieldValue("soundFileName", file[0].name);
|
||||
setFieldValue("soundFile", file[0]);
|
||||
setFieldValue("uploadedAt", Date.now());
|
||||
if (e?.target?.files[0]?.size >= 1 * 1024 * 1024) {
|
||||
if (file[0]?.size >= 1 * 1024 * 1024) {
|
||||
setFieldError("soundFile", "larger than 1mb");
|
||||
toast.error("File larger than 1MB");
|
||||
return;
|
||||
|
||||
@@ -5,21 +5,38 @@ import { timezones } from "./timezones";
|
||||
import SystemFileUpload from "./SystemFileUpload";
|
||||
import type { SystemValues, SystemValuesErrors } from "../../../types/types";
|
||||
import { useDNSSettings, useSystemConfig } from "../../../hooks/useSystemConfig";
|
||||
import { ValidateIPaddress } from "../../../utils/utils";
|
||||
import { ValidateIPaddress, isUtcOutOfSync } from "../../../utils/utils";
|
||||
import { toast } from "sonner";
|
||||
import { useSystemStatus } from "../../../hooks/useSystemStatus";
|
||||
|
||||
const SystemConfigFields = () => {
|
||||
const { saveSystemSettings, systemSettingsData, saveSystemSettingsLoading } = useSystemConfig();
|
||||
const { systemStatusQuery } = useSystemStatus();
|
||||
const { hardRebootMutation } = useReboots();
|
||||
const { dnsQuery, dnsMutation } = useDNSSettings();
|
||||
|
||||
if (systemStatusQuery?.isLoading || !systemStatusQuery?.data) {
|
||||
return <div>Loading...</div>;
|
||||
}
|
||||
const utcTime = systemStatusQuery?.data?.SystemStatus?.utctime;
|
||||
const localDate = systemStatusQuery?.data?.SystemStatus?.localdate;
|
||||
const localTime = systemStatusQuery?.data?.SystemStatus?.localtime;
|
||||
|
||||
const utcOutOfSync = isUtcOutOfSync({
|
||||
utctime: utcTime,
|
||||
localdate: localDate,
|
||||
localtime: localTime,
|
||||
});
|
||||
|
||||
const sntpInterval = systemSettingsData?.sntpInterval;
|
||||
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,
|
||||
sntpInterval: sntpInterval ?? 60,
|
||||
serverPrimary: dnsPrimary ?? "",
|
||||
serverSecondary: dnsSecondary ?? "",
|
||||
softwareUpdate: null,
|
||||
@@ -67,6 +84,13 @@ const SystemConfigFields = () => {
|
||||
>
|
||||
{({ values, errors, touched, isSubmitting }) => (
|
||||
<Form className="flex flex-col space-y-5 px-2">
|
||||
<div>
|
||||
{utcOutOfSync?.outOfSync ? (
|
||||
<span className="text-red-800 bg-red-300 border border-red-800 rounded-lg p-2">UTC is out of sync</span>
|
||||
) : (
|
||||
<span className="text-green-300 bg-green-800 border border-green-600 rounded-lg p-2">UTC is in sync</span>
|
||||
)}
|
||||
</div>
|
||||
<FormGroup>
|
||||
<label htmlFor="deviceName" className="font-medium whitespace-nowrap md:w-1/2 text-left">
|
||||
Device Name
|
||||
|
||||
@@ -2,6 +2,7 @@ import { useFormikContext } from "formik";
|
||||
import FormGroup from "../components/FormGroup";
|
||||
import { toast } from "sonner";
|
||||
import { useSystemConfig } from "../../../hooks/useSystemConfig";
|
||||
import { CAM_BASE } from "../../../utils/config";
|
||||
|
||||
type SystemFileUploadProps = {
|
||||
name: string;
|
||||
@@ -19,7 +20,7 @@ const SystemFileUpload = ({ name, selectedFile }: SystemFileUploadProps) => {
|
||||
opts: {
|
||||
timeoutMs: 30000,
|
||||
fieldName: "upload",
|
||||
uploadUrl: "http://192.168.75.11/upload/software-update/2",
|
||||
uploadUrl: `${CAM_BASE}/upload/software-update/4`,
|
||||
},
|
||||
};
|
||||
uploadSettings(settings);
|
||||
|
||||
@@ -17,7 +17,6 @@ const WiFiSettingsForm = () => {
|
||||
const initialValues = {
|
||||
ssid: wifiSSID ?? "",
|
||||
password: wifiPassword ?? "",
|
||||
encryption: "WPA2",
|
||||
};
|
||||
|
||||
const validatePassword = (password: string) => {
|
||||
@@ -83,22 +82,7 @@ const WiFiSettingsForm = () => {
|
||||
/>
|
||||
</div>
|
||||
</FormGroup>
|
||||
<FormGroup>
|
||||
<label htmlFor="encryption" className="font-medium whitespace-nowrap md:w-2/3">
|
||||
WPA/Encryption Type
|
||||
</label>
|
||||
<Field
|
||||
id="encryption"
|
||||
name="encryption"
|
||||
className="p-2 border border-gray-400 rounded-lg text-white bg-[#253445] flex-1 w-2/3"
|
||||
as="select"
|
||||
>
|
||||
<option value="WPA2">WPA2</option>
|
||||
<option value="WPA3">WPA3</option>
|
||||
<option value="WEP">WEP</option>
|
||||
<option value="None">None</option>
|
||||
</Field>
|
||||
</FormGroup>
|
||||
|
||||
<button
|
||||
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"
|
||||
|
||||
@@ -10,7 +10,8 @@ import HotListImg from "/Hotlist_Hit.svg";
|
||||
import NPED_CAT_A from "/NPED_Cat_A.svg";
|
||||
import NPED_CAT_B from "/NPED_Cat_B.svg";
|
||||
import NPED_CAT_C from "/NPED_Cat_C.svg";
|
||||
import { checkIsHotListHit, getHotlistName, getNPEDCategory } from "../../utils/utils";
|
||||
import NPED_CAT_D from "/NPED_Cat_D.svg";
|
||||
import { checkIsHotListHit, getHotlistName, getNPEDCategory, getNPEDReason } from "../../utils/utils";
|
||||
|
||||
type SightingModalProps = {
|
||||
isSightingModalOpen: boolean;
|
||||
@@ -74,11 +75,19 @@ const SightingModal = ({ isSightingModalOpen, handleClose, sighting, onDelete }:
|
||||
};
|
||||
|
||||
const motionAway = (sighting?.motion ?? "").toUpperCase() === "AWAY";
|
||||
|
||||
const isHotListHit = checkIsHotListHit(sighting);
|
||||
const cat = getNPEDCategory(sighting);
|
||||
const isNPEDHitA = cat === "A";
|
||||
const isNPEDHitB = cat === "B";
|
||||
const isNPEDHitC = cat === "C";
|
||||
const isNPEDHitD = cat === "D";
|
||||
|
||||
const reason = getNPEDReason(sighting);
|
||||
|
||||
const insuranceStatus = reason ? reason["INSURANCE STATUS"] : null;
|
||||
const motStatus = reason ? reason["MOT STATUS"] : null;
|
||||
const taxStatus = reason ? reason["TAX STATUS"] : null;
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -133,17 +142,18 @@ const SightingModal = ({ isSightingModalOpen, handleClose, sighting, onDelete }:
|
||||
{isNPEDHitA && <img src={NPED_CAT_A} alt="hotlistHit" className="h-20 object-contain rounded-md" />}
|
||||
{isNPEDHitB && <img src={NPED_CAT_B} alt="hotlistHit" className="h-20 object-contain rounded-md" />}
|
||||
{isNPEDHitC && <img src={NPED_CAT_C} alt="hotlistHit" className="h-20 object-contain rounded-md" />}
|
||||
{isNPEDHitD && <img src={NPED_CAT_D} alt="hotlistHit" className="h-20 object-contain rounded-md" />}
|
||||
</div>
|
||||
{hotlistNames && hotlistNames.length > 0 && (
|
||||
<div className="flex flex-col border-b border-gray-600 mb-4">
|
||||
<p className="text-gray-300">Hotlists</p>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-x-[90%] lg:gap-x-[15%] w-[50%]">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 md:gap-x-[20%] w-[50%]">
|
||||
{hotlistNames.map((hotlistName, index) => (
|
||||
<div className="items-center px-2.5 py-0.5 rounded-sm me-2 bg-amber-500 w-55 m-2" key={index}>
|
||||
<span className="items-center px-2.5 py-0.5 rounded-sm me-2 bg-amber-500 w-50 m-2" key={index}>
|
||||
<p className="font-medium text-2xl break-all text-amber-800">
|
||||
{hotlistName ? hotlistName?.replace(/\.csv$/i, "") : "-"}
|
||||
</p>
|
||||
</div>
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
@@ -158,44 +168,93 @@ const SightingModal = ({ isSightingModalOpen, handleClose, sighting, onDelete }:
|
||||
<h3 className="text-base md:text-lg font-semibold pb-2 border-b border-gray-700">Vehicle Info</h3>
|
||||
<dl className="mt-3 gap-x-4 gap-y-2 text-sm">
|
||||
<div>
|
||||
<dt className="text-gray-300">VRM</dt>
|
||||
<dd className="font-medium text-2xl break-all">{sighting?.vrm ?? "-"}</dd>
|
||||
<dd className="font-medium text-2xl break-all font-mono tracking-wide">{sighting?.vrm ?? "-"}</dd>
|
||||
</div>
|
||||
{isNPEDHitA || isNPEDHitB || isNPEDHitC || isNPEDHitD ? (
|
||||
<>
|
||||
<div className="">
|
||||
<dt className="text-gray-300 text-xl">Insurance</dt>
|
||||
<dd className="font-medium text-2xl flex">
|
||||
{insuranceStatus ? (
|
||||
<span
|
||||
className={`text-green-600 bg-green-300 w-[30%] px-2 rounded-lg border border-green-900`}
|
||||
>
|
||||
YES
|
||||
</span>
|
||||
) : (
|
||||
<span className={`text-red-300 bg-red-600 w-[30%] px-2 rounded-lg border border-red-900`}>
|
||||
NO
|
||||
</span>
|
||||
)}
|
||||
</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt className="text-gray-300 text-3xl">MOT</dt>
|
||||
<dd className="font-medium text-2xl">
|
||||
{motStatus ? (
|
||||
<span
|
||||
className={`text-green-700 bg-green-400 w-[30%] px-2 rounded-lg border border-green-900`}
|
||||
>
|
||||
VALID
|
||||
</span>
|
||||
) : (
|
||||
<span className={`text-red-600 bg-red-300 w-[30%] px-2 rounded-lg border border-red-900`}>
|
||||
EXPIRED
|
||||
</span>
|
||||
)}
|
||||
</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt className="text-gray-300 text-3xl">Tax</dt>
|
||||
<dd className="font-medium text-2xl">
|
||||
{taxStatus ? (
|
||||
<span
|
||||
className={`text-green-700 bg-green-400 w-[30%] px-2 rounded-lg border border-green-900`}
|
||||
>
|
||||
VALID
|
||||
</span>
|
||||
) : (
|
||||
<span className={`text-red-600 bg-red-300 w-[30%] px-2 rounded-lg border border-red-900`}>
|
||||
EXPIRED
|
||||
</span>
|
||||
)}
|
||||
</dd>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div>
|
||||
<dt className="text-gray-300">Motion</dt>
|
||||
<dd className="font-medium text-2xl ">{sighting?.motion ?? "-"}</dd>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<dt className="text-gray-300">Motion</dt>
|
||||
<dd className="font-medium text-2xl">{sighting?.motion ?? "-"}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt className="text-gray-300">Seen Count</dt>
|
||||
<dd className="font-medium text-2xl">{sighting?.seenCount ?? "-"}</dd>
|
||||
</div>
|
||||
{sighting?.make && sighting.make.trim() && sighting.make.toLowerCase() !== "disabled" && (
|
||||
<div>
|
||||
<dt className="text-gray-300">Make</dt>
|
||||
<dd className="font-medium text-2xl">{sighting.make}</dd>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{sighting?.make && sighting.make.trim() && sighting.make.toLowerCase() !== "disabled" && (
|
||||
<div>
|
||||
<dt className="text-gray-300">Make</dt>
|
||||
<dd className="font-medium text-2xl">{sighting.make}</dd>
|
||||
</div>
|
||||
{sighting?.model && sighting.model.trim() && sighting.model.toLowerCase() !== "disabled" && (
|
||||
<div>
|
||||
<dt className="text-gray-300">Model</dt>
|
||||
<dd className="font-medium text-2xl">{sighting.model}</dd>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{sighting?.color && sighting.color.trim() && sighting.color.toLowerCase() !== "disabled" && (
|
||||
<div className="sm:col-span-2">
|
||||
<dt className="text-gray-300">Colour</dt>
|
||||
<dd className="font-medium text-2xl">{sighting.color}</dd>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div>
|
||||
<dt className="text-gray-300">Time</dt>
|
||||
<dd className="font-medium text-xl">{sighting?.timeStamp ?? "-"}</dd>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{sighting?.model && sighting.model.trim() && sighting.model.toLowerCase() !== "disabled" && (
|
||||
<div>
|
||||
<dt className="text-gray-300">Model</dt>
|
||||
<dd className="font-medium text-2xl">{sighting.model}</dd>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{sighting?.color && sighting.color.trim() && sighting.color.toLowerCase() !== "disabled" && (
|
||||
<div className="sm:col-span-2">
|
||||
<dt className="text-gray-300">Colour</dt>
|
||||
<dd className="font-medium text-2xl">{sighting.color}</dd>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div>
|
||||
<dt className="text-gray-300">Time</dt>
|
||||
<dd className="font-medium text-xl">{sighting?.timeStamp ?? "-"}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
@@ -12,14 +12,10 @@ import HotListImg from "/Hotlist_Hit.svg";
|
||||
import NPED_CAT_A from "/NPED_Cat_A.svg";
|
||||
import NPED_CAT_B from "/NPED_Cat_B.svg";
|
||||
import NPED_CAT_C from "/NPED_Cat_C.svg";
|
||||
import popup from "../../assets/sounds/ui/popup_open.mp3";
|
||||
import notification from "../../assets/sounds/ui/notification.mp3";
|
||||
import { useSound } from "react-sounds";
|
||||
import NPED_CAT_D from "/NPED_Cat_D.svg";
|
||||
import { useIntegrationsContext } from "../../context/IntegrationsContext";
|
||||
import { useSoundContext } from "../../context/SoundContext";
|
||||
import Loading from "../UI/Loading";
|
||||
import { checkIsHotListHit, getNPEDCategory } from "../../utils/utils";
|
||||
import { useCachedSoundSrc } from "../../hooks/usecachedSoundSrc";
|
||||
|
||||
function useNow(tickMs = 1000) {
|
||||
const [, setNow] = useState(() => Date.now());
|
||||
@@ -41,14 +37,9 @@ type SightingHistoryProps = {
|
||||
|
||||
export default function SightingHistoryWidget({ className, title }: SightingHistoryProps) {
|
||||
const [modalQueue, setModalQueue] = useState<QueuedHit[]>([]);
|
||||
|
||||
useNow(1000);
|
||||
const { state } = useSoundContext();
|
||||
|
||||
const { src: soundSrcHotlist } = useCachedSoundSrc(state?.hotlistSound, state?.soundOptions, notification);
|
||||
const { src: soundSrcNped } = useCachedSoundSrc(state?.NPEDsound, state?.soundOptions, popup);
|
||||
|
||||
const { play: npedSound } = useSound(soundSrcNped, { volume: state.NPEDsoundVolume });
|
||||
const { play: hotlistsound } = useSound(soundSrcHotlist, { volume: state.hotlistSoundVolume });
|
||||
const {
|
||||
sightings,
|
||||
setSelectedSighting,
|
||||
@@ -73,18 +64,24 @@ export default function SightingHistoryWidget({ className, title }: SightingHist
|
||||
const isCatCEnabled = integrationState?.iscatEnabled?.catC;
|
||||
const isCatDEnabled = integrationState?.iscatEnabled?.catD;
|
||||
|
||||
const enqueue = useCallback((sighting: SightingType, kind: HitKind) => {
|
||||
const id = sighting.vrm ?? sighting.ref;
|
||||
if (processedRefs.current.has(id)) return;
|
||||
const enqueue = useCallback(
|
||||
(sighting: SightingType, kind: HitKind) => {
|
||||
if (!sighting) return;
|
||||
|
||||
const inList = alertState?.alertList?.find((sighting) => sighting.vrm === id);
|
||||
if (inList) {
|
||||
return;
|
||||
}
|
||||
processedRefs.current.add(id);
|
||||
const id = sighting.vrm ?? sighting.ref;
|
||||
if (processedRefs.current.has(id)) return;
|
||||
|
||||
setModalQueue((q) => [...q, { id, sighting, kind }]);
|
||||
}, []);
|
||||
const inList = alertState?.alertList?.find((sighting) => sighting.vrm === id);
|
||||
if (inList) {
|
||||
return;
|
||||
}
|
||||
|
||||
processedRefs.current.add(id);
|
||||
|
||||
setModalQueue((q) => [...q, { id, sighting, kind }]);
|
||||
},
|
||||
[alertState?.alertList]
|
||||
);
|
||||
|
||||
const reduceObject = (obj: SightingType): ReducedSightingType => {
|
||||
return {
|
||||
@@ -133,31 +130,16 @@ export default function SightingHistoryWidget({ className, title }: SightingHist
|
||||
enqueue(sighting, isNPED ? "NPED" : "HOTLIST"); // enqueue ONLY
|
||||
}
|
||||
}
|
||||
}, [rows, enqueue]);
|
||||
|
||||
useEffect(() => {
|
||||
rows?.forEach((obj) => {
|
||||
const cat = getNPEDCategory(obj);
|
||||
const isNPEDHitA = cat === "A";
|
||||
const isNPEDHitB = cat === "B";
|
||||
const isNPEDHitC = cat === "C";
|
||||
if (isNPEDHitA || isNPEDHitB || isNPEDHitC) {
|
||||
dispatch({
|
||||
type: "ADD",
|
||||
payload: obj,
|
||||
});
|
||||
}
|
||||
});
|
||||
}, [dispatch]);
|
||||
}, [rows, enqueue, isCatAEnabled, isCatBEnabled, isCatCEnabled, isCatDEnabled]);
|
||||
|
||||
useEffect(() => {
|
||||
if (hasAutoOpenedRef.current || npedRef.current) return;
|
||||
const firstNPED = rows.find((r) => {
|
||||
const cat = getNPEDCategory(r);
|
||||
const isNPEDHitA = cat === "A";
|
||||
const isNPEDHitB = cat === "B";
|
||||
const isNPEDHitC = cat === "C";
|
||||
const isNPEDHitD = cat === "D";
|
||||
const isNPEDHitA = cat === "A" && isCatAEnabled;
|
||||
const isNPEDHitB = cat === "B" && isCatBEnabled;
|
||||
const isNPEDHitC = cat === "C" && isCatCEnabled;
|
||||
const isNPEDHitD = cat === "D" && isCatDEnabled;
|
||||
return isNPEDHitA || isNPEDHitB || isNPEDHitC || isNPEDHitD;
|
||||
});
|
||||
const firstHot = rows?.find((r) => {
|
||||
@@ -176,20 +158,41 @@ export default function SightingHistoryWidget({ className, title }: SightingHist
|
||||
|
||||
hasAutoOpenedRef.current = true;
|
||||
}
|
||||
}, [enqueue, hotlistsound, npedSound, rows, setSelectedSighting, setSightingModalOpen]);
|
||||
}, [
|
||||
enqueue,
|
||||
rows,
|
||||
setSelectedSighting,
|
||||
setSightingModalOpen,
|
||||
isCatAEnabled,
|
||||
isCatBEnabled,
|
||||
isCatCEnabled,
|
||||
isCatDEnabled,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isSightingModalOpen && modalQueue.length > 0) {
|
||||
const next = modalQueue[0];
|
||||
|
||||
if (next.kind === "NPED") npedSound();
|
||||
else hotlistsound();
|
||||
|
||||
setSelectedSighting(next.sighting);
|
||||
|
||||
setSightingModalOpen(true);
|
||||
}
|
||||
}, [isSightingModalOpen, npedSound, hotlistsound, setSelectedSighting, setSightingModalOpen, modalQueue]);
|
||||
}, [isSightingModalOpen, setSelectedSighting, setSightingModalOpen, modalQueue]);
|
||||
|
||||
useEffect(() => {
|
||||
rows?.forEach((obj) => {
|
||||
const cat = getNPEDCategory(obj);
|
||||
const isNPEDHitA = cat === "A";
|
||||
const isNPEDHitB = cat === "B";
|
||||
const isNPEDHitC = cat === "C";
|
||||
const isNPEDHitD = cat === "D";
|
||||
if (isNPEDHitA || isNPEDHitB || isNPEDHitC || isNPEDHitD) {
|
||||
dispatch({
|
||||
type: "ADD",
|
||||
payload: obj,
|
||||
});
|
||||
}
|
||||
});
|
||||
}, [dispatch, rows]);
|
||||
|
||||
const handleClose = () => {
|
||||
setSightingModalOpen(false);
|
||||
@@ -212,6 +215,7 @@ export default function SightingHistoryWidget({ className, title }: SightingHist
|
||||
const isNPEDHitA = cat === "A";
|
||||
const isNPEDHitB = cat === "B";
|
||||
const isNPEDHitC = cat === "C";
|
||||
const isNPEDHitD = cat === "D";
|
||||
const motionAway = (obj?.motion ?? "").toUpperCase() === "AWAY";
|
||||
const isHotListHit = checkIsHotListHit(obj);
|
||||
return (
|
||||
@@ -230,6 +234,7 @@ export default function SightingHistoryWidget({ className, title }: SightingHist
|
||||
{isNPEDHitA && <img src={NPED_CAT_A} alt="hotlistHit" className="h-20 object-contain rounded-md" />}
|
||||
{isNPEDHitB && <img src={NPED_CAT_B} alt="hotlistHit" className="h-20 object-contain rounded-md" />}
|
||||
{isNPEDHitC && <img src={NPED_CAT_C} alt="hotlistHit" className="h-20 object-contain rounded-md" />}
|
||||
{isNPEDHitD && <img src={NPED_CAT_D} alt="hotlistHit" className="h-20 object-contain rounded-md" />}
|
||||
<NumberPlate motion={motionAway} vrm={obj?.vrm} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -12,8 +12,16 @@ const ModalComponent = ({ isModalOpen, children, close }: ModalComponentProps) =
|
||||
<Modal
|
||||
isOpen={isModalOpen}
|
||||
onRequestClose={close}
|
||||
className="bg-[#1e2a38] p-3 rounded-lg shadow-lg w-[95%] mt-[2%] md:w-[60%] h-[100%] md:h-[95%] lg:h-[85%] z-[100] overflow-y-auto"
|
||||
overlayClassName="fixed inset-0 bg-[#1e2a38]/70 flex justify-center items-start z-100"
|
||||
className="bg-[#1e2a38] p-3 rounded-lg shadow-lg w-[95%] mt-[2%] md:w-[60%] h-[100%] md:h-[95%] lg:h-[80%] z-[100] overflow-y-hidden border border-gray-500"
|
||||
overlayClassName="fixed inset-0 bg-[#1e2a38]/70 flex justify-center items-start z-100 "
|
||||
style={{
|
||||
overlay: {
|
||||
transition: "opacity 200ms ease-in-out",
|
||||
},
|
||||
content: {
|
||||
transition: "all 200ms ease-in-out",
|
||||
},
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</Modal>
|
||||
|
||||
@@ -15,10 +15,10 @@ const VersionsModal = ({ isDevModalOpen, handleClose, data }: VersionsModalProps
|
||||
|
||||
return (
|
||||
<ModalComponent isModalOpen={isDevModalOpen} close={handleClose}>
|
||||
<div className="flex justify-end">
|
||||
<div className="flex justify-end overflow-auto">
|
||||
<button
|
||||
onClick={handleClose}
|
||||
className="p-2 border border-gray-600 rounded-md text-gray-200 hover:bg-gray-700 transition mb-4"
|
||||
className="p-2 border border-gray-600 rounded-md text-gray-200 hover:bg-gray-700 transition"
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
|
||||
33
src/context/WebsocketContext.ts
Normal file
33
src/context/WebsocketContext.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { createContext, useContext } from "react";
|
||||
import type { InfoBarData } from "../types/types";
|
||||
import { ReadyState } from "react-use-websocket";
|
||||
|
||||
type InfoSocketState = {
|
||||
data: InfoBarData | null;
|
||||
readyState: ReadyState;
|
||||
sendJson: (msg: unknown) => void;
|
||||
send?: (msg: string) => void;
|
||||
};
|
||||
|
||||
type heatmapSocketState = {
|
||||
data: null;
|
||||
readyState: ReadyState;
|
||||
sendJson: (msg: unknown) => void;
|
||||
send?: (msg: string) => void;
|
||||
};
|
||||
|
||||
export type WebsocketContextValue = {
|
||||
info: InfoSocketState;
|
||||
heatmap?: heatmapSocketState;
|
||||
};
|
||||
|
||||
export const WebsocketContext = createContext<WebsocketContextValue | null>(null);
|
||||
|
||||
const useWebSocketContext = () => {
|
||||
const ctx = useContext(WebsocketContext);
|
||||
if (!ctx) throw new Error("useWebSocketContext must be used inside <WebSocketConext.Provider>");
|
||||
return ctx;
|
||||
};
|
||||
|
||||
export const useInfoBarSocket = () => useWebSocketContext().info;
|
||||
export const useHeatmapSocket = () => useWebSocketContext().heatmap;
|
||||
@@ -36,10 +36,19 @@ export const IntegrationsProvider = ({ children }: IntegrationsProviderType) =>
|
||||
});
|
||||
|
||||
if (!isMounted) return;
|
||||
if (!result?.result || typeof result.result === "string") return;
|
||||
|
||||
dispatch({ type: "UPDATE", payload: result.result });
|
||||
dispatch({ type: "NPEDCATENABLED", payload: catResult.result });
|
||||
if (result?.result && typeof result.result !== "string") {
|
||||
dispatch({ type: "UPDATE", payload: result.result });
|
||||
}
|
||||
|
||||
if (catResult?.result) {
|
||||
dispatch({ type: "NPEDCATENABLED", payload: catResult.result });
|
||||
} else {
|
||||
dispatch({
|
||||
type: "NPEDCATENABLED",
|
||||
payload: { catA: true, catB: true, catC: true, catD: true },
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error in fetchData:", error);
|
||||
}
|
||||
|
||||
40
src/context/providers/WebSocketProvider.tsx
Normal file
40
src/context/providers/WebSocketProvider.tsx
Normal file
@@ -0,0 +1,40 @@
|
||||
import { useEffect, useMemo, useState, type ReactNode } from "react";
|
||||
import type { InfoBarData } from "../../types/types";
|
||||
import useWebSocket from "react-use-websocket";
|
||||
import { ws_config } from "../../utils/ws_config";
|
||||
import { WebsocketContext, type WebsocketContextValue } from "../WebsocketContext";
|
||||
|
||||
type WebSocketProviderProps = {
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
const WebSocketProvider = ({ children }: WebSocketProviderProps) => {
|
||||
const [systemData, setSystemData] = useState<InfoBarData | null>(null);
|
||||
|
||||
const infoSocket = useWebSocket(ws_config.infoBar, { share: true, shouldReconnect: () => true });
|
||||
|
||||
useEffect(() => {
|
||||
async function parseData() {
|
||||
if (infoSocket.lastMessage) {
|
||||
const text = await infoSocket.lastMessage.data.text();
|
||||
const data = JSON.parse(text);
|
||||
setSystemData(data);
|
||||
}
|
||||
}
|
||||
parseData();
|
||||
}, [infoSocket.lastMessage]);
|
||||
|
||||
const value = useMemo<WebsocketContextValue>(
|
||||
() => ({
|
||||
info: {
|
||||
data: systemData,
|
||||
readyState: infoSocket.readyState,
|
||||
sendJson: infoSocket.sendJsonMessage,
|
||||
},
|
||||
}),
|
||||
[systemData, infoSocket.readyState, infoSocket.sendJsonMessage]
|
||||
);
|
||||
return <WebsocketContext.Provider value={value}>{children}</WebsocketContext.Provider>;
|
||||
};
|
||||
|
||||
export default WebSocketProvider;
|
||||
@@ -1,12 +1,9 @@
|
||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import { CAM_BASE } from "../utils/config";
|
||||
import { toast } from "sonner";
|
||||
import { getOrCacheBlob } from "../utils/cacheSound";
|
||||
const camBase = import.meta.env.MODE !== "development" ? CAM_BASE : CAM_BASE;
|
||||
|
||||
type UseFileUploadProps = {
|
||||
queryKey?: string[];
|
||||
};
|
||||
const camBase = import.meta.env.MODE !== "development" ? CAM_BASE : CAM_BASE;
|
||||
console.log(camBase);
|
||||
|
||||
const uploadFile = async (file: File) => {
|
||||
const form = new FormData();
|
||||
@@ -21,19 +18,7 @@ const uploadFile = async (file: File) => {
|
||||
return response.text();
|
||||
};
|
||||
|
||||
const getUploadFiles = async ({ queryKey }: { queryKey: string[] }) => {
|
||||
const [, fileName] = queryKey;
|
||||
const url = fileName;
|
||||
return getOrCacheBlob(url);
|
||||
};
|
||||
|
||||
export const useFileUpload = ({ queryKey }: UseFileUploadProps) => {
|
||||
const query = useQuery({
|
||||
queryKey: ["getUploadFiles", ...(queryKey ?? [])],
|
||||
queryFn: () => getUploadFiles({ queryKey: ["getUploadFiles", ...(queryKey ?? [])] }),
|
||||
enabled: !!queryKey,
|
||||
});
|
||||
|
||||
export const useFileUpload = () => {
|
||||
const mutation = useMutation({
|
||||
mutationFn: (file: File) => uploadFile(file),
|
||||
mutationKey: ["uploadFile"],
|
||||
@@ -41,5 +26,5 @@ export const useFileUpload = ({ queryKey }: UseFileUploadProps) => {
|
||||
onSuccess: async (msg) => toast.success(msg),
|
||||
});
|
||||
|
||||
return { query: queryKey ? query : undefined, mutation };
|
||||
return { mutation };
|
||||
};
|
||||
|
||||
22
src/hooks/useGetUploadedFiles.ts
Normal file
22
src/hooks/useGetUploadedFiles.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { getOrCacheBlob } from "../utils/cacheSound";
|
||||
|
||||
type UseFileUploadProps = {
|
||||
queryKey?: string[];
|
||||
};
|
||||
|
||||
const getUploadFiles = async ({ queryKey }: { queryKey: string[] }) => {
|
||||
const [, fileName] = queryKey;
|
||||
const url = fileName;
|
||||
return getOrCacheBlob(url);
|
||||
};
|
||||
|
||||
export const useGetUploadedFiles = ({ queryKey }: UseFileUploadProps) => {
|
||||
const query = useQuery({
|
||||
queryKey: ["getUploadFiles", ...(queryKey ?? [])],
|
||||
queryFn: () => getUploadFiles({ queryKey: ["getUploadFiles", ...(queryKey ?? [])] }),
|
||||
enabled: !!queryKey,
|
||||
});
|
||||
|
||||
return { query: queryKey ? query : undefined };
|
||||
};
|
||||
@@ -88,8 +88,14 @@ export function useSightingFeed(url: string | undefined) {
|
||||
const isNPEDHitA = cat === "A";
|
||||
const isNPEDHitB = cat === "B";
|
||||
const isNPEDHitC = cat === "C";
|
||||
const isNPEDHitD = cat === "D";
|
||||
|
||||
if ((isNPEDHitA && audioArmed) || (isNPEDHitB && audioArmed) || (isNPEDHitC && audioArmed)) {
|
||||
if (
|
||||
(isNPEDHitA && audioArmed) ||
|
||||
(isNPEDHitB && audioArmed) ||
|
||||
(isNPEDHitC && audioArmed) ||
|
||||
(isNPEDHitD && audioArmed)
|
||||
) {
|
||||
playNPEDHitSound();
|
||||
} else if (isHotListHit && audioArmed) {
|
||||
playHotlistsound();
|
||||
|
||||
20
src/hooks/useSystemStatus.ts
Normal file
20
src/hooks/useSystemStatus.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { CAM_BASE } from "../utils/config";
|
||||
|
||||
const fetchSystemStatus = async () => {
|
||||
const response = await fetch(`${CAM_BASE}/sysstatus?func=getstatus`);
|
||||
if (!response.ok) {
|
||||
throw new Error("Network response was not ok");
|
||||
}
|
||||
return response.json();
|
||||
};
|
||||
|
||||
export const useSystemStatus = () => {
|
||||
const systemStatusQuery = useQuery({
|
||||
queryKey: ["get systemStatus"],
|
||||
queryFn: fetchSystemStatus,
|
||||
refetchInterval: 60000,
|
||||
});
|
||||
|
||||
return { systemStatusQuery };
|
||||
};
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useFileUpload } from "./useFileUpload";
|
||||
import { getSoundFileURL } from "../utils/utils";
|
||||
import type { SoundUploadValue } from "../types/types";
|
||||
import { resolveSoundSource } from "../utils/soundResolver";
|
||||
import { useGetUploadedFiles } from "./useGetUploadedFiles";
|
||||
|
||||
export function useCachedSoundSrc(
|
||||
selected: string | undefined,
|
||||
@@ -13,7 +13,7 @@ export function useCachedSoundSrc(
|
||||
|
||||
const resolved = resolveSoundSource(selected, soundOptions);
|
||||
|
||||
const { query } = useFileUpload({
|
||||
const { query } = useGetUploadedFiles({
|
||||
queryKey: resolved?.type === "uploaded" ? [resolved?.url] : undefined,
|
||||
});
|
||||
|
||||
|
||||
@@ -37,3 +37,33 @@ body {
|
||||
stroke-width: 20px;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
|
||||
/* Modal animations */
|
||||
.ReactModal__Overlay {
|
||||
opacity: 0;
|
||||
transition: opacity 200ms ease-in-out;
|
||||
}
|
||||
|
||||
.ReactModal__Overlay--after-open {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.ReactModal__Overlay--before-close {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.ReactModal__Content {
|
||||
transform: scale(0.9) translateY(-20px);
|
||||
opacity: 0;
|
||||
transition: all 200ms ease-in-out;
|
||||
}
|
||||
|
||||
.ReactModal__Content--after-open {
|
||||
transform: scale(1) translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.ReactModal__Content--before-close {
|
||||
transform: scale(0.9) translateY(-20px);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
@@ -367,7 +367,7 @@ export type SoundAction = UpdateAction | AddAction | VolumeAction | UploadedStat
|
||||
export type WifiSettingValues = {
|
||||
ssid: string;
|
||||
password: string;
|
||||
encryption: string;
|
||||
encryption?: string;
|
||||
};
|
||||
export type ModemConfigPayload = {
|
||||
property: string;
|
||||
@@ -458,3 +458,10 @@ export type versionInfo = {
|
||||
"Serial No.": string;
|
||||
"Model No.": string;
|
||||
};
|
||||
|
||||
export type InfoBarData = {
|
||||
"system-clock-utc": string;
|
||||
"system-clock-local": string;
|
||||
"memory-cpu-status": string;
|
||||
"thread-count": string;
|
||||
};
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
export async function getOrCacheBlob(url: string) {
|
||||
const cacheAvailable = typeof window !== "undefined" && "caches" in window;
|
||||
|
||||
if (!cacheAvailable) {
|
||||
const res = await fetch(url, { cache: "no-store" });
|
||||
if (!res.ok) throw new Error(`Fetch failed: ${res.status}`);
|
||||
return await res.blob();
|
||||
}
|
||||
|
||||
const cache = await caches.open("app-sounds-v1");
|
||||
const hit = await cache.match(url);
|
||||
if (hit) return await hit.blob();
|
||||
@@ -11,6 +19,11 @@ export async function getOrCacheBlob(url: string) {
|
||||
}
|
||||
|
||||
export async function evictFromCache(url: string) {
|
||||
const cacheAvailable = typeof window !== "undefined" && "caches" in window;
|
||||
|
||||
if (!cacheAvailable) {
|
||||
return;
|
||||
}
|
||||
const cache = await caches.open("app-sounds-v1");
|
||||
await cache.delete(url);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
const rawCamBase = import.meta.env.VITE_AGX_BOX_URL;
|
||||
const rawCamBase = import.meta.env.VITE_CHRIS_BOX_URL;
|
||||
const environment = import.meta.env.MODE;
|
||||
|
||||
export const CAM_BASE =
|
||||
environment === "development" ? rawCamBase : window.location.origin;
|
||||
export const CAM_BASE = environment === "development" ? rawCamBase : window.location.origin;
|
||||
|
||||
@@ -159,6 +159,8 @@ 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 getNPEDReason = (r?: SightingType | null) => r?.metadata?.npedJSON;
|
||||
|
||||
export const zoomMapping = (zoomLevel: number | undefined) => {
|
||||
switch (zoomLevel) {
|
||||
case 1:
|
||||
@@ -195,3 +197,21 @@ export const ValidateIPaddress = (value: string | undefined) => {
|
||||
return "Invalid IP address format";
|
||||
}
|
||||
};
|
||||
|
||||
export function isUtcOutOfSync(
|
||||
data: {
|
||||
utctime: number;
|
||||
localdate: string;
|
||||
localtime: string;
|
||||
},
|
||||
maxDriftMs = 60_000
|
||||
) {
|
||||
const utc = new Date(data.utctime);
|
||||
|
||||
const [d, m, y] = data.localdate.split("/").map(Number);
|
||||
const [hh, mm, ss] = data.localtime.split(":").map(Number);
|
||||
// Construct local Date in device’s local timezone
|
||||
const local = new Date(y, m - 1, d, hh, mm, ss);
|
||||
const driftMs = Math.abs(utc.getTime() - local.getTime() + utc.getTimezoneOffset() * 60_000);
|
||||
return { driftMs, outOfSync: driftMs > maxDriftMs };
|
||||
}
|
||||
|
||||
6
src/utils/ws_config.ts
Normal file
6
src/utils/ws_config.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { CAM_BASE } from "./config";
|
||||
|
||||
export const ws_config = {
|
||||
infoBar: `${CAM_BASE.replace("http", "ws")}/websocket-infobar`,
|
||||
heatmap: `${CAM_BASE.replace("http", "ws")}/websocket-SystemConfig`,
|
||||
};
|
||||
@@ -27,7 +27,7 @@ export default defineConfig({
|
||||
host: true,
|
||||
proxy: {
|
||||
"/api": {
|
||||
target: "http://100.118.196.113:8080",
|
||||
target: "http://100.72.72.70:8080",
|
||||
changeOrigin: true,
|
||||
},
|
||||
},
|
||||
@@ -40,3 +40,4 @@ export default defineConfig({
|
||||
__GIT_TIMESTAMP__: JSON.stringify(gitCommitTimeStamp),
|
||||
},
|
||||
});
|
||||
// Previous target: "http://100.118.196.113:8080",
|
||||
|
||||
438
yarn.lock
438
yarn.lock
@@ -24,7 +24,7 @@
|
||||
resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz"
|
||||
integrity sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==
|
||||
|
||||
"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.28.0":
|
||||
"@babel/core@^7.28.0":
|
||||
version "7.28.0"
|
||||
resolved "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz"
|
||||
integrity sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==
|
||||
@@ -173,6 +173,153 @@
|
||||
"@babel/helper-string-parser" "^7.27.1"
|
||||
"@babel/helper-validator-identifier" "^7.27.1"
|
||||
|
||||
"@emnapi/core@^1.4.3":
|
||||
version "1.7.1"
|
||||
resolved "https://registry.yarnpkg.com/@emnapi/core/-/core-1.7.1.tgz#3a79a02dbc84f45884a1806ebb98e5746bdfaac4"
|
||||
integrity sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==
|
||||
dependencies:
|
||||
"@emnapi/wasi-threads" "1.1.0"
|
||||
tslib "^2.4.0"
|
||||
|
||||
"@emnapi/runtime@^1.4.3":
|
||||
version "1.7.1"
|
||||
resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.7.1.tgz#a73784e23f5d57287369c808197288b52276b791"
|
||||
integrity sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==
|
||||
dependencies:
|
||||
tslib "^2.4.0"
|
||||
|
||||
"@emnapi/wasi-threads@1.1.0", "@emnapi/wasi-threads@^1.0.2":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz#60b2102fddc9ccb78607e4a3cf8403ea69be41bf"
|
||||
integrity sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==
|
||||
dependencies:
|
||||
tslib "^2.4.0"
|
||||
|
||||
"@esbuild/aix-ppc64@0.25.9":
|
||||
version "0.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz#bef96351f16520055c947aba28802eede3c9e9a9"
|
||||
integrity sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==
|
||||
|
||||
"@esbuild/android-arm64@0.25.9":
|
||||
version "0.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz#d2e70be7d51a529425422091e0dcb90374c1546c"
|
||||
integrity sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==
|
||||
|
||||
"@esbuild/android-arm@0.25.9":
|
||||
version "0.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.25.9.tgz#d2a753fe2a4c73b79437d0ba1480e2d760097419"
|
||||
integrity sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==
|
||||
|
||||
"@esbuild/android-x64@0.25.9":
|
||||
version "0.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.25.9.tgz#5278836e3c7ae75761626962f902a0d55352e683"
|
||||
integrity sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==
|
||||
|
||||
"@esbuild/darwin-arm64@0.25.9":
|
||||
version "0.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz#f1513eaf9ec8fa15dcaf4c341b0f005d3e8b47ae"
|
||||
integrity sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==
|
||||
|
||||
"@esbuild/darwin-x64@0.25.9":
|
||||
version "0.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz#e27dbc3b507b3a1cea3b9280a04b8b6b725f82be"
|
||||
integrity sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==
|
||||
|
||||
"@esbuild/freebsd-arm64@0.25.9":
|
||||
version "0.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz#364e3e5b7a1fd45d92be08c6cc5d890ca75908ca"
|
||||
integrity sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==
|
||||
|
||||
"@esbuild/freebsd-x64@0.25.9":
|
||||
version "0.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz#7c869b45faeb3df668e19ace07335a0711ec56ab"
|
||||
integrity sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==
|
||||
|
||||
"@esbuild/linux-arm64@0.25.9":
|
||||
version "0.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz#48d42861758c940b61abea43ba9a29b186d6cb8b"
|
||||
integrity sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==
|
||||
|
||||
"@esbuild/linux-arm@0.25.9":
|
||||
version "0.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz#6ce4b9cabf148274101701d112b89dc67cc52f37"
|
||||
integrity sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==
|
||||
|
||||
"@esbuild/linux-ia32@0.25.9":
|
||||
version "0.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz#207e54899b79cac9c26c323fc1caa32e3143f1c4"
|
||||
integrity sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==
|
||||
|
||||
"@esbuild/linux-loong64@0.25.9":
|
||||
version "0.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz#0ba48a127159a8f6abb5827f21198b999ffd1fc0"
|
||||
integrity sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==
|
||||
|
||||
"@esbuild/linux-mips64el@0.25.9":
|
||||
version "0.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz#a4d4cc693d185f66a6afde94f772b38ce5d64eb5"
|
||||
integrity sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==
|
||||
|
||||
"@esbuild/linux-ppc64@0.25.9":
|
||||
version "0.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz#0f5805c1c6d6435a1dafdc043cb07a19050357db"
|
||||
integrity sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==
|
||||
|
||||
"@esbuild/linux-riscv64@0.25.9":
|
||||
version "0.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz#6776edece0f8fca79f3386398b5183ff2a827547"
|
||||
integrity sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==
|
||||
|
||||
"@esbuild/linux-s390x@0.25.9":
|
||||
version "0.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz#3f6f29ef036938447c2218d309dc875225861830"
|
||||
integrity sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==
|
||||
|
||||
"@esbuild/linux-x64@0.25.9":
|
||||
version "0.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz#831fe0b0e1a80a8b8391224ea2377d5520e1527f"
|
||||
integrity sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==
|
||||
|
||||
"@esbuild/netbsd-arm64@0.25.9":
|
||||
version "0.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz#06f99d7eebe035fbbe43de01c9d7e98d2a0aa548"
|
||||
integrity sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==
|
||||
|
||||
"@esbuild/netbsd-x64@0.25.9":
|
||||
version "0.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz#db99858e6bed6e73911f92a88e4edd3a8c429a52"
|
||||
integrity sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==
|
||||
|
||||
"@esbuild/openbsd-arm64@0.25.9":
|
||||
version "0.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz#afb886c867e36f9d86bb21e878e1185f5d5a0935"
|
||||
integrity sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==
|
||||
|
||||
"@esbuild/openbsd-x64@0.25.9":
|
||||
version "0.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz#30855c9f8381fac6a0ef5b5f31ac6e7108a66ecf"
|
||||
integrity sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==
|
||||
|
||||
"@esbuild/openharmony-arm64@0.25.9":
|
||||
version "0.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz#2f2144af31e67adc2a8e3705c20c2bd97bd88314"
|
||||
integrity sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==
|
||||
|
||||
"@esbuild/sunos-x64@0.25.9":
|
||||
version "0.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz#69b99a9b5bd226c9eb9c6a73f990fddd497d732e"
|
||||
integrity sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==
|
||||
|
||||
"@esbuild/win32-arm64@0.25.9":
|
||||
version "0.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz#d789330a712af916c88325f4ffe465f885719c6b"
|
||||
integrity sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==
|
||||
|
||||
"@esbuild/win32-ia32@0.25.9":
|
||||
version "0.25.9"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz#52fc735406bd49688253e74e4e837ac2ba0789e3"
|
||||
integrity sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==
|
||||
|
||||
"@esbuild/win32-x64@0.25.9":
|
||||
version "0.25.9"
|
||||
resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz"
|
||||
@@ -226,7 +373,7 @@
|
||||
minimatch "^3.1.2"
|
||||
strip-json-comments "^3.1.1"
|
||||
|
||||
"@eslint/js@^9.32.0", "@eslint/js@9.33.0":
|
||||
"@eslint/js@9.33.0", "@eslint/js@^9.32.0":
|
||||
version "9.33.0"
|
||||
resolved "https://registry.npmjs.org/@eslint/js/-/js-9.33.0.tgz"
|
||||
integrity sha512-5K1/mKhWaMfreBGJTwval43JJmkip0RmM+3+IuqupeSKNC/Th2Kc7ucaq5ovTSra/OOKB9c58CGSz3QMVbWt0A==
|
||||
@@ -249,7 +396,7 @@
|
||||
resolved "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-7.0.0.tgz"
|
||||
integrity sha512-PGMrIYXLGA5K8RWy8zwBkd4vFi4z7ubxtet6Yn13Plf6krRTwPbdlCwlcfmoX0R7B4Z643QvrtHmdQ5fNtfFCg==
|
||||
|
||||
"@fortawesome/fontawesome-svg-core@^7.0.0", "@fortawesome/fontawesome-svg-core@~1 || ~6 || ~7":
|
||||
"@fortawesome/fontawesome-svg-core@^7.0.0":
|
||||
version "7.0.0"
|
||||
resolved "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-7.0.0.tgz"
|
||||
integrity sha512-obBEF+zd98r/KtKVW6A+8UGWeaOoyMpl6Q9P3FzHsOnsg742aXsl8v+H/zp09qSSu/a/Hxe9LNKzbBaQq1CEbA==
|
||||
@@ -345,6 +492,15 @@
|
||||
"@jridgewell/resolve-uri" "^3.1.0"
|
||||
"@jridgewell/sourcemap-codec" "^1.4.14"
|
||||
|
||||
"@napi-rs/wasm-runtime@^0.2.11":
|
||||
version "0.2.12"
|
||||
resolved "https://registry.yarnpkg.com/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz#3e78a8b96e6c33a6c517e1894efbd5385a7cb6f2"
|
||||
integrity sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==
|
||||
dependencies:
|
||||
"@emnapi/core" "^1.4.3"
|
||||
"@emnapi/runtime" "^1.4.3"
|
||||
"@tybys/wasm-util" "^0.10.0"
|
||||
|
||||
"@nodelib/fs.scandir@2.1.5":
|
||||
version "2.1.5"
|
||||
resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz"
|
||||
@@ -353,7 +509,7 @@
|
||||
"@nodelib/fs.stat" "2.0.5"
|
||||
run-parallel "^1.1.9"
|
||||
|
||||
"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5":
|
||||
"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
|
||||
version "2.0.5"
|
||||
resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz"
|
||||
integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
|
||||
@@ -371,6 +527,101 @@
|
||||
resolved "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz"
|
||||
integrity sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==
|
||||
|
||||
"@rollup/rollup-android-arm-eabi@4.46.2":
|
||||
version "4.46.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.46.2.tgz#292e25953d4988d3bd1af0f5ebbd5ee4d65c90b4"
|
||||
integrity sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA==
|
||||
|
||||
"@rollup/rollup-android-arm64@4.46.2":
|
||||
version "4.46.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.46.2.tgz#053b3def3451e6fc1a9078188f22799e868d7c59"
|
||||
integrity sha512-nTeCWY83kN64oQ5MGz3CgtPx8NSOhC5lWtsjTs+8JAJNLcP3QbLCtDDgUKQc/Ro/frpMq4SHUaHN6AMltcEoLQ==
|
||||
|
||||
"@rollup/rollup-darwin-arm64@4.46.2":
|
||||
version "4.46.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.46.2.tgz#98d90445282dec54fd05440305a5e8df79a91ece"
|
||||
integrity sha512-HV7bW2Fb/F5KPdM/9bApunQh68YVDU8sO8BvcW9OngQVN3HHHkw99wFupuUJfGR9pYLLAjcAOA6iO+evsbBaPQ==
|
||||
|
||||
"@rollup/rollup-darwin-x64@4.46.2":
|
||||
version "4.46.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.46.2.tgz#fe05f95a736423af5f9c3a59a70f41ece52a1f20"
|
||||
integrity sha512-SSj8TlYV5nJixSsm/y3QXfhspSiLYP11zpfwp6G/YDXctf3Xkdnk4woJIF5VQe0of2OjzTt8EsxnJDCdHd2xMA==
|
||||
|
||||
"@rollup/rollup-freebsd-arm64@4.46.2":
|
||||
version "4.46.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.46.2.tgz#41e1fbdc1f8c3dc9afb6bc1d6e3fb3104bd81eee"
|
||||
integrity sha512-ZyrsG4TIT9xnOlLsSSi9w/X29tCbK1yegE49RYm3tu3wF1L/B6LVMqnEWyDB26d9Ecx9zrmXCiPmIabVuLmNSg==
|
||||
|
||||
"@rollup/rollup-freebsd-x64@4.46.2":
|
||||
version "4.46.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.46.2.tgz#69131e69cb149d547abb65ef3b38fc746c940e24"
|
||||
integrity sha512-pCgHFoOECwVCJ5GFq8+gR8SBKnMO+xe5UEqbemxBpCKYQddRQMgomv1104RnLSg7nNvgKy05sLsY51+OVRyiVw==
|
||||
|
||||
"@rollup/rollup-linux-arm-gnueabihf@4.46.2":
|
||||
version "4.46.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.46.2.tgz#977ded91c7cf6fc0d9443bb9c0a064e45a805267"
|
||||
integrity sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==
|
||||
|
||||
"@rollup/rollup-linux-arm-musleabihf@4.46.2":
|
||||
version "4.46.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.46.2.tgz#dc034fc3c0f0eb5c75b6bc3eca3b0b97fd35f49a"
|
||||
integrity sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==
|
||||
|
||||
"@rollup/rollup-linux-arm64-gnu@4.46.2":
|
||||
version "4.46.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.46.2.tgz#5e92613768d3de3ffcabc965627dd0a59b3e7dfc"
|
||||
integrity sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==
|
||||
|
||||
"@rollup/rollup-linux-arm64-musl@4.46.2":
|
||||
version "4.46.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.46.2.tgz#2a44f88e83d28b646591df6e50aa0a5a931833d8"
|
||||
integrity sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==
|
||||
|
||||
"@rollup/rollup-linux-loongarch64-gnu@4.46.2":
|
||||
version "4.46.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.46.2.tgz#bd5897e92db7fbf7dc456f61d90fff96c4651f2e"
|
||||
integrity sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==
|
||||
|
||||
"@rollup/rollup-linux-ppc64-gnu@4.46.2":
|
||||
version "4.46.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.46.2.tgz#a7065025411c14ad9ec34cc1cd1414900ec2a303"
|
||||
integrity sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==
|
||||
|
||||
"@rollup/rollup-linux-riscv64-gnu@4.46.2":
|
||||
version "4.46.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.46.2.tgz#17f9c0c675e13ef4567cfaa3730752417257ccc3"
|
||||
integrity sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==
|
||||
|
||||
"@rollup/rollup-linux-riscv64-musl@4.46.2":
|
||||
version "4.46.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.46.2.tgz#bc6ed3db2cedc1ba9c0a2183620fe2f792c3bf3f"
|
||||
integrity sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==
|
||||
|
||||
"@rollup/rollup-linux-s390x-gnu@4.46.2":
|
||||
version "4.46.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.46.2.tgz#440c4f6753274e2928e06d2a25613e5a1cf97b41"
|
||||
integrity sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==
|
||||
|
||||
"@rollup/rollup-linux-x64-gnu@4.46.2":
|
||||
version "4.46.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.46.2.tgz#1e936446f90b2574ea4a83b4842a762cc0a0aed3"
|
||||
integrity sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==
|
||||
|
||||
"@rollup/rollup-linux-x64-musl@4.46.2":
|
||||
version "4.46.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.46.2.tgz#c6f304dfba1d5faf2be5d8b153ccbd8b5d6f1166"
|
||||
integrity sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==
|
||||
|
||||
"@rollup/rollup-win32-arm64-msvc@4.46.2":
|
||||
version "4.46.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.46.2.tgz#b4ad4a79219892aac112ed1c9d1356cad0566ef5"
|
||||
integrity sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g==
|
||||
|
||||
"@rollup/rollup-win32-ia32-msvc@4.46.2":
|
||||
version "4.46.2"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.46.2.tgz#b1b22eb2a9568048961e4a6f540438b4a762aa62"
|
||||
integrity sha512-gBgaUDESVzMgWZhcyjfs9QFK16D8K6QZpwAaVNJxYDLHWayOta4ZMjGm/vsAEy3hvlS2GosVFlBlP9/Wb85DqQ==
|
||||
|
||||
"@rollup/rollup-win32-x64-msvc@4.46.2":
|
||||
version "4.46.2"
|
||||
resolved "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.46.2.tgz"
|
||||
@@ -389,6 +640,68 @@
|
||||
source-map-js "^1.2.1"
|
||||
tailwindcss "4.1.11"
|
||||
|
||||
"@tailwindcss/oxide-android-arm64@4.1.11":
|
||||
version "4.1.11"
|
||||
resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.11.tgz#1f387d8302f011b61c226deb0c3a1d2bd79c6915"
|
||||
integrity sha512-3IfFuATVRUMZZprEIx9OGDjG3Ou3jG4xQzNTvjDoKmU9JdmoCohQJ83MYd0GPnQIu89YoJqvMM0G3uqLRFtetg==
|
||||
|
||||
"@tailwindcss/oxide-darwin-arm64@4.1.11":
|
||||
version "4.1.11"
|
||||
resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.11.tgz#acd35ffb7e4eae83d0a3fe2f8ea36cfcc9b21f7e"
|
||||
integrity sha512-ESgStEOEsyg8J5YcMb1xl8WFOXfeBmrhAwGsFxxB2CxY9evy63+AtpbDLAyRkJnxLy2WsD1qF13E97uQyP1lfQ==
|
||||
|
||||
"@tailwindcss/oxide-darwin-x64@4.1.11":
|
||||
version "4.1.11"
|
||||
resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.11.tgz#a0022312993a3893d6ff0312d6e3c83c4636fef4"
|
||||
integrity sha512-EgnK8kRchgmgzG6jE10UQNaH9Mwi2n+yw1jWmof9Vyg2lpKNX2ioe7CJdf9M5f8V9uaQxInenZkOxnTVL3fhAw==
|
||||
|
||||
"@tailwindcss/oxide-freebsd-x64@4.1.11":
|
||||
version "4.1.11"
|
||||
resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.11.tgz#dd8e55eb0b88fe7995b8148c0e0ae5fa27092d22"
|
||||
integrity sha512-xdqKtbpHs7pQhIKmqVpxStnY1skuNh4CtbcyOHeX1YBE0hArj2romsFGb6yUmzkq/6M24nkxDqU8GYrKrz+UcA==
|
||||
|
||||
"@tailwindcss/oxide-linux-arm-gnueabihf@4.1.11":
|
||||
version "4.1.11"
|
||||
resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.11.tgz#02ee99090988847d3f13d277679012cbffcdde37"
|
||||
integrity sha512-ryHQK2eyDYYMwB5wZL46uoxz2zzDZsFBwfjssgB7pzytAeCCa6glsiJGjhTEddq/4OsIjsLNMAiMlHNYnkEEeg==
|
||||
|
||||
"@tailwindcss/oxide-linux-arm64-gnu@4.1.11":
|
||||
version "4.1.11"
|
||||
resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.11.tgz#4837559c102bebe65089879f6a0278ed473b4813"
|
||||
integrity sha512-mYwqheq4BXF83j/w75ewkPJmPZIqqP1nhoghS9D57CLjsh3Nfq0m4ftTotRYtGnZd3eCztgbSPJ9QhfC91gDZQ==
|
||||
|
||||
"@tailwindcss/oxide-linux-arm64-musl@4.1.11":
|
||||
version "4.1.11"
|
||||
resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.11.tgz#bec465112a13a1383558ff36afdf28b8a8cb9021"
|
||||
integrity sha512-m/NVRFNGlEHJrNVk3O6I9ggVuNjXHIPoD6bqay/pubtYC9QIdAMpS+cswZQPBLvVvEF6GtSNONbDkZrjWZXYNQ==
|
||||
|
||||
"@tailwindcss/oxide-linux-x64-gnu@4.1.11":
|
||||
version "4.1.11"
|
||||
resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.11.tgz#f9e47e6aa67ff77f32f7412bc9698d4278e101bf"
|
||||
integrity sha512-YW6sblI7xukSD2TdbbaeQVDysIm/UPJtObHJHKxDEcW2exAtY47j52f8jZXkqE1krdnkhCMGqP3dbniu1Te2Fg==
|
||||
|
||||
"@tailwindcss/oxide-linux-x64-musl@4.1.11":
|
||||
version "4.1.11"
|
||||
resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.11.tgz#7d6e8adcfb9bc84d8e2e2e8781d661edb9e41ba8"
|
||||
integrity sha512-e3C/RRhGunWYNC3aSF7exsQkdXzQ/M+aYuZHKnw4U7KQwTJotnWsGOIVih0s2qQzmEzOFIJ3+xt7iq67K/p56Q==
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi@4.1.11":
|
||||
version "4.1.11"
|
||||
resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.11.tgz#a1762f4939c6ebaa824696fda2fd7db1b85fbed2"
|
||||
integrity sha512-Xo1+/GU0JEN/C/dvcammKHzeM6NqKovG+6921MR6oadee5XPBaKOumrJCXvopJ/Qb5TH7LX/UAywbqrP4lax0g==
|
||||
dependencies:
|
||||
"@emnapi/core" "^1.4.3"
|
||||
"@emnapi/runtime" "^1.4.3"
|
||||
"@emnapi/wasi-threads" "^1.0.2"
|
||||
"@napi-rs/wasm-runtime" "^0.2.11"
|
||||
"@tybys/wasm-util" "^0.9.0"
|
||||
tslib "^2.8.0"
|
||||
|
||||
"@tailwindcss/oxide-win32-arm64-msvc@4.1.11":
|
||||
version "4.1.11"
|
||||
resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.11.tgz#70ba392dca0fa3707ebe27d2bd6ac3e69d35e3b7"
|
||||
integrity sha512-UgKYx5PwEKrac3GPNPf6HVMNhUIGuUh4wlDFR2jYYdkX6pL/rn73zTq/4pzUm8fOjAn5L8zDeHp9iXmUGOXZ+w==
|
||||
|
||||
"@tailwindcss/oxide-win32-x64-msvc@4.1.11":
|
||||
version "4.1.11"
|
||||
resolved "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.11.tgz"
|
||||
@@ -436,6 +749,20 @@
|
||||
dependencies:
|
||||
"@tanstack/query-core" "5.85.2"
|
||||
|
||||
"@tybys/wasm-util@^0.10.0":
|
||||
version "0.10.1"
|
||||
resolved "https://registry.yarnpkg.com/@tybys/wasm-util/-/wasm-util-0.10.1.tgz#ecddd3205cf1e2d5274649ff0eedd2991ed7f414"
|
||||
integrity sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==
|
||||
dependencies:
|
||||
tslib "^2.4.0"
|
||||
|
||||
"@tybys/wasm-util@^0.9.0":
|
||||
version "0.9.0"
|
||||
resolved "https://registry.yarnpkg.com/@tybys/wasm-util/-/wasm-util-0.9.0.tgz#3e75eb00604c8d6db470bf18c37b7d984a0e3355"
|
||||
integrity sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==
|
||||
dependencies:
|
||||
tslib "^2.4.0"
|
||||
|
||||
"@types/babel__core@^7.20.5":
|
||||
version "7.20.5"
|
||||
resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz"
|
||||
@@ -469,7 +796,7 @@
|
||||
dependencies:
|
||||
"@babel/types" "^7.28.2"
|
||||
|
||||
"@types/estree@^1.0.6", "@types/estree@1.0.8":
|
||||
"@types/estree@1.0.8", "@types/estree@^1.0.6":
|
||||
version "1.0.8"
|
||||
resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz"
|
||||
integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==
|
||||
@@ -491,7 +818,7 @@
|
||||
resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz"
|
||||
integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
|
||||
|
||||
"@types/node@^20.19.0 || >=22.12.0", "@types/node@^25.0.1":
|
||||
"@types/node@^25.0.1":
|
||||
version "25.0.1"
|
||||
resolved "https://registry.npmjs.org/@types/node/-/node-25.0.1.tgz"
|
||||
integrity sha512-czWPzKIAXucn9PtsttxmumiQ9N0ok9FrBwgRWrwmVLlp86BrMExzvXRLFYRJ+Ex3g6yqj+KuaxfX1JTgV2lpfg==
|
||||
@@ -510,7 +837,7 @@
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react@*", "@types/react@^19.0.0", "@types/react@^19.1.9":
|
||||
"@types/react@*", "@types/react@^19.1.9":
|
||||
version "19.1.10"
|
||||
resolved "https://registry.npmjs.org/@types/react/-/react-19.1.10.tgz"
|
||||
integrity sha512-EhBeSYX0Y6ye8pNebpKrwFJq7BoQ8J5SO6NlvNwwHjSj6adXJViPQrKlsyPw7hLBLvckEMO1yxeGdR82YBBlDg==
|
||||
@@ -532,7 +859,7 @@
|
||||
natural-compare "^1.4.0"
|
||||
ts-api-utils "^2.1.0"
|
||||
|
||||
"@typescript-eslint/parser@^8.39.1", "@typescript-eslint/parser@8.39.1":
|
||||
"@typescript-eslint/parser@8.39.1":
|
||||
version "8.39.1"
|
||||
resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.39.1.tgz"
|
||||
integrity sha512-pUXGCuHnnKw6PyYq93lLRiZm3vjuslIy7tus1lIQTYVK9bL8XBgJnCWm8a0KcTtHC84Yya1Q6rtll+duSMj0dg==
|
||||
@@ -560,7 +887,7 @@
|
||||
"@typescript-eslint/types" "8.39.1"
|
||||
"@typescript-eslint/visitor-keys" "8.39.1"
|
||||
|
||||
"@typescript-eslint/tsconfig-utils@^8.39.1", "@typescript-eslint/tsconfig-utils@8.39.1":
|
||||
"@typescript-eslint/tsconfig-utils@8.39.1", "@typescript-eslint/tsconfig-utils@^8.39.1":
|
||||
version "8.39.1"
|
||||
resolved "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.39.1.tgz"
|
||||
integrity sha512-ePUPGVtTMR8XMU2Hee8kD0Pu4NDE1CN9Q1sxGSGd/mbOtGZDM7pnhXNJnzW63zk/q+Z54zVzj44HtwXln5CvHA==
|
||||
@@ -576,7 +903,7 @@
|
||||
debug "^4.3.4"
|
||||
ts-api-utils "^2.1.0"
|
||||
|
||||
"@typescript-eslint/types@^8.39.1", "@typescript-eslint/types@8.39.1":
|
||||
"@typescript-eslint/types@8.39.1", "@typescript-eslint/types@^8.39.1":
|
||||
version "8.39.1"
|
||||
resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.39.1.tgz"
|
||||
integrity sha512-7sPDKQQp+S11laqTrhHqeAbsCfMkwJMrV7oTDvtDds4mEofJYir414bYKUEb8YPUm9QL3U+8f6L6YExSoAGdQw==
|
||||
@@ -637,7 +964,7 @@ acorn-jsx@^5.3.2:
|
||||
resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz"
|
||||
integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
|
||||
|
||||
"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8.15.0:
|
||||
acorn@^8.15.0:
|
||||
version "8.15.0"
|
||||
resolved "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz"
|
||||
integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==
|
||||
@@ -691,7 +1018,7 @@ braces@^3.0.3:
|
||||
dependencies:
|
||||
fill-range "^7.1.1"
|
||||
|
||||
browserslist@^4.24.0, "browserslist@>= 4.21.0":
|
||||
browserslist@^4.24.0:
|
||||
version "4.25.2"
|
||||
resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.25.2.tgz"
|
||||
integrity sha512-0si2SJK3ooGzIawRu61ZdPCO1IncZwS8IzuX73sPZsXW6EQ/w/DAfPyKI8l1ETTCr2MnvqWitmlCUxgdul45jA==
|
||||
@@ -914,7 +1241,7 @@ eslint-visitor-keys@^4.2.1:
|
||||
resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz"
|
||||
integrity sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==
|
||||
|
||||
"eslint@^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0", "eslint@^6.0.0 || ^7.0.0 || >=8.0.0", "eslint@^8.57.0 || ^9.0.0", eslint@^9.32.0, eslint@>=8.40:
|
||||
eslint@^9.32.0:
|
||||
version "9.33.0"
|
||||
resolved "https://registry.npmjs.org/eslint/-/eslint-9.33.0.tgz"
|
||||
integrity sha512-TS9bTNIryDzStCpJN93aC5VRSW3uTx9sClUn4B87pwiCaJh220otoI0X8mJKr+VcPtniMdN8GKjlwgWGUv5ZKA==
|
||||
@@ -1090,6 +1417,11 @@ formik@^2.4.6:
|
||||
tiny-warning "^1.0.2"
|
||||
tslib "^2.0.0"
|
||||
|
||||
fsevents@~2.3.2, fsevents@~2.3.3:
|
||||
version "2.3.3"
|
||||
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
|
||||
integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
|
||||
|
||||
gensync@^1.0.0-beta.2:
|
||||
version "1.0.0-beta.2"
|
||||
resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz"
|
||||
@@ -1203,7 +1535,7 @@ isexe@^2.0.0:
|
||||
resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz"
|
||||
integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
|
||||
|
||||
jiti@*, jiti@^2.4.2, jiti@>=1.21.0:
|
||||
jiti@^2.4.2:
|
||||
version "2.5.1"
|
||||
resolved "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz"
|
||||
integrity sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==
|
||||
@@ -1265,12 +1597,57 @@ levn@^0.4.1:
|
||||
prelude-ls "^1.2.1"
|
||||
type-check "~0.4.0"
|
||||
|
||||
lightningcss-darwin-arm64@1.30.1:
|
||||
version "1.30.1"
|
||||
resolved "https://registry.yarnpkg.com/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz#3d47ce5e221b9567c703950edf2529ca4a3700ae"
|
||||
integrity sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==
|
||||
|
||||
lightningcss-darwin-x64@1.30.1:
|
||||
version "1.30.1"
|
||||
resolved "https://registry.yarnpkg.com/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz#e81105d3fd6330860c15fe860f64d39cff5fbd22"
|
||||
integrity sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==
|
||||
|
||||
lightningcss-freebsd-x64@1.30.1:
|
||||
version "1.30.1"
|
||||
resolved "https://registry.yarnpkg.com/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz#a0e732031083ff9d625c5db021d09eb085af8be4"
|
||||
integrity sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==
|
||||
|
||||
lightningcss-linux-arm-gnueabihf@1.30.1:
|
||||
version "1.30.1"
|
||||
resolved "https://registry.yarnpkg.com/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz#1f5ecca6095528ddb649f9304ba2560c72474908"
|
||||
integrity sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==
|
||||
|
||||
lightningcss-linux-arm64-gnu@1.30.1:
|
||||
version "1.30.1"
|
||||
resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz#eee7799726103bffff1e88993df726f6911ec009"
|
||||
integrity sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==
|
||||
|
||||
lightningcss-linux-arm64-musl@1.30.1:
|
||||
version "1.30.1"
|
||||
resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz#f2e4b53f42892feeef8f620cbb889f7c064a7dfe"
|
||||
integrity sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==
|
||||
|
||||
lightningcss-linux-x64-gnu@1.30.1:
|
||||
version "1.30.1"
|
||||
resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz#2fc7096224bc000ebb97eea94aea248c5b0eb157"
|
||||
integrity sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==
|
||||
|
||||
lightningcss-linux-x64-musl@1.30.1:
|
||||
version "1.30.1"
|
||||
resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz#66dca2b159fd819ea832c44895d07e5b31d75f26"
|
||||
integrity sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==
|
||||
|
||||
lightningcss-win32-arm64-msvc@1.30.1:
|
||||
version "1.30.1"
|
||||
resolved "https://registry.yarnpkg.com/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz#7d8110a19d7c2d22bfdf2f2bb8be68e7d1b69039"
|
||||
integrity sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==
|
||||
|
||||
lightningcss-win32-x64-msvc@1.30.1:
|
||||
version "1.30.1"
|
||||
resolved "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz"
|
||||
integrity sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==
|
||||
|
||||
lightningcss@^1.21.0, lightningcss@1.30.1:
|
||||
lightningcss@1.30.1:
|
||||
version "1.30.1"
|
||||
resolved "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz"
|
||||
integrity sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==
|
||||
@@ -1472,7 +1849,7 @@ picomatch@^2.3.1:
|
||||
resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz"
|
||||
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
|
||||
|
||||
"picomatch@^3 || ^4", picomatch@^4.0.2, picomatch@^4.0.3:
|
||||
picomatch@^4.0.2, picomatch@^4.0.3:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz"
|
||||
integrity sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==
|
||||
@@ -1527,7 +1904,7 @@ rc-util@^5.36.0:
|
||||
"@babel/runtime" "^7.18.3"
|
||||
react-is "^18.2.0"
|
||||
|
||||
react-dom@*, "react-dom@^0.14.0 || ^15.0.0 || ^16 || ^17 || ^18 || ^19", "react-dom@^18.0.0 || ^19.0.0 || ^19.0.0-rc", react-dom@^19.1.1, react-dom@>=16.9.0, react-dom@>=18:
|
||||
react-dom@^19.1.1:
|
||||
version "19.1.1"
|
||||
resolved "https://registry.npmjs.org/react-dom/-/react-dom-19.1.1.tgz"
|
||||
integrity sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==
|
||||
@@ -1602,6 +1979,11 @@ react-universal-interface@^0.6.2:
|
||||
resolved "https://registry.npmjs.org/react-universal-interface/-/react-universal-interface-0.6.2.tgz"
|
||||
integrity sha512-dg8yXdcQmvgR13RIlZbTRQOoUrDciFVoSBZILwjE2LFISxZZ8loVJKAkuzswl5js8BHda79bIb2b84ehU8IjXw==
|
||||
|
||||
react-use-websocket@^4.13.0:
|
||||
version "4.13.0"
|
||||
resolved "https://registry.yarnpkg.com/react-use-websocket/-/react-use-websocket-4.13.0.tgz#9db1dbac6dc8ba2fdc02a5bba06205fbf6406736"
|
||||
integrity sha512-anMuVoV//g2N76Wxqvqjjo1X48r9Np3y1/gMl7arX84tAPXdy5R7sB5lO5hvCzQRYjqXwV8XMAiEBOUbyrZFrw==
|
||||
|
||||
react-use@^17.6.0:
|
||||
version "17.6.0"
|
||||
resolved "https://registry.npmjs.org/react-use/-/react-use-17.6.0.tgz"
|
||||
@@ -1622,7 +2004,7 @@ react-use@^17.6.0:
|
||||
ts-easing "^0.2.0"
|
||||
tslib "^2.1.0"
|
||||
|
||||
react@*, "react@^0.14.0 || ^15.0.0 || ^16 || ^17 || ^18 || ^19", "react@^16.3 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.8.3 || ^17 || ^18 || ^19.0.0 || ^19.0.0-rc", "react@^18 || ^19", "react@^18.0.0 || ^19.0.0", "react@^18.0.0 || ^19.0.0 || ^19.0.0-rc", react@^19.1.1, react@>=16.8.0, react@>=16.9.0, react@>=18:
|
||||
react@^19.1.1:
|
||||
version "19.1.1"
|
||||
resolved "https://registry.npmjs.org/react/-/react-19.1.1.tgz"
|
||||
integrity sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==
|
||||
@@ -1737,16 +2119,16 @@ source-map-js@^1.2.1:
|
||||
resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz"
|
||||
integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==
|
||||
|
||||
source-map@^0.6.1:
|
||||
version "0.6.1"
|
||||
resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz"
|
||||
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
|
||||
|
||||
source-map@0.5.6:
|
||||
version "0.5.6"
|
||||
resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz"
|
||||
integrity sha512-MjZkVp0NHr5+TPihLcadqnlVoGIoWo4IBHptutGh9wI3ttUYvCG26HkSuDi+K6lsZ25syXJXcctwgyVCt//xqA==
|
||||
|
||||
source-map@^0.6.1:
|
||||
version "0.6.1"
|
||||
resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz"
|
||||
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
|
||||
|
||||
stack-generator@^2.0.5:
|
||||
version "2.0.10"
|
||||
resolved "https://registry.npmjs.org/stack-generator/-/stack-generator-2.0.10.tgz"
|
||||
@@ -1793,7 +2175,7 @@ supports-color@^7.1.0:
|
||||
dependencies:
|
||||
has-flag "^4.0.0"
|
||||
|
||||
tailwindcss@^4.1.11, tailwindcss@4.1.11:
|
||||
tailwindcss@4.1.11, tailwindcss@^4.1.11:
|
||||
version "4.1.11"
|
||||
resolved "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.11.tgz"
|
||||
integrity sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA==
|
||||
@@ -1855,9 +2237,9 @@ ts-easing@^0.2.0:
|
||||
resolved "https://registry.npmjs.org/ts-easing/-/ts-easing-0.2.0.tgz"
|
||||
integrity sha512-Z86EW+fFFh/IFB1fqQ3/+7Zpf9t2ebOAxNI/V6Wo7r5gqiqtxmgTlQ1qbqQcjLKYeSHPTsEmvlJUDg/EuL0uHQ==
|
||||
|
||||
tslib@*, tslib@^2.0.0, tslib@^2.1.0:
|
||||
tslib@^2.0.0, tslib@^2.1.0, tslib@^2.4.0, tslib@^2.8.0:
|
||||
version "2.8.1"
|
||||
resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f"
|
||||
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
|
||||
|
||||
type-check@^0.4.0, type-check@~0.4.0:
|
||||
@@ -1877,7 +2259,7 @@ typescript-eslint@^8.39.0:
|
||||
"@typescript-eslint/typescript-estree" "8.39.1"
|
||||
"@typescript-eslint/utils" "8.39.1"
|
||||
|
||||
typescript@>=4.8.4, "typescript@>=4.8.4 <6.0.0", typescript@~5.8.3:
|
||||
typescript@~5.8.3:
|
||||
version "5.8.3"
|
||||
resolved "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz"
|
||||
integrity sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==
|
||||
@@ -1907,7 +2289,7 @@ use-debounce@^10.0.6:
|
||||
resolved "https://registry.npmjs.org/use-debounce/-/use-debounce-10.0.6.tgz"
|
||||
integrity sha512-C5OtPyhAZgVoteO9heXMTdW7v/IbFI+8bSVKYCJrSmiWWCLsbUxiBSp4t9v0hNBTGY97bT72ydDIDyGSFWfwXg==
|
||||
|
||||
"vite@^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0", "vite@^5.2.0 || ^6 || ^7", vite@^7.1.0:
|
||||
vite@^7.1.0:
|
||||
version "7.1.2"
|
||||
resolved "https://registry.npmjs.org/vite/-/vite-7.1.2.tgz"
|
||||
integrity sha512-J0SQBPlQiEXAF7tajiH+rUooJPo0l8KQgyg4/aMunNtrOa7bwuZJsJbDWzeljqQpgftxuq5yNJxQ91O9ts29UQ==
|
||||
|
||||
Reference in New Issue
Block a user