- Enhanced Dashboard and SystemOverview components with totalSightings prop
- improved layout and loading states in VideoFeed and SightingStack components.
This commit is contained in:
@@ -6,22 +6,24 @@ import { useCameraSettingsContext } from "../../app/context/CameraSettingsContex
|
|||||||
import SystemOverview from "./SystemOverview/SystemOverview";
|
import SystemOverview from "./SystemOverview/SystemOverview";
|
||||||
|
|
||||||
const Dashboard = () => {
|
const Dashboard = () => {
|
||||||
const { sightingList, isLoading } = useSightingList();
|
const { sightingList, isLoading, totalSightings } = useSightingList();
|
||||||
const { state: cameraSettings } = useCameraSettingsContext();
|
const { state: cameraSettings } = useCameraSettingsContext();
|
||||||
const size = cameraSettings.imageSize;
|
const size = cameraSettings.imageSize;
|
||||||
|
|
||||||
const mostRecent = sightingList[0];
|
const mostRecent = sightingList[0];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className="flex flex-col">
|
||||||
<SystemOverview />
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-2 md:gap-5">
|
||||||
<div className="grid grid-cols-1 md:grid-cols-12 gap-2 md:gap-5 mt-4">
|
<VideoFeed mostRecentSighting={mostRecent} isLoading={isLoading} size={size} />
|
||||||
<div className="col-span-7">
|
<SightingStack sightings={sightingList} />
|
||||||
<VideoFeed mostRecentSighting={mostRecent} isLoading={isLoading} size={size} />
|
</div>
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-2 md:gap-5 items-center">
|
||||||
|
<div className="col-span-1">
|
||||||
<PlateRead sighting={mostRecent} />
|
<PlateRead sighting={mostRecent} />
|
||||||
</div>
|
</div>
|
||||||
<div className="col-span-5">
|
<div className="col-span-2">
|
||||||
<SightingStack sightings={sightingList} />
|
<SystemOverview totalSightings={totalSightings} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,7 +5,11 @@ import { useGetSystemHealth } from "../hooks/useGetSystemHealth";
|
|||||||
import PlatesProcessed from "./PlatesProcessed";
|
import PlatesProcessed from "./PlatesProcessed";
|
||||||
import SystemStatusContent from "./SystemStatusContent";
|
import SystemStatusContent from "./SystemStatusContent";
|
||||||
|
|
||||||
const SystemOverview = () => {
|
type SystemOverViewProps = {
|
||||||
|
totalSightings: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
const SystemOverview = ({ totalSightings }: SystemOverViewProps) => {
|
||||||
const { systemHealthQuery } = useGetSystemHealth();
|
const { systemHealthQuery } = useGetSystemHealth();
|
||||||
const { storeQuery } = useGetStore();
|
const { storeQuery } = useGetStore();
|
||||||
|
|
||||||
@@ -19,23 +23,24 @@ const SystemOverview = () => {
|
|||||||
return <div>Loading system overview...</div>;
|
return <div>Loading system overview...</div>;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div>
|
<Card className="p-4">
|
||||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
<Card className="p-4 hover:bg-[#233241] cursor-pointer">
|
<div className="p-4 border border-gray-600 rounded-lg hover:bg-[#233241] cursor-pointer ">
|
||||||
<SystemStatusContent status={cameraStatus} isError={isError} />
|
<SystemStatusContent status={cameraStatus} isError={isError} />
|
||||||
</Card>
|
</div>
|
||||||
<Card className="p-4 hover:bg-[#233241] cursor-pointer">
|
<div className="p-4 border border-gray-600 rounded-lg hover:bg-[#233241] cursor-pointer">
|
||||||
<h3 className="text-lg">Active Sightings</h3>
|
<h3 className="text-lg">Sightings</h3>
|
||||||
</Card>
|
<p>{totalSightings}</p>
|
||||||
<Card className="p-4 hover:bg-[#233241] cursor-pointer">
|
</div>
|
||||||
|
<div className="p-4 border border-gray-600 rounded-lg hover:bg-[#233241] cursor-pointer">
|
||||||
<PlatesProcessed platesProcessed={platesProcessed} />
|
<PlatesProcessed platesProcessed={platesProcessed} />
|
||||||
</Card>
|
</div>
|
||||||
<Card className="p-4 hover:bg-[#233241] cursor-pointer">
|
<div className="p-4 border border-gray-600 rounded-lg hover:bg-[#233241] cursor-pointer">
|
||||||
<h3 className="text-lg">Up Time</h3> <span className="text-slate-300">{upTime}</span>
|
<h3 className="text-lg">Up Time</h3> <span className="text-slate-300">{upTime}</span>
|
||||||
<h3 className="text-lg">Start Time</h3> <span className="text-slate-300">{startTime}</span>
|
<h3 className="text-lg">Start Time</h3> <span className="text-slate-300">{startTime}</span>
|
||||||
</Card>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Card>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ const SightingStack = ({ sightings }: SightingStackProps) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Card className="p-4 w-full h-full">
|
<Card className="p-4 w-full h-[65vh] overflow-y-auto">
|
||||||
<CardHeader title="Live Sightings" />
|
<CardHeader title="Live Sightings" />
|
||||||
<div className="md:h-[65%]">
|
<div className="md:h-[65%]">
|
||||||
{sightings.map((sighting) => (
|
{sightings.map((sighting) => (
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ const VideoFeed = ({ mostRecentSighting, isLoading, size, modeSetting, isModal =
|
|||||||
const contextMode = cameraSettings.mode;
|
const contextMode = cameraSettings.mode;
|
||||||
const [localMode, setLocalMode] = useState(0);
|
const [localMode, setLocalMode] = useState(0);
|
||||||
const mode = isModal ? localMode : contextMode;
|
const mode = isModal ? localMode : contextMode;
|
||||||
|
console.log(mode);
|
||||||
const { image, plateRect, plateTrack } = useCreateVideoSnapshot(mostRecentSighting);
|
const { image, plateRect, plateTrack } = useCreateVideoSnapshot(mostRecentSighting);
|
||||||
|
|
||||||
const handleModeChange = (newMode: number) => {
|
const handleModeChange = (newMode: number) => {
|
||||||
@@ -33,7 +34,7 @@ const VideoFeed = ({ mostRecentSighting, isLoading, size, modeSetting, isModal =
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const updateSize = () => {
|
const updateSize = () => {
|
||||||
const width = window.innerWidth * 0.57;
|
const width = window.innerWidth * 0.48;
|
||||||
const height = (width * 2) / 3;
|
const height = (width * 2) / 3;
|
||||||
dispatch({ type: "SET_IMAGE_SIZE", payload: { width, height } });
|
dispatch({ type: "SET_IMAGE_SIZE", payload: { width, height } });
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import type { SightingType } from "../../../utils/types";
|
|||||||
|
|
||||||
export const useSightingList = () => {
|
export const useSightingList = () => {
|
||||||
const [sightingList, setSightingList] = useState<SightingType[]>([]);
|
const [sightingList, setSightingList] = useState<SightingType[]>([]);
|
||||||
|
const [totalSightings, setTotalSightings] = useState<number>(0);
|
||||||
const { videoFeedQuery } = useVideoFeed();
|
const { videoFeedQuery } = useVideoFeed();
|
||||||
const latestSighting = videoFeedQuery?.data;
|
const latestSighting = videoFeedQuery?.data;
|
||||||
const lastProcessedRef = useRef<number>(-1);
|
const lastProcessedRef = useRef<number>(-1);
|
||||||
@@ -11,6 +12,8 @@ export const useSightingList = () => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!latestSighting || latestSighting.ref === undefined || latestSighting.ref === -1) return;
|
if (!latestSighting || latestSighting.ref === undefined || latestSighting.ref === -1) return;
|
||||||
|
// eslint-disable-next-line react-hooks/set-state-in-effect
|
||||||
|
setTotalSightings((prev) => (latestSighting.ref! > prev ? latestSighting.ref! : prev));
|
||||||
|
|
||||||
if (latestSighting.ref !== lastProcessedRef.current) {
|
if (latestSighting.ref !== lastProcessedRef.current) {
|
||||||
lastProcessedRef.current = latestSighting.ref;
|
lastProcessedRef.current = latestSighting.ref;
|
||||||
@@ -23,5 +26,5 @@ export const useSightingList = () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [latestSighting, latestSighting?.ref]);
|
}, [latestSighting, latestSighting?.ref]);
|
||||||
return { sightingList, isLoading };
|
return { sightingList, isLoading, totalSightings };
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ const cols = 40;
|
|||||||
const gap = 0;
|
const gap = 0;
|
||||||
|
|
||||||
const VideoFeedSetup = () => {
|
const VideoFeedSetup = () => {
|
||||||
const { latestBitmapRef, isLoading } = useCreateVideoPreviewSnapshot();
|
const { latestBitmapRef, isPreviewLoading } = useCreateVideoPreviewSnapshot();
|
||||||
|
|
||||||
const { state, dispatch } = useCameraSettingsContext();
|
const { state, dispatch } = useCameraSettingsContext();
|
||||||
const cameraMode = state.cameraMode;
|
const cameraMode = state.cameraMode;
|
||||||
const paintedCells = state.regionPainter.paintedCells;
|
const paintedCells = state.regionPainter.paintedCells;
|
||||||
@@ -84,9 +85,10 @@ const VideoFeedSetup = () => {
|
|||||||
updateSize();
|
updateSize();
|
||||||
window.addEventListener("resize", updateSize);
|
window.addEventListener("resize", updateSize);
|
||||||
return () => window.removeEventListener("resize", updateSize);
|
return () => window.removeEventListener("resize", updateSize);
|
||||||
}, []);
|
}, [dispatch]);
|
||||||
|
|
||||||
|
if (isPreviewLoading) return <>Loading Preview...</>;
|
||||||
|
|
||||||
if (isLoading) return <>Loading...</>;
|
|
||||||
return (
|
return (
|
||||||
<div className="mt-[1%]">
|
<div className="mt-[1%]">
|
||||||
<Stage width={size.width} height={size.height} onMouseDown={handleStageMouseDown} onMouseMove={handleMouseMove}>
|
<Stage width={size.width} height={size.height} onMouseDown={handleStageMouseDown} onMouseMove={handleMouseMove}>
|
||||||
|
|||||||
@@ -6,7 +6,9 @@ export const useCreateVideoPreviewSnapshot = () => {
|
|||||||
const { state } = useCameraSettingsContext();
|
const { state } = useCameraSettingsContext();
|
||||||
const { videoPreviewQuery, targetDetectionFeedQuery } = useVideoPreview(state.cameraMode);
|
const { videoPreviewQuery, targetDetectionFeedQuery } = useVideoPreview(state.cameraMode);
|
||||||
const latestBitmapRef = useRef<ImageBitmap | null>(null);
|
const latestBitmapRef = useRef<ImageBitmap | null>(null);
|
||||||
const isLoading = videoPreviewQuery?.isPending || targetDetectionFeedQuery?.isPending;
|
const isPreviewLoading = videoPreviewQuery?.isPending;
|
||||||
|
const isTargetDetectionLoading = targetDetectionFeedQuery?.isPending;
|
||||||
|
|
||||||
let snapshot;
|
let snapshot;
|
||||||
if (state.cameraMode === 0) {
|
if (state.cameraMode === 0) {
|
||||||
snapshot = videoPreviewQuery?.data;
|
snapshot = videoPreviewQuery?.data;
|
||||||
@@ -20,6 +22,7 @@ export const useCreateVideoPreviewSnapshot = () => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const bitmap = await createImageBitmap(imageBlob);
|
const bitmap = await createImageBitmap(imageBlob);
|
||||||
|
|
||||||
latestBitmapRef.current = bitmap;
|
latestBitmapRef.current = bitmap;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
@@ -28,5 +31,10 @@ export const useCreateVideoPreviewSnapshot = () => {
|
|||||||
createImageBitmapFromBlob();
|
createImageBitmapFromBlob();
|
||||||
}, [imageBlob]);
|
}, [imageBlob]);
|
||||||
|
|
||||||
return { latestBitmapRef, isLoading, imageURL: imageBlob ? URL.createObjectURL(imageBlob) : null };
|
return {
|
||||||
|
latestBitmapRef,
|
||||||
|
isPreviewLoading,
|
||||||
|
isTargetDetectionLoading,
|
||||||
|
imageURL: imageBlob ? URL.createObjectURL(imageBlob) : null,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user