diff --git a/src/App.tsx b/src/App.tsx index aeca601..67ea871 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -17,7 +17,7 @@ function App() { }> } /> - } /> + } /> } /> } /> } /> diff --git a/src/components/CameraOverview/SnapshotContainer.tsx b/src/components/CameraOverview/SnapshotContainer.tsx index 51a5821..cc491db 100644 --- a/src/components/CameraOverview/SnapshotContainer.tsx +++ b/src/components/CameraOverview/SnapshotContainer.tsx @@ -1,25 +1,58 @@ import { useGetOverviewSnapshot } from "../../hooks/useGetOverviewSnapshot"; +import type { ZoomLevel } from "../../types/types"; import NavigationArrow from "../UI/NavigationArrow"; type SnapshotContainerProps = { side: string; settingsPage?: boolean; + zoomLevel?: ZoomLevel; + onZoomLevelChange?: (level: ZoomLevel) => void; }; export const SnapshotContainer = ({ side, settingsPage, + zoomLevel, + onZoomLevelChange, }: SnapshotContainerProps) => { - const { canvasRef, isError, isPending } = useGetOverviewSnapshot(side); + const { canvasRef, isError, isPending } = useGetOverviewSnapshot(); + if (isError) return

An error occurred

; + if (isPending) return

Loading...

; - if (isError) return <>An error occurred; - if (isPending) return <>Loading...; + const handleZoomClick = (event: React.MouseEvent) => { + const bounds = canvasRef.current?.getBoundingClientRect(); + if (!bounds) return; + const left = bounds.left; + const top = bounds.top; + const x = event.pageX; + const y = event.pageY; + const cw = canvasRef.current?.clientWidth; + const ch = canvasRef.current?.clientHeight; + if (!cw || !ch) return; + const px = x / cw; + const py = y / ch; + + const baseLevel = zoomLevel?.level ?? 1; + const newLevel = baseLevel >= 8 ? 1 : baseLevel * 2; + + if (onZoomLevelChange) + onZoomLevelChange({ + left, + top, + x, + y, + px, + py, + level: newLevel, + }); + }; return (
diff --git a/src/components/CameraSettings/CameraSettingFields.tsx b/src/components/CameraSettings/CameraSettingFields.tsx index 6f31f46..74db4bc 100644 --- a/src/components/CameraSettings/CameraSettingFields.tsx +++ b/src/components/CameraSettings/CameraSettingFields.tsx @@ -3,19 +3,25 @@ import type { CameraConfig, CameraSettingErrorValues, CameraSettingValues, + ZoomLevel, } from "../../types/types"; import { useMemo, useState } from "react"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faEye, faEyeSlash } from "@fortawesome/free-regular-svg-icons"; +import CardHeader from "../UI/CardHeader"; type CameraSettingsProps = { initialData: CameraConfig; updateCameraConfig: (values: CameraSettingValues) => Promise | void; + zoomLevel?: ZoomLevel; + onZoomLevelChange?: (level: ZoomLevel) => void; }; const CameraSettingFields = ({ initialData, updateCameraConfig, + zoomLevel, + onZoomLevelChange, }: CameraSettingsProps) => { const [showPwd, setShowPwd] = useState(false); @@ -26,8 +32,9 @@ const CameraSettingFields = ({ userName: "", password: "", id: initialData?.id, + zoom: zoomLevel?.level ? zoomLevel.level : 1, }), - [initialData?.id, initialData?.propURI?.value] + [initialData?.id, initialData?.propURI?.value, zoomLevel?.level] ); const validateValues = (values: CameraSettingValues) => { @@ -41,16 +48,24 @@ const CameraSettingFields = ({ }; const handleSubmit = (values: CameraSettingValues) => { + console.log(values); updateCameraConfig(values); }; + const handleRadioButtonChange = (levelNumber: number) => { + if (!onZoomLevelChange || !zoomLevel) return; + onZoomLevelChange({ + ...zoomLevel, + level: zoomLevel?.level !== levelNumber ? levelNumber : zoomLevel?.level, + }); + }; + return ( {({ errors, touched }) => (
@@ -111,7 +126,7 @@ const CameraSettingFields = ({ {errors.password} )} -
+
+
+ +
+
+ handleRadioButtonChange(1)} + /> + +
+
+ handleRadioButtonChange(2)} + /> + +
+ +
+ handleRadioButtonChange(4)} + /> + +
+ +
+ handleRadioButtonChange(8)} + /> + +
+
+
diff --git a/src/components/FrontCameraOverview/FrontCameraOverviewCard.tsx b/src/components/FrontCameraOverview/FrontCameraOverviewCard.tsx index 3c2a540..6c449dd 100644 --- a/src/components/FrontCameraOverview/FrontCameraOverviewCard.tsx +++ b/src/components/FrontCameraOverview/FrontCameraOverviewCard.tsx @@ -9,7 +9,7 @@ const FrontCameraOverviewCard = () => { useOverviewVideo(); const navigate = useNavigate(); const handlers = useSwipeable({ - onSwipedRight: () => navigate("/front-camera-settings"), + onSwipedRight: () => navigate("/camera-settings"), trackMouse: true, }); diff --git a/src/components/FrontCameraSettings/OverviewVideoContainer.tsx b/src/components/FrontCameraSettings/OverviewVideoContainer.tsx index 7ed4c87..db16aeb 100644 --- a/src/components/FrontCameraSettings/OverviewVideoContainer.tsx +++ b/src/components/FrontCameraSettings/OverviewVideoContainer.tsx @@ -3,14 +3,19 @@ import { SnapshotContainer } from "../CameraOverview/SnapshotContainer"; import Card from "../UI/Card"; import { useNavigate } from "react-router"; import { useSwipeable } from "react-swipeable"; +import type { ZoomLevel } from "../../types/types"; const OverviewVideoContainer = ({ side, settingsPage, + zoomLevel, + onZoomLevelChange, }: { title: string; side: string; settingsPage?: boolean; + zoomLevel?: ZoomLevel; + onZoomLevelChange?: (level: ZoomLevel) => void; }) => { const navigate = useNavigate(); const handlers = useSwipeable({ @@ -24,7 +29,12 @@ const OverviewVideoContainer = ({ )} >
- +
); diff --git a/src/components/SightingOverview/SightingOverview.tsx b/src/components/SightingOverview/SightingOverview.tsx index 222ff11..14b012b 100644 --- a/src/components/SightingOverview/SightingOverview.tsx +++ b/src/components/SightingOverview/SightingOverview.tsx @@ -22,9 +22,10 @@ const SightingOverview = () => { const { sync } = useHiDPICanvas(imgRef, canvasRef); - if (isLoading) return

Loading

; + if (isLoading) return

Loading

; - if (isError) return

An error occurred, Cannot display footage

; + if (isError) + return

An error occurred, Cannot display footage

; return (
diff --git a/src/hooks/useCameraConfig.ts b/src/hooks/useCameraConfig.ts index 8601bab..284468f 100644 --- a/src/hooks/useCameraConfig.ts +++ b/src/hooks/useCameraConfig.ts @@ -1,8 +1,8 @@ import { useMutation, useQuery } from "@tanstack/react-query"; import { toast } from "sonner"; -import { OUTSIDE_CAM_BASE } from "../utils/config"; +import { CAM_BASE } from "../utils/config"; -const base_url = `${OUTSIDE_CAM_BASE}/api`; +const base_url = `${CAM_BASE}/api`; console.log(base_url); const fetchCameraSideConfig = async ({ queryKey }: { queryKey: string[] }) => { diff --git a/src/hooks/useGetOverviewSnapshot.ts b/src/hooks/useGetOverviewSnapshot.ts index 1cbaff0..5e00b0e 100644 --- a/src/hooks/useGetOverviewSnapshot.ts +++ b/src/hooks/useGetOverviewSnapshot.ts @@ -1,11 +1,11 @@ import { useRef, useCallback, useEffect } from "react"; import { useQuery } from "@tanstack/react-query"; -import { OUTSIDE_CAM_BASE } from "../utils/config"; +import { CAM_BASE } from "../utils/config"; -const apiUrl = OUTSIDE_CAM_BASE; +const apiUrl = CAM_BASE; -async function fetchSnapshot(cameraSide: string) { - const response = await fetch(`${apiUrl}/${cameraSide}-preview`); +async function fetchSnapshot() { + const response = await fetch(`${apiUrl}/CameraRear-preview`); if (!response.ok) { throw new Error("Cannot reach endpoint"); } @@ -13,7 +13,7 @@ async function fetchSnapshot(cameraSide: string) { return await response.blob(); } -export function useGetOverviewSnapshot(cameraSide: string) { +export function useGetOverviewSnapshot() { const latestUrlRef = useRef(null); const canvasRef = useRef(null); const imageRef = useRef(null); @@ -37,8 +37,8 @@ export function useGetOverviewSnapshot(cameraSide: string) { error, isPending, } = useQuery({ - queryKey: ["overviewSnapshot", cameraSide], - queryFn: () => fetchSnapshot(cameraSide), + queryKey: ["overviewSnapshot"], + queryFn: () => fetchSnapshot(), refetchOnWindowFocus: false, refetchInterval: 250, }); diff --git a/src/pages/Dashboard.tsx b/src/pages/Dashboard.tsx index cb81f39..844a26b 100644 --- a/src/pages/Dashboard.tsx +++ b/src/pages/Dashboard.tsx @@ -1,13 +1,12 @@ import FrontCameraOverviewCard from "../components/FrontCameraOverview/FrontCameraOverviewCard"; import SightingHistoryWidget from "../components/SightingsWidget/SightingWidget"; import { SightingFeedProvider } from "../context/providers/SightingFeedProvider"; -// import { OUTSIDE_CAM_BASE } from "../utils/config"; +import { CAM_BASE } from "../utils/config"; const Dashboard = () => { - // const dev_OUTSIDE_URL = `${OUTSIDE_CAM_BASE}/SightingListFront/sightingSummary?mostRecentRef=`; - const folkestone_OUTSIDE_URL = `http://100.116.253.81/mergedHistory/sightingSummary?mostRecentRef=`; + const base_url = `${CAM_BASE}/SightingListFront/sightingSummary?mostRecentRef=`; return ( - +
diff --git a/src/pages/FrontCamera.tsx b/src/pages/FrontCamera.tsx index dd97803..cc4bc03 100644 --- a/src/pages/FrontCamera.tsx +++ b/src/pages/FrontCamera.tsx @@ -1,16 +1,34 @@ +import { useState } from "react"; import CameraSettings from "../components/CameraSettings/CameraSettings"; import OverviewVideoContainer from "../components/FrontCameraSettings/OverviewVideoContainer"; import { Toaster } from "sonner"; +import type { ZoomLevel } from "../types/types"; const FrontCamera = () => { + const [zoomLevel, setZoomLevel] = useState({ + left: 0, + top: 0, + x: 0, + y: 0, + px: 0, + py: 0, + level: 1, + }); return (
+ -
); diff --git a/src/types/types.ts b/src/types/types.ts index a43d6a0..e70d706 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -251,3 +251,13 @@ export type CameraBlackBoardOptions = { export type CameraBlackboardResponse = { data: object; }; + +export type ZoomLevel = { + left: number; + top: number; + x: number; + y: number; + px: number; + py: number; + level?: number; +}; diff --git a/src/utils/config.ts b/src/utils/config.ts index 3cd72f3..f403ad1 100644 --- a/src/utils/config.ts +++ b/src/utils/config.ts @@ -1,4 +1,4 @@ -const rawCamBase = import.meta.env.VITE_CAM_BASE; +const rawCamBase = import.meta.env.VITE_OUTSIDE_BASEURL; export const CAM_BASE = rawCamBase && rawCamBase.trim().length > 0 ? rawCamBase