- minor big fixes

- default settings toggled
-update camera zoom need to test
This commit is contained in:
2025-11-04 13:38:06 +00:00
parent 76643cc84c
commit 61894c0c42
9 changed files with 43 additions and 51 deletions

View File

@@ -5,6 +5,7 @@ import { useCameraZoom } from "../../hooks/useCameraZoom";
import { useEffect } from "react"; import { useEffect } from "react";
import Loading from "../UI/Loading"; import Loading from "../UI/Loading";
import ErrorState from "../UI/ErrorState"; import ErrorState from "../UI/ErrorState";
import { zoomMapping } from "../../utils/utils";
type SnapshotContainerProps = { type SnapshotContainerProps = {
side: string; side: string;
@@ -13,20 +14,14 @@ type SnapshotContainerProps = {
onZoomLevelChange?: (level: number) => void; onZoomLevelChange?: (level: number) => void;
}; };
export const SnapshotContainer = ({ export const SnapshotContainer = ({ side, settingsPage, zoomLevel, onZoomLevelChange }: SnapshotContainerProps) => {
side,
settingsPage,
zoomLevel,
onZoomLevelChange,
}: SnapshotContainerProps) => {
const { canvasRef, isError, isPending } = useGetOverviewSnapshot(side); const { canvasRef, isError, isPending } = useGetOverviewSnapshot(side);
const cameraControllerSide = const cameraControllerSide = side === "CameraA" ? "CameraControllerA" : "CameraControllerB";
side === "CameraA" ? "CameraControllerA" : "CameraControllerB";
const { mutation } = useCameraZoom({ camera: cameraControllerSide }); const { mutation } = useCameraZoom({ camera: cameraControllerSide });
const handleZoomClick = () => { const handleZoomClick = () => {
const baseLevel = zoomLevel ?? 1; const baseLevel = zoomLevel ?? 1;
const newLevel = baseLevel >= 8 ? 1 : baseLevel * 2; const newLevel = baseLevel >= 4 ? 1 : baseLevel * 2;
if (onZoomLevelChange) onZoomLevelChange(newLevel); if (onZoomLevelChange) onZoomLevelChange(newLevel);
@@ -35,9 +30,11 @@ export const SnapshotContainer = ({
useEffect(() => { useEffect(() => {
if (zoomLevel) { if (zoomLevel) {
const text = zoomMapping(zoomLevel);
const zoomInOptions: ZoomInOptions = { const zoomInOptions: ZoomInOptions = {
camera: cameraControllerSide, camera: cameraControllerSide,
multiplier: zoomLevel, multiplier: zoomLevel,
multiplierText: text,
}; };
mutation.mutate(zoomInOptions); mutation.mutate(zoomInOptions);
} }

View File

@@ -5,7 +5,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faEye, faEyeSlash } from "@fortawesome/free-regular-svg-icons"; import { faEye, faEyeSlash } from "@fortawesome/free-regular-svg-icons";
import CardHeader from "../UI/CardHeader"; import CardHeader from "../UI/CardHeader";
import { useCameraZoom } from "../../hooks/useCameraZoom"; import { useCameraZoom } from "../../hooks/useCameraZoom";
import { parseRTSPUrl } from "../../utils/utils"; import { parseRTSPUrl, zoomMapping } from "../../utils/utils";
type CameraSettingsProps = { type CameraSettingsProps = {
initialData: CameraConfig; initialData: CameraConfig;
@@ -25,7 +25,12 @@ const CameraSettingFields = ({
const [showPwd, setShowPwd] = useState(false); const [showPwd, setShowPwd] = useState(false);
const cameraControllerSide = initialData?.id === "CameraA" ? "CameraControllerA" : "CameraControllerB"; const cameraControllerSide = initialData?.id === "CameraA" ? "CameraControllerA" : "CameraControllerB";
const { mutation, query } = useCameraZoom({ camera: cameraControllerSide }); const { mutation, query } = useCameraZoom({ camera: cameraControllerSide });
const zoomOptions = [1, 2, 4, 8]; const zoomOptions = [1, 2, 4];
// const zoomTextOptions = [
// { label: "near", value: 4 },
// { label: "medium", value: 2 },
// { label: "far", value: 1 },
// ];
const parsed = parseRTSPUrl(initialData?.propURI?.value); const parsed = parseRTSPUrl(initialData?.propURI?.value);
@@ -36,6 +41,7 @@ const CameraSettingFields = ({
}, [query?.data, onZoomLevelChange]); }, [query?.data, onZoomLevelChange]);
const getZoomLevel = (levelstring: string | undefined) => { const getZoomLevel = (levelstring: string | undefined) => {
console.log(levelstring);
switch (levelstring) { switch (levelstring) {
case "1x": case "1x":
return 1; return 1;
@@ -46,8 +52,6 @@ const CameraSettingFields = ({
case "4x": case "4x":
return 4; return 4;
case "8x":
return 8;
default: default:
return 1; return 1;
} }
@@ -80,11 +84,13 @@ const CameraSettingFields = ({
const handleRadioButtonChange = async (levelNumber: number) => { const handleRadioButtonChange = async (levelNumber: number) => {
if (!onZoomLevelChange || !zoomLevel) return; if (!onZoomLevelChange || !zoomLevel) return;
const text = zoomMapping(levelNumber);
onZoomLevelChange(levelNumber); onZoomLevelChange(levelNumber);
const zoomInOptions: ZoomInOptions = { const zoomInOptions: ZoomInOptions = {
camera: cameraControllerSide, camera: cameraControllerSide,
multiplier: levelNumber, multiplier: levelNumber,
multiplierText: text,
}; };
mutation.mutate(zoomInOptions); mutation.mutate(zoomInOptions);
@@ -169,7 +175,7 @@ const CameraSettingFields = ({
</div> </div>
<div className="my-3"> <div className="my-3">
<CardHeader title="Zoom settings" /> <CardHeader title="Zoom settings" />
<div className="mx-auto grid grid-cols-4 items-center"> <div className="mx-auto grid grid-cols-3 place-items-center">
{zoomOptions.map((zoom) => ( {zoomOptions.map((zoom) => (
<div key={zoom} className="my-3"> <div key={zoom} className="my-3">
<Field <Field
@@ -187,7 +193,7 @@ const CameraSettingFields = ({
peer-checked:border-2 peer-checked:border-blue-900 peer-checked:border-2 peer-checked:border-blue-900
peer-checked:text-blue-600 peer-checked:bg-gray-100" peer-checked:text-blue-600 peer-checked:bg-gray-100"
> >
x{zoom} {zoomMapping(zoom)}
</label> </label>
</div> </div>
))} ))}

View File

@@ -40,9 +40,7 @@ const NumberPlate = ({ motion, vrm, size }: NumberPlateProps) => {
return ( return (
<div <div
className={`relative ${options.plateWidth} ${ className={`relative ${options.plateWidth} ${options.borderWidth} border-black rounded-xl text-nowrap
options.borderWidth
} border-black rounded-xl text-nowrap
text-black px-6 py-2 text-black px-6 py-2
${motion ? "bg-yellow-400" : "bg-white"}`} ${motion ? "bg-yellow-400" : "bg-white"}`}
> >
@@ -50,9 +48,7 @@ const NumberPlate = ({ motion, vrm, size }: NumberPlateProps) => {
<div className="absolute inset-y-0 left-0 bg-blue-600 w-8 flex flex-col"> <div className="absolute inset-y-0 left-0 bg-blue-600 w-8 flex flex-col">
<GB /> <GB />
</div> </div>
<p className={`pl-4 font-extrabold ${options.textSize} text-right`}> <p className={`pl-4 font-extrabold ${options.textSize} text-right`}>{vrm && formatNumberPlate(vrm)}</p>
{vrm && formatNumberPlate(vrm)}
</p>
</div> </div>
</div> </div>
); );

View File

@@ -58,9 +58,7 @@ const ChannelFields = ({ touched, isSubmitting, format }: ChannelFieldsProps) =>
type="text" type="text"
id="backoffice" id="backoffice"
placeholder="https://www.backoffice.com" placeholder="https://www.backoffice.com"
className={`p-1.5 border ${ className={`p-1.5 border border-gray-400 rounded-lg w-full md:w-60`}
errors.backOfficeURL && touched.backOfficeURL ? "border-red-500" : "border-gray-400 "
} rounded-lg w-full md:w-60`}
/> />
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
@@ -70,9 +68,7 @@ const ChannelFields = ({ touched, isSubmitting, format }: ChannelFieldsProps) =>
type="text" type="text"
id="username" id="username"
placeholder="Back office username" placeholder="Back office username"
className={`p-1.5 border ${ className={`p-1.5 border border-gray-400 rounded-lg w-full md:w-60`}
errors.username && touched.username ? "border-red-500" : "border-gray-400 "
} rounded-lg w-full md:w-60`}
/> />
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
@@ -159,7 +155,6 @@ const ChannelFields = ({ touched, isSubmitting, format }: ChannelFieldsProps) =>
id="timestampSource" id="timestampSource"
className="p-2 border border-gray-400 rounded-lg text-white bg-[#253445] w-full md:w-60" className="p-2 border border-gray-400 rounded-lg text-white bg-[#253445] w-full md:w-60"
> >
<option value="">-- Select format --</option>
<option value={"UTC"}>UTC</option> <option value={"UTC"}>UTC</option>
<option value={"local"}>Local</option> <option value={"local"}>Local</option>
</Field> </Field>
@@ -172,9 +167,8 @@ const ChannelFields = ({ touched, isSubmitting, format }: ChannelFieldsProps) =>
id="GPSFormat" id="GPSFormat"
className="p-2 border border-gray-400 rounded-lg text-white bg-[#253445] w-full md:w-60" className="p-2 border border-gray-400 rounded-lg text-white bg-[#253445] w-full md:w-60"
> >
<option value="">-- Select format --</option>
<option value={"Decimal Degrees"}>Decimal degrees</option>
<option value={"Minutes"}>Minutes</option> <option value={"Minutes"}>Minutes</option>
<option value={"Decimal Degrees"}>Decimal degrees</option>
</Field> </Field>
</FormGroup> </FormGroup>
</> </>

View File

@@ -46,16 +46,6 @@ const SettingForms = () => {
const validateValues = (values: InitialValuesForm): InitialValuesFormErrors => { const validateValues = (values: InitialValuesForm): InitialValuesFormErrors => {
const errors: InitialValuesFormErrors = {}; const errors: InitialValuesFormErrors = {};
const url = values.backOfficeURL?.trim();
const username = values.username?.trim();
const password = values.password?.trim();
if (!url) {
errors.backOfficeURL = "Required";
}
if (!username) errors.username = "Required";
if (!password) errors.password = "Required";
const read = Number(values.readTimeoutSeconds); const read = Number(values.readTimeoutSeconds);
if (!Number.isFinite(read)) { if (!Number.isFinite(read)) {
errors.readTimeoutSeconds = "Must be a number"; errors.readTimeoutSeconds = "Must be a number";

View File

@@ -38,7 +38,7 @@ const NavigationArrow = ({ side, settingsPage }: NavigationArrowProps) => {
icon={faArrowLeft} icon={faArrowLeft}
size="2xl" size="2xl"
className="absolute top-[50%] left-[2%] backdrop-blur-md hover:cursor-pointer animate-bounce z-30" className="absolute top-[50%] left-[2%] backdrop-blur-md hover:cursor-pointer animate-bounce z-30"
onClick={() => navigationDest(side)} onClick={() => navigationDest("Rear")}
/> />
)} )}
</> </>

View File

@@ -1,8 +1,4 @@
import { import { useMutation, useQuery, type QueryFunctionContext } from "@tanstack/react-query";
useMutation,
useQuery,
type QueryFunctionContext,
} from "@tanstack/react-query";
import { CAM_BASE } from "../utils/config"; import { CAM_BASE } from "../utils/config";
import type { zoomConfig, ZoomInOptions } from "../types/types"; import type { zoomConfig, ZoomInOptions } from "../types/types";
import { toast } from "sonner"; import { toast } from "sonner";
@@ -10,7 +6,7 @@ import { useEffect } from "react";
async function zoomIn(options: ZoomInOptions) { async function zoomIn(options: ZoomInOptions) {
const response = await fetch( const response = await fetch(
`${CAM_BASE}/Ip${options.camera}-command?magnification=${options.multiplier}x`, `${CAM_BASE}/Ip${options.camera}-command?magnification=${options.multiplierText?.toLowerCase()}`,
{ {
signal: AbortSignal.timeout(500), signal: AbortSignal.timeout(500),
} }
@@ -22,11 +18,9 @@ async function zoomIn(options: ZoomInOptions) {
return response.json(); return response.json();
} }
async function fetchZoomInConfig({ async function fetchZoomInConfig({ queryKey }: QueryFunctionContext<[string, zoomConfig]>) {
queryKey,
}: QueryFunctionContext<[string, zoomConfig]>) {
const [, { camera }] = queryKey; const [, { camera }] = queryKey;
const response = await fetch(`${CAM_BASE}/Ip${camera}-inspect`, { const response = await fetch(`${CAM_BASE}/Ip${camera}-command`, {
signal: AbortSignal.timeout(500), signal: AbortSignal.timeout(500),
}); });
if (!response.ok) { if (!response.ok) {

View File

@@ -374,6 +374,7 @@ export type ModemConfig = {
export type ZoomInOptions = { export type ZoomInOptions = {
camera: string; camera: string;
multiplier: number; multiplier: number;
multiplierText?: string;
}; };
export type zoomConfig = { export type zoomConfig = {
@@ -407,5 +408,6 @@ export type NPEDSTATE = {
export type NPEDACTION = { export type NPEDACTION = {
type: string; type: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
payload: any; payload: any;
}; };

View File

@@ -158,3 +158,16 @@ export function getHotlistName(obj: HotlistMatches | undefined) {
export const getNPEDCategory = (r?: SightingType | null) => export const getNPEDCategory = (r?: SightingType | null) =>
r?.metadata?.npedJSON?.["NPED CATEGORY"] as "A" | "B" | "C" | "D" | undefined; r?.metadata?.npedJSON?.["NPED CATEGORY"] as "A" | "B" | "C" | "D" | undefined;
export const zoomMapping = (zoomLevel: number) => {
switch (zoomLevel) {
case 1:
return "Far";
case 2:
return "Medium";
case 4:
return "Close";
default:
break;
}
};