- Enhanced Dashboard and SystemOverview components with totalSightings prop

- improved layout and loading states in VideoFeed and SightingStack components.
This commit is contained in:
2026-01-12 15:38:01 +00:00
parent 1555221825
commit 2ecc39317d
7 changed files with 50 additions and 29 deletions

View File

@@ -6,22 +6,24 @@ import { useCameraSettingsContext } from "../../app/context/CameraSettingsContex
import SystemOverview from "./SystemOverview/SystemOverview";
const Dashboard = () => {
const { sightingList, isLoading } = useSightingList();
const { sightingList, isLoading, totalSightings } = useSightingList();
const { state: cameraSettings } = useCameraSettingsContext();
const size = cameraSettings.imageSize;
const mostRecent = sightingList[0];
return (
<div>
<SystemOverview />
<div className="grid grid-cols-1 md:grid-cols-12 gap-2 md:gap-5 mt-4">
<div className="col-span-7">
<div className="flex flex-col">
<div className="grid grid-cols-1 md:grid-cols-2 gap-2 md:gap-5">
<VideoFeed mostRecentSighting={mostRecent} isLoading={isLoading} size={size} />
<SightingStack sightings={sightingList} />
</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} />
</div>
<div className="col-span-5">
<SightingStack sightings={sightingList} />
<div className="col-span-2">
<SystemOverview totalSightings={totalSightings} />
</div>
</div>
</div>

View File

@@ -5,7 +5,11 @@ import { useGetSystemHealth } from "../hooks/useGetSystemHealth";
import PlatesProcessed from "./PlatesProcessed";
import SystemStatusContent from "./SystemStatusContent";
const SystemOverview = () => {
type SystemOverViewProps = {
totalSightings: number;
};
const SystemOverview = ({ totalSightings }: SystemOverViewProps) => {
const { systemHealthQuery } = useGetSystemHealth();
const { storeQuery } = useGetStore();
@@ -19,23 +23,24 @@ const SystemOverview = () => {
return <div>Loading system overview...</div>;
}
return (
<div>
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
<Card className="p-4 hover:bg-[#233241] cursor-pointer">
<Card className="p-4">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="p-4 border border-gray-600 rounded-lg hover:bg-[#233241] cursor-pointer ">
<SystemStatusContent status={cameraStatus} isError={isError} />
</Card>
<Card className="p-4 hover:bg-[#233241] cursor-pointer">
<h3 className="text-lg">Active Sightings</h3>
</Card>
<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">
<h3 className="text-lg">Sightings</h3>
<p>{totalSightings}</p>
</div>
<div className="p-4 border border-gray-600 rounded-lg hover:bg-[#233241] cursor-pointer">
<PlatesProcessed platesProcessed={platesProcessed} />
</Card>
<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">
<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>
</div>
</div>
</Card>
</div>
</div>
);
};

View File

@@ -19,7 +19,7 @@ const SightingStack = ({ sightings }: SightingStackProps) => {
return (
<>
<Card className="p-4 w-full h-full">
<Card className="p-4 w-full h-[65vh] overflow-y-auto">
<CardHeader title="Live Sightings" />
<div className="md:h-[65%]">
{sightings.map((sighting) => (

View File

@@ -17,6 +17,7 @@ const VideoFeed = ({ mostRecentSighting, isLoading, size, modeSetting, isModal =
const contextMode = cameraSettings.mode;
const [localMode, setLocalMode] = useState(0);
const mode = isModal ? localMode : contextMode;
console.log(mode);
const { image, plateRect, plateTrack } = useCreateVideoSnapshot(mostRecentSighting);
const handleModeChange = (newMode: number) => {
@@ -33,7 +34,7 @@ const VideoFeed = ({ mostRecentSighting, isLoading, size, modeSetting, isModal =
useEffect(() => {
const updateSize = () => {
const width = window.innerWidth * 0.57;
const width = window.innerWidth * 0.48;
const height = (width * 2) / 3;
dispatch({ type: "SET_IMAGE_SIZE", payload: { width, height } });
};

View File

@@ -4,6 +4,7 @@ import type { SightingType } from "../../../utils/types";
export const useSightingList = () => {
const [sightingList, setSightingList] = useState<SightingType[]>([]);
const [totalSightings, setTotalSightings] = useState<number>(0);
const { videoFeedQuery } = useVideoFeed();
const latestSighting = videoFeedQuery?.data;
const lastProcessedRef = useRef<number>(-1);
@@ -11,6 +12,8 @@ export const useSightingList = () => {
useEffect(() => {
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) {
lastProcessedRef.current = latestSighting.ref;
@@ -23,5 +26,5 @@ export const useSightingList = () => {
});
}
}, [latestSighting, latestSighting?.ref]);
return { sightingList, isLoading };
return { sightingList, isLoading, totalSightings };
};

View File

@@ -13,7 +13,8 @@ const cols = 40;
const gap = 0;
const VideoFeedSetup = () => {
const { latestBitmapRef, isLoading } = useCreateVideoPreviewSnapshot();
const { latestBitmapRef, isPreviewLoading } = useCreateVideoPreviewSnapshot();
const { state, dispatch } = useCameraSettingsContext();
const cameraMode = state.cameraMode;
const paintedCells = state.regionPainter.paintedCells;
@@ -84,9 +85,10 @@ const VideoFeedSetup = () => {
updateSize();
window.addEventListener("resize", updateSize);
return () => window.removeEventListener("resize", updateSize);
}, []);
}, [dispatch]);
if (isPreviewLoading) return <>Loading Preview...</>;
if (isLoading) return <>Loading...</>;
return (
<div className="mt-[1%]">
<Stage width={size.width} height={size.height} onMouseDown={handleStageMouseDown} onMouseMove={handleMouseMove}>

View File

@@ -6,7 +6,9 @@ export const useCreateVideoPreviewSnapshot = () => {
const { state } = useCameraSettingsContext();
const { videoPreviewQuery, targetDetectionFeedQuery } = useVideoPreview(state.cameraMode);
const latestBitmapRef = useRef<ImageBitmap | null>(null);
const isLoading = videoPreviewQuery?.isPending || targetDetectionFeedQuery?.isPending;
const isPreviewLoading = videoPreviewQuery?.isPending;
const isTargetDetectionLoading = targetDetectionFeedQuery?.isPending;
let snapshot;
if (state.cameraMode === 0) {
snapshot = videoPreviewQuery?.data;
@@ -20,6 +22,7 @@ export const useCreateVideoPreviewSnapshot = () => {
try {
const bitmap = await createImageBitmap(imageBlob);
latestBitmapRef.current = bitmap;
} catch (error) {
console.log(error);
@@ -28,5 +31,10 @@ export const useCreateVideoPreviewSnapshot = () => {
createImageBitmapFromBlob();
}, [imageBlob]);
return { latestBitmapRef, isLoading, imageURL: imageBlob ? URL.createObjectURL(imageBlob) : null };
return {
latestBitmapRef,
isPreviewLoading,
isTargetDetectionLoading,
imageURL: imageBlob ? URL.createObjectURL(imageBlob) : null,
};
};