From c2074f86a2e6b27ae157f4ae8c941c9779b561c8 Mon Sep 17 00:00:00 2001 From: Toba Ojo Date: Tue, 23 Sep 2025 13:03:54 +0100 Subject: [PATCH] added sounds, updated nped config and tweaks + code quality improvements --- .env | 2 +- src/App.tsx | 31 +++--- src/assets/sounds/ui/computer-mouse-click.mp3 | Bin 0 -> 33792 bytes src/assets/sounds/ui/keystroke_hard.mp3 | Bin 0 -> 8822 bytes src/assets/sounds/ui/popup_open.mp3 | Bin 0 -> 17181 bytes .../CameraSettings/CameraSettingFields.tsx | 6 +- .../FrontCameraOverviewCard.tsx | 8 +- .../RearCameraOverviewCard.tsx | 9 +- src/components/SessionForm/SessionCard.tsx | 12 +- .../SettingForms/System/SettingSaveRecall.tsx | 5 +- .../System/SystemConfigFields.tsx | 1 - .../SightingsWidget/SightingWidget.tsx | 6 +- .../SightingsWidget/SightingWidgetDetails.tsx | 104 +++++------------- src/components/UI/CardHeader.tsx | 14 ++- src/components/UI/Header.tsx | 2 + src/components/UI/SoundBtn.tsx | 22 ++++ src/context/SightingFeedContext.ts | 1 + .../providers/SightingFeedProvider.tsx | 5 +- src/hooks/useCameraConfig.ts | 4 +- src/hooks/useGetOverviewSnapshot.ts | 1 - src/hooks/useNPEDAuth.ts | 10 +- src/hooks/useSightingFeed.ts | 17 ++- src/hooks/useSound.ts | 64 +++++++++++ src/pages/Dashboard.tsx | 1 + src/pages/FrontCamera.tsx | 17 ++- src/pages/RearCamera.tsx | 18 +-- src/utils/config.ts | 3 +- 27 files changed, 224 insertions(+), 139 deletions(-) create mode 100644 src/assets/sounds/ui/computer-mouse-click.mp3 create mode 100644 src/assets/sounds/ui/keystroke_hard.mp3 create mode 100644 src/assets/sounds/ui/popup_open.mp3 create mode 100644 src/components/UI/SoundBtn.tsx create mode 100644 src/hooks/useSound.ts diff --git a/.env b/.env index a8fa5c2..28c2d7a 100644 --- a/.env +++ b/.env @@ -2,7 +2,7 @@ VITE_BASEURL=http://192.168.75.11/ VITE_CAM_BASE=http://100.113.222.39 VITE_FOLKESTONE_BASE=http://100.116.253.81 VITE_TESTURL=http://100.82.205.44/SightingListRear/sightingSummary?mostRecentRef=-1 -VITE_OUTSIDE_BASEURL=http://100.82.205.44/api +VITE_OUTSIDE_BASEURL=http://100.82.205.44 VITE_FOLKESTONE_URL=http://100.116.253.81/mergedHistory/sightingSummary?mostRecentRef= VITE_MAV_URL=http://192.168.75.11/SightingListFront/sightingSummary?mostRecentRef= diff --git a/src/App.tsx b/src/App.tsx index e835576..aeca601 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -7,23 +7,26 @@ import SystemSettings from "./pages/SystemSettings"; import Session from "./pages/Session"; import { NPEDUserProvider } from "./context/providers/NPEDUserContextProvider"; import { AlertHitProvider } from "./context/providers/AlertHitProvider"; +import { SoundProvider } from "react-sounds"; function App() { return ( - - - - }> - } /> - } /> - } /> - } /> - } /> - } /> - - - - + + + + + }> + } /> + } /> + } /> + } /> + } /> + } /> + + + + + ); } diff --git a/src/assets/sounds/ui/computer-mouse-click.mp3 b/src/assets/sounds/ui/computer-mouse-click.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..bb8e2373b69535f4baf0fae5491b4ed208ad6200 GIT binary patch literal 33792 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 Z08qv4dM7pjki-DDOJM&0^8aBA{2zs_uzdgk literal 0 HcmV?d00001 diff --git a/src/components/CameraSettings/CameraSettingFields.tsx b/src/components/CameraSettings/CameraSettingFields.tsx index a30fe34..3f88cf9 100644 --- a/src/components/CameraSettings/CameraSettingFields.tsx +++ b/src/components/CameraSettings/CameraSettingFields.tsx @@ -21,13 +21,13 @@ const CameraSettingFields = ({ const initialValues = useMemo( () => ({ - friendlyName: initialData?.propLEDDriverControlURI?.value ?? "", - cameraAddress: "", + friendlyName: initialData?.id ?? "", + cameraAddress: initialData?.propURI?.value ?? "", userName: "", password: "", id: initialData?.id, }), - [initialData?.id, initialData?.propLEDDriverControlURI?.value] + [initialData?.id, initialData?.propURI?.value] ); const validateValues = (values: CameraSettingValues) => { diff --git a/src/components/FrontCameraOverview/FrontCameraOverviewCard.tsx b/src/components/FrontCameraOverview/FrontCameraOverviewCard.tsx index 81c2ddb..2bd572e 100644 --- a/src/components/FrontCameraOverview/FrontCameraOverviewCard.tsx +++ b/src/components/FrontCameraOverview/FrontCameraOverviewCard.tsx @@ -6,6 +6,7 @@ import { useSwipeable } from "react-swipeable"; import { useNavigate } from "react-router"; import { useOverviewVideo } from "../../hooks/useOverviewVideo"; import SightingOverview from "../SightingOverview/SightingOverview"; +import { useSightingFeedContext } from "../../context/SightingFeedContext"; type CardProps = React.HTMLAttributes; @@ -17,6 +18,7 @@ const FrontCameraOverviewCard = ({ className }: CardProps) => { trackMouse: true, }); + const { mostRecent } = useSightingFeedContext(); return ( { )} >
- + {/* */}
diff --git a/src/components/RearCameraOverview/RearCameraOverviewCard.tsx b/src/components/RearCameraOverview/RearCameraOverviewCard.tsx index 40421f1..55afe4e 100644 --- a/src/components/RearCameraOverview/RearCameraOverviewCard.tsx +++ b/src/components/RearCameraOverview/RearCameraOverviewCard.tsx @@ -6,6 +6,7 @@ import { useNavigate } from "react-router"; import CardHeader from "../UI/CardHeader"; import { faCamera } from "@fortawesome/free-regular-svg-icons"; import SightingOverview from "../SightingOverview/SightingOverview"; +import { useSightingFeedContext } from "../../context/SightingFeedContext"; type CardProps = React.HTMLAttributes; @@ -15,7 +16,7 @@ const RearCameraOverviewCard = ({ className }: CardProps) => { onSwipedLeft: () => navigate("/rear-camera-settings"), trackMouse: true, }); - + const { mostRecent } = useSightingFeedContext(); return ( { )} >
- +
diff --git a/src/components/SessionForm/SessionCard.tsx b/src/components/SessionForm/SessionCard.tsx index 675094c..1502bb5 100644 --- a/src/components/SessionForm/SessionCard.tsx +++ b/src/components/SessionForm/SessionCard.tsx @@ -1,10 +1,12 @@ +import { useSound } from "react-sounds"; import Card from "../UI/Card"; import CardHeader from "../UI/CardHeader"; const SessionCard = () => { - function onStart(): void { - throw new Error("Function not implemented."); - } + const { play } = useSound("notification/notification"); + // function onStart(): void { + // throw new Error("Function not implemented."); + // } return ( @@ -12,7 +14,9 @@ const SessionCard = () => {
diff --git a/src/components/SettingForms/System/SettingSaveRecall.tsx b/src/components/SettingForms/System/SettingSaveRecall.tsx index 15bc00a..83511b9 100644 --- a/src/components/SettingForms/System/SettingSaveRecall.tsx +++ b/src/components/SettingForms/System/SettingSaveRecall.tsx @@ -1,4 +1,5 @@ import type { SystemValues } from "../../../types/types"; +import { CAM_BASE } from "../../../utils/config"; export async function handleSystemSave(values: SystemValues) { const payload = { @@ -16,7 +17,7 @@ export async function handleSystemSave(values: SystemValues) { }; try { - const response = await fetch("http://192.168.75.11/api/update-config", { + const response = await fetch(`${CAM_BASE}/api/update-config`, { method: "POST", headers: { "Content-Type": "application/json", @@ -39,7 +40,7 @@ export async function handleSystemSave(values: SystemValues) { } export async function handleSystemRecall() { - const url = "http://192.168.75.11/api/fetch-config?id=GLOBAL--Device"; + const url = `${CAM_BASE}/api/fetch-config?id=GLOBAL--Device`; const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 7000); diff --git a/src/components/SettingForms/System/SystemConfigFields.tsx b/src/components/SettingForms/System/SystemConfigFields.tsx index 687eb83..1b14594 100644 --- a/src/components/SettingForms/System/SystemConfigFields.tsx +++ b/src/components/SettingForms/System/SystemConfigFields.tsx @@ -8,7 +8,6 @@ import { useSystemConfig } from "../../../hooks/useSystemConfig"; const SystemConfigFields = () => { const { saveSystemSettings, systemSettingsData } = useSystemConfig(); - const initialvalues: SystemValues = { deviceName: systemSettingsData?.deviceName ?? "", timeZone: systemSettingsData?.timeZone ?? "", diff --git a/src/components/SightingsWidget/SightingWidget.tsx b/src/components/SightingsWidget/SightingWidget.tsx index a6f0dc6..df1c816 100644 --- a/src/components/SightingsWidget/SightingWidget.tsx +++ b/src/components/SightingsWidget/SightingWidget.tsx @@ -13,6 +13,7 @@ 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 { useSound } from "react-sounds"; function useNow(tickMs = 1000) { @@ -38,7 +39,7 @@ export default function SightingHistoryWidget({ title, }: SightingHistoryProps) { useNow(1000); - const { play } = useSound("notification/notification"); + const { play } = useSound(popup); const { sightings, setSelectedSighting, @@ -72,14 +73,13 @@ export default function SightingHistoryWidget({ const isNPEDHitC = obj?.metadata?.npedJSON?.["NPED CATEGORY"] === "C"; if (isNPEDHitA || isNPEDHitB || isNPEDHitC) { - play(); dispatch({ type: "ADD", payload: obj, }); } }); - }, [rows, dispatch, play]); + }, [dispatch, rows]); useEffect(() => { if (hasAutoOpenedRef.current) return; diff --git a/src/components/SightingsWidget/SightingWidgetDetails.tsx b/src/components/SightingsWidget/SightingWidgetDetails.tsx index 5d35a74..642f1ba 100644 --- a/src/components/SightingsWidget/SightingWidgetDetails.tsx +++ b/src/components/SightingsWidget/SightingWidgetDetails.tsx @@ -1,5 +1,4 @@ import type { SightingType } from "../../types/types"; -import { useState } from "react"; type SightingWidgetDetailsProps = { effectiveSelected: SightingType | null; @@ -8,85 +7,38 @@ type SightingWidgetDetailsProps = { const SightingWidgetDetails = ({ effectiveSelected, }: SightingWidgetDetailsProps) => { - const [advancedDetailsEnabled, setAdvancedDetailsEnabled] = useState(false); - - const handleDetailsClick = () => - setAdvancedDetailsEnabled(!advancedDetailsEnabled); - return ( <>
-
- VRM:{" "} - {effectiveSelected?.vrm ?? "—"} -
- -
- Make:{" "} - {effectiveSelected?.make ?? "—"} -
-
- Model:{" "} - {effectiveSelected?.model ?? "—"} -
-
- Colour:{" "} - {effectiveSelected?.color ?? "—"} -
-
- Timestamp:{" "} - - {effectiveSelected?.timeStamp ?? "—"} - -
- {advancedDetailsEnabled && ( - <> -
- Country:{" "} - - {effectiveSelected?.countryCode ?? "—"} - -
-
- Seen:{" "} - - {effectiveSelected?.seenCount ?? "—"} - -
-
- Category:{" "} - - {effectiveSelected?.category ?? "—"} - -
-
- Char Ht:{" "} - - {effectiveSelected?.charHeight ?? "—"} - -
-
- Plate Size:{" "} - - {effectiveSelected?.plateSize ?? "—"} - -
-
- Overview Size:{" "} - - {effectiveSelected?.overviewSize ?? "—"} - -
- + {effectiveSelected?.vrm && ( +
+ VRM:{" "} + {effectiveSelected?.vrm ?? "—"} +
+ )} + + {effectiveSelected?.make !== "" && ( +
+ Make:{" "} + {effectiveSelected?.make ?? "—"} +
+ )} + {effectiveSelected?.model.trim() !== "" && ( +
+ Model:{" "} + + {effectiveSelected?.model ?? "—"} + +
+ )} + {effectiveSelected?.color !== "" && ( +
+ Colour:{" "} + + {effectiveSelected?.color ?? "—"} + +
)} -
-
-

- Sighting Details -

); diff --git a/src/components/UI/CardHeader.tsx b/src/components/UI/CardHeader.tsx index df8724a..120df69 100644 --- a/src/components/UI/CardHeader.tsx +++ b/src/components/UI/CardHeader.tsx @@ -1,18 +1,27 @@ import type { IconProp } from "@fortawesome/fontawesome-svg-core"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import clsx from "clsx"; +import NumberPlate from "../PlateStack/NumberPlate"; +import type { SightingType } from "../../types/types"; type CameraOverviewHeaderProps = { title: string; icon?: IconProp; img?: string; + sighting?: SightingType | null; }; -const CardHeader = ({ title, icon, img }: CameraOverviewHeaderProps) => { +const CardHeader = ({ + title, + icon, + img, + sighting, +}: CameraOverviewHeaderProps) => { + // console.log(sighting?.debug.toLowerCase()); return (
@@ -22,6 +31,7 @@ const CardHeader = ({ title, icon, img }: CameraOverviewHeaderProps) => { {img && ( Logo )} + {sighting?.vrm && }
); }; diff --git a/src/components/UI/Header.tsx b/src/components/UI/Header.tsx index c38270b..d959e63 100644 --- a/src/components/UI/Header.tsx +++ b/src/components/UI/Header.tsx @@ -10,6 +10,7 @@ import { } from "@fortawesome/free-solid-svg-icons"; import type { VersionFieldType } from "../../types/types"; import { useEffect, useState } from "react"; +import SoundBtn from "./SoundBtn"; async function fetchVersions( signal?: AbortSignal @@ -120,6 +121,7 @@ export default function Header() { size="2x" /> + diff --git a/src/components/UI/SoundBtn.tsx b/src/components/UI/SoundBtn.tsx new file mode 100644 index 0000000..fb2080f --- /dev/null +++ b/src/components/UI/SoundBtn.tsx @@ -0,0 +1,22 @@ +import { faVolumeHigh, faVolumeXmark } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { useSoundEnabled } from "react-sounds"; + +const SoundBtn = () => { + const [enabled, setEnabled] = useSoundEnabled(); + + const handleClick = () => { + setEnabled(!enabled); + }; + + return ( + + ); +}; + +export default SoundBtn; diff --git a/src/context/SightingFeedContext.ts b/src/context/SightingFeedContext.ts index 2cddb67..493fde6 100644 --- a/src/context/SightingFeedContext.ts +++ b/src/context/SightingFeedContext.ts @@ -14,6 +14,7 @@ type SightingFeedContextType = { isSightingModalOpen: boolean; isError: boolean; isLoading: boolean; + data: SightingType | undefined; }; export const SightingFeedContext = createContext< diff --git a/src/context/providers/SightingFeedProvider.tsx b/src/context/providers/SightingFeedProvider.tsx index bfc4f33..c903ede 100644 --- a/src/context/providers/SightingFeedProvider.tsx +++ b/src/context/providers/SightingFeedProvider.tsx @@ -17,13 +17,13 @@ export const SightingFeedProvider = ({ sightings, selectedRef, setSelectedRef, - + data, isLoading, isError, setSelectedSighting, selectedSighting, mostRecent, - } = useSightingFeed(url); + } = useSightingFeed(url, side); const [isSightingModalOpen, setSightingModalOpen] = useState(false); @@ -41,6 +41,7 @@ export const SightingFeedProvider = ({ isError, isLoading, side, + data, }} > {children} diff --git a/src/hooks/useCameraConfig.ts b/src/hooks/useCameraConfig.ts index afd985a..284468f 100644 --- a/src/hooks/useCameraConfig.ts +++ b/src/hooks/useCameraConfig.ts @@ -1,7 +1,9 @@ import { useMutation, useQuery } from "@tanstack/react-query"; import { toast } from "sonner"; +import { CAM_BASE } from "../utils/config"; -const base_url = import.meta.env.VITE_OUTSIDE_BASEURL; +const base_url = `${CAM_BASE}/api`; +console.log(base_url); const fetchCameraSideConfig = async ({ queryKey }: { queryKey: string[] }) => { const [, cameraSide] = queryKey; diff --git a/src/hooks/useGetOverviewSnapshot.ts b/src/hooks/useGetOverviewSnapshot.ts index d872659..66dcc7b 100644 --- a/src/hooks/useGetOverviewSnapshot.ts +++ b/src/hooks/useGetOverviewSnapshot.ts @@ -5,7 +5,6 @@ import { CAM_BASE } from "../utils/config"; const apiUrl = CAM_BASE; async function fetchSnapshot(cameraSide: string) { - console.log(`${apiUrl}/${cameraSide}-preview`); const response = await fetch(`${apiUrl}/${cameraSide}-preview`); if (!response.ok) { throw new Error("Cannot reach endpoint"); diff --git a/src/hooks/useNPEDAuth.ts b/src/hooks/useNPEDAuth.ts index 96fab80..ed48fc1 100644 --- a/src/hooks/useNPEDAuth.ts +++ b/src/hooks/useNPEDAuth.ts @@ -2,10 +2,10 @@ import { useMutation, useQuery } from "@tanstack/react-query"; import type { NPEDFieldType } from "../types/types"; import { useNPEDContext } from "../context/NPEDUserContext"; import { useEffect } from "react"; +import { CAM_BASE } from "../utils/config"; -const base_url = import.meta.env.VITE_OUTSIDE_BASEURL; async function fetchNPEDDetails() { - const fetchUrl = `${base_url}/fetch-config?id=NPED`; + const fetchUrl = `${CAM_BASE}/api/fetch-config?id=NPED`; const response = await fetch(fetchUrl); if (!response.ok) throw new Error("Cannot reach fetch-config endpoint"); @@ -14,8 +14,8 @@ async function fetchNPEDDetails() { async function signIn(loginDetails: NPEDFieldType) { const { frontId, rearId, username, password, clientId } = loginDetails; - const NPEDLoginURLFront = `${base_url}/update-config?id=${frontId}`; - const NPEDLoginURLRear = `${base_url}/update-config?id=${rearId}`; + const NPEDLoginURLFront = `${CAM_BASE}/api/update-config?id=${frontId}`; + const NPEDLoginURLRear = `${CAM_BASE}/api/update-config?id=${rearId}`; const frontCameraPayload = { id: frontId, fields: [ @@ -66,7 +66,7 @@ async function signOut() { { property: "propClientID", value: "" }, ], }; - const NPEDLoginURLFront = `${base_url}/update-config?id=NPED`; + const NPEDLoginURLFront = `${CAM_BASE}/api/update-config?id=NPED`; const response = await fetch(NPEDLoginURLFront, { method: "POST", body: JSON.stringify(nullPayload), diff --git a/src/hooks/useSightingFeed.ts b/src/hooks/useSightingFeed.ts index b81f036..6ca2715 100644 --- a/src/hooks/useSightingFeed.ts +++ b/src/hooks/useSightingFeed.ts @@ -1,6 +1,8 @@ import { useEffect, useRef, useState } from "react"; import { useQuery } from "@tanstack/react-query"; import type { SightingType } from "../types/types"; +import { useSoundOnChange } from "react-sounds"; +import click from "../assets/sounds/ui/computer-mouse-click.mp3"; async function fetchSighting(url: string, ref: number): Promise { const res = await fetch(`${url}${ref}`); @@ -8,14 +10,19 @@ async function fetchSighting(url: string, ref: number): Promise { return res.json(); } -export function useSightingFeed(url: string) { +export function useSightingFeed(url: string, side: string) { const [sightings, setSightings] = useState([]); const [selectedRef, setSelectedRef] = useState(null); const mostRecent = sightings[0] ?? null; + const latestRef = mostRecent?.ref ?? null; const [selectedSighting, setSelectedSighting] = useState( null ); + useSoundOnChange(click, latestRef, { + volume: side === "Rear" ? 0 : 1, + }); + const currentRef = useRef(-1); const lastValidTimestamp = useRef(Date.now()); @@ -61,6 +68,13 @@ export function useSightingFeed(url: string) { return; } + // if (Notification.permission === "granted") { + // new Notification("New Sighting!", { + // body: `Ref: ${data.ref}`, + // icon: "/MAV-blue.svg", + // }); + // } + currentRef.current = data.ref; lastValidTimestamp.current = now; @@ -75,7 +89,6 @@ export function useSightingFeed(url: string) { useEffect(() => { if (query.error) { - // you can add logging/telemetry here // console.error("Sighting feed error:", query.error); } }, [query.error]); diff --git a/src/hooks/useSound.ts b/src/hooks/useSound.ts new file mode 100644 index 0000000..21f3455 --- /dev/null +++ b/src/hooks/useSound.ts @@ -0,0 +1,64 @@ +// useBeep.ts +import { useEffect, useRef } from "react"; +import { useSoundEnabled } from "react-sounds"; // so it respects your SoundBtn toggle + +/** + * Plays a sound whenever `latestRef` changes. + * + * @param src Path to the sound file + * @param latestRef The primitive value to watch (e.g. sighting.ref) + * @param opts volume: 0..1, enabledOverride: force enable/disable, minGapMs: throttle interval + */ +export function useBeep( + src: string, + latestRef: number | null, + opts?: { volume?: number; enabledOverride?: boolean; minGapMs?: number } +) { + const audioRef = useRef(undefined); + const prevRef = useRef(null); + const lastPlay = useRef(0); + const [enabled] = useSoundEnabled(); + + const minGap = opts?.minGapMs ?? 250; // don’t play more than 4 times/sec + + // Create the audio element once + useEffect(() => { + const a = new Audio(src); + a.preload = "auto"; + if (opts?.volume !== undefined) a.volume = opts.volume; + audioRef.current = a; + return () => { + a.pause(); + }; + }, [src, opts?.volume]); + + // Watch for ref changes + useEffect(() => { + if (latestRef == null) return; + + const canPlay = + (opts?.enabledOverride ?? enabled) && + document.visibilityState === "visible"; + if (!canPlay) { + prevRef.current = latestRef; // consume the change + return; + } + + if (prevRef.current !== null && latestRef !== prevRef.current) { + const now = Date.now(); + if (now - lastPlay.current >= minGap) { + const a = audioRef.current; + if (a) { + try { + a.currentTime = 0; // restart from beginning + void a.play(); // fire and forget + lastPlay.current = now; + } catch (err) { + console.warn("Audio play failed:", err); + } + } + } + } + prevRef.current = latestRef; + }, [latestRef, enabled, opts?.enabledOverride, minGap]); +} diff --git a/src/pages/Dashboard.tsx b/src/pages/Dashboard.tsx index 7bf11d3..fb45cd2 100644 --- a/src/pages/Dashboard.tsx +++ b/src/pages/Dashboard.tsx @@ -3,6 +3,7 @@ import RearCameraOverviewCard from "../components/RearCameraOverview/RearCameraO import SightingHistoryWidget from "../components/SightingsWidget/SightingWidget"; import { SightingFeedProvider } from "../context/providers/SightingFeedProvider"; import { CAM_BASE } from "../utils/config"; + const Dashboard = () => { const dev_REAR_URL = `${CAM_BASE}/SightingListRear/sightingSummary?mostRecentRef=`; const dev_FRONT_URL = `${CAM_BASE}/SightingListFront/sightingSummary?mostRecentRef=`; diff --git a/src/pages/FrontCamera.tsx b/src/pages/FrontCamera.tsx index 712d825..c665d0a 100644 --- a/src/pages/FrontCamera.tsx +++ b/src/pages/FrontCamera.tsx @@ -12,15 +12,14 @@ const FrontCamera = () => { }); return ( -
- +
+
+ +
diff --git a/src/pages/RearCamera.tsx b/src/pages/RearCamera.tsx index a450a16..3ee433d 100644 --- a/src/pages/RearCamera.tsx +++ b/src/pages/RearCamera.tsx @@ -12,16 +12,16 @@ const RearCamera = () => { }); return ( -
+
- + +
+ +
); diff --git a/src/utils/config.ts b/src/utils/config.ts index 6665faa..fac7887 100644 --- a/src/utils/config.ts +++ b/src/utils/config.ts @@ -1,4 +1,5 @@ -const rawCamBase = import.meta.env.VITE_CAM_BASE; +// 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