- Implement CameraFeed context and provider with reducer for state management
- able to switch footage on tab clicks
This commit is contained in:
16
src/app/context/CameraFeedContext.ts
Normal file
16
src/app/context/CameraFeedContext.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { createContext, useContext } from "react";
|
||||||
|
import type { CameraFeedAction, CameraFeedState } from "../../types/types";
|
||||||
|
|
||||||
|
type CameraFeedContextType = {
|
||||||
|
state: CameraFeedState;
|
||||||
|
// check and refactor
|
||||||
|
dispatch: (state: CameraFeedAction) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const CameraFeedContext = createContext<CameraFeedContextType | null>(null);
|
||||||
|
|
||||||
|
export const useCameraFeedContext = () => {
|
||||||
|
const ctx = useContext(CameraFeedContext);
|
||||||
|
if (!ctx) throw new Error("useCameraFeedContext must be used inside <CameraFeedContext.Provider>");
|
||||||
|
return ctx;
|
||||||
|
};
|
||||||
@@ -1,11 +1,14 @@
|
|||||||
import type { PropsWithChildren } from "react";
|
import type { PropsWithChildren } from "react";
|
||||||
import { QueryProvider } from "./QueryProviders";
|
import { QueryProvider } from "./QueryProviders";
|
||||||
import { WebSocketProvider } from "./WebSocketProvider";
|
import { WebSocketProvider } from "./WebSocketProvider";
|
||||||
|
import { CameraFeedProvider } from "./CameraFeedProvider";
|
||||||
|
|
||||||
export const AppProviders = ({ children }: PropsWithChildren) => {
|
export const AppProviders = ({ children }: PropsWithChildren) => {
|
||||||
return (
|
return (
|
||||||
<QueryProvider>
|
<QueryProvider>
|
||||||
<WebSocketProvider>{children}</WebSocketProvider>
|
<CameraFeedProvider>
|
||||||
|
<WebSocketProvider>{children}</WebSocketProvider>
|
||||||
|
</CameraFeedProvider>
|
||||||
</QueryProvider>
|
</QueryProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
9
src/app/providers/CameraFeedProvider.tsx
Normal file
9
src/app/providers/CameraFeedProvider.tsx
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { useReducer, type ReactNode } from "react";
|
||||||
|
import { CameraFeedContext } from "../context/CameraFeedContext";
|
||||||
|
import { initialState, reducer } from "../reducers/cameraFeedReducer";
|
||||||
|
|
||||||
|
export const CameraFeedProvider = ({ children }: { children: ReactNode }) => {
|
||||||
|
const [state, dispatch] = useReducer(reducer, initialState);
|
||||||
|
|
||||||
|
return <CameraFeedContext.Provider value={{ state, dispatch }}>{children}</CameraFeedContext.Provider>;
|
||||||
|
};
|
||||||
17
src/app/reducers/cameraFeedReducer.ts
Normal file
17
src/app/reducers/cameraFeedReducer.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import type { CameraFeedAction, CameraFeedState } from "../../types/types";
|
||||||
|
|
||||||
|
export const initialState: CameraFeedState = {
|
||||||
|
cameraFeedID: "A",
|
||||||
|
};
|
||||||
|
|
||||||
|
export function reducer(state: CameraFeedState, action: CameraFeedAction) {
|
||||||
|
switch (action.type) {
|
||||||
|
case "SET_CAMERA_FEED":
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
cameraFeedID: action.payload,
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import { useEffect } from "react";
|
||||||
|
import { useCameraFeedContext } from "../../../../app/context/CameraFeedContext";
|
||||||
|
|
||||||
|
type CameraPanelProps = {
|
||||||
|
tabIndex: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
const CameraPanel = ({ tabIndex }: CameraPanelProps) => {
|
||||||
|
const { dispatch } = useCameraFeedContext();
|
||||||
|
const mapIndextoCameraId = () => {
|
||||||
|
switch (tabIndex) {
|
||||||
|
case 1:
|
||||||
|
return "A";
|
||||||
|
case 2:
|
||||||
|
return "B";
|
||||||
|
case 3:
|
||||||
|
return "C";
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const cameraId = mapIndextoCameraId();
|
||||||
|
|
||||||
|
dispatch({ type: "SET_CAMERA_FEED", payload: cameraId });
|
||||||
|
}, [tabIndex]);
|
||||||
|
|
||||||
|
return <div>CameraPanel</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CameraPanel;
|
||||||
@@ -4,6 +4,7 @@ import "react-tabs/style/react-tabs.css";
|
|||||||
import RegionSelector from "./RegionSelector";
|
import RegionSelector from "./RegionSelector";
|
||||||
import type { PaintedCell, Region } from "../../../../types/types";
|
import type { PaintedCell, Region } from "../../../../types/types";
|
||||||
import type { RefObject } from "react";
|
import type { RefObject } from "react";
|
||||||
|
import CameraPanel from "./CameraPanel";
|
||||||
|
|
||||||
type CameraSettingsProps = {
|
type CameraSettingsProps = {
|
||||||
regions: Region[];
|
regions: Region[];
|
||||||
@@ -59,13 +60,13 @@ const CameraSettings = ({
|
|||||||
/>
|
/>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel>
|
<TabPanel>
|
||||||
<div>Camera details {tabIndex}</div>
|
<CameraPanel tabIndex={tabIndex} />
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel>
|
<TabPanel>
|
||||||
<div>Camera details {tabIndex}</div>
|
<CameraPanel tabIndex={tabIndex} />
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel>
|
<TabPanel>
|
||||||
<div>Camera details {tabIndex}</div>
|
<CameraPanel tabIndex={tabIndex} />
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
import { CAMBASE } from "../../../utils/config";
|
||||||
|
|
||||||
const getfeed = async () => {
|
const getfeed = async (cameraFeedID: "A" | "B" | "C" | null) => {
|
||||||
const response = await fetch(`http://100.115.148.59/TargetDetectionColour-preview`, {
|
const response = await fetch(`${CAMBASE}TargetDetectionColour${cameraFeedID}-preview`, {
|
||||||
signal: AbortSignal.timeout(300000),
|
signal: AbortSignal.timeout(300000),
|
||||||
cache: "no-store",
|
cache: "no-store",
|
||||||
});
|
});
|
||||||
@@ -11,10 +12,10 @@ const getfeed = async () => {
|
|||||||
return response.blob();
|
return response.blob();
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useGetVideoFeed = () => {
|
export const useGetVideoFeed = (cameraFeedID: "A" | "B" | "C" | null) => {
|
||||||
const videoQuery = useQuery({
|
const videoQuery = useQuery({
|
||||||
queryKey: ["getfeed"],
|
queryKey: ["getfeed", cameraFeedID],
|
||||||
queryFn: getfeed,
|
queryFn: () => getfeed(cameraFeedID),
|
||||||
refetchInterval: 500,
|
refetchInterval: 500,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
import { useEffect, useRef } from "react";
|
import { useEffect, useRef } from "react";
|
||||||
import { useGetVideoFeed } from "./useGetVideoFeed";
|
import { useGetVideoFeed } from "./useGetVideoFeed";
|
||||||
|
import { useCameraFeedContext } from "../../../app/context/CameraFeedContext";
|
||||||
|
|
||||||
export const useCreateVideoSnapshot = () => {
|
export const useCreateVideoSnapshot = () => {
|
||||||
|
const { state } = useCameraFeedContext();
|
||||||
|
const cameraFeedID = state?.cameraFeedID;
|
||||||
const latestBitmapRef = useRef<ImageBitmap | null>(null);
|
const latestBitmapRef = useRef<ImageBitmap | null>(null);
|
||||||
const { videoQuery } = useGetVideoFeed();
|
const { videoQuery } = useGetVideoFeed(cameraFeedID);
|
||||||
|
|
||||||
const snapShot = videoQuery?.data;
|
const snapShot = videoQuery?.data;
|
||||||
const isloading = videoQuery.isPending;
|
const isloading = videoQuery.isPending;
|
||||||
|
|||||||
@@ -95,3 +95,12 @@ export type OptionalBOF2LaneIDs = {
|
|||||||
LID2?: string;
|
LID2?: string;
|
||||||
LID3?: string;
|
LID3?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type CameraFeedState = {
|
||||||
|
cameraFeedID: "A" | "B" | "C" | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CameraFeedAction = {
|
||||||
|
type: string;
|
||||||
|
payload: "A" | "B" | "C" | null;
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user