- added websocket context to connect to websockets if needed

This commit is contained in:
2025-12-15 16:07:30 +00:00
parent cae652477e
commit 555330991d
10 changed files with 510 additions and 62 deletions

View File

@@ -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>
);

View File

@@ -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"

View File

@@ -21,7 +21,6 @@ type SightingModalProps = {
};
const SightingModal = ({ isSightingModalOpen, handleClose, sighting, onDelete }: SightingModalProps) => {
console.log(sighting);
const { dispatch } = useAlertHitContext();
const { query, mutation } = useCameraBlackboard();

View File

@@ -13,8 +13,11 @@ import {
import { useState } from "react";
import SoundBtn from "./SoundBtn";
import { useIntegrationsContext } from "../../context/IntegrationsContext";
import { useInfoBarSocket } from "../../context/WebsocketContext";
export default function Header() {
const { data: stats } = useInfoBarSocket();
console.log(stats);
const [isFullscreen, setIsFullscreen] = useState(false);
const [isMenuOpen, setIsMenuOpen] = useState(false);
const { state } = useIntegrationsContext();

View File

@@ -0,0 +1,24 @@
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;
};
export type WebsocketContextValue = {
info: InfoSocketState;
};
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;

View 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,
},
}),
[infoSocket.readyState, infoSocket.sendJsonMessage, systemData]
);
return <WebsocketContext.Provider value={value}>{children}</WebsocketContext.Provider>;
};
export default WebSocketProvider;

View File

@@ -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;
};

5
src/utils/ws_config.ts Normal file
View File

@@ -0,0 +1,5 @@
import { CAM_BASE } from "./config";
export const ws_config = {
infoBar: `${CAM_BASE.replace("http", "ws")}/websocket-infobar`,
};