feat: update modal and sighting components for improved layout and timestamp display

This commit is contained in:
2025-12-23 12:41:25 +00:00
parent 3b7487da09
commit 9394793669
5 changed files with 40 additions and 11 deletions

View File

@@ -10,7 +10,7 @@ const ModalComponent = ({ isModalOpen, children, close }: ModalComponentProps) =
<Modal <Modal
isOpen={isModalOpen} isOpen={isModalOpen}
onRequestClose={close} onRequestClose={close}
className="bg-[#1e2a38] p-6 rounded-lg shadow-lg w-[95%] mt-[2%] md:w-[55%] z-100 overflow-y-auto border border-gray-600 max-h-[90%]" className="bg-[#1e2a38] p-6 rounded-lg shadow-lg w-[95%] mt-[2%] md:w-[60%] z-100 overflow-y-auto border border-gray-600 max-h-[90%]"
overlayClassName="fixed inset-0 bg-[#1e2a38]/70 flex justify-center items-start z-100" overlayClassName="fixed inset-0 bg-[#1e2a38]/70 flex justify-center items-start z-100"
closeTimeoutMS={200} closeTimeoutMS={200}
style={{ style={{

View File

@@ -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-full">
<CardHeader title="Live Sightings" /> <CardHeader title="Live Sightings" />
<div className="md:h-[65%]"> <div className="md:h-[65%]">
{sightings.map((sighting) => ( {sightings.map((sighting) => (

View File

@@ -1,5 +1,6 @@
import { useCameraSettingsContext } from "../../../../../app/context/CameraSettingsContext"; import { useCameraSettingsContext } from "../../../../../app/context/CameraSettingsContext";
import type { SightingType } from "../../../../../utils/types"; import type { SightingType } from "../../../../../utils/types";
import { timeAgo } from "../../../../../utils/utils";
import NumberPlate from "../../platePatch/NumberPlate"; import NumberPlate from "../../platePatch/NumberPlate";
import VideoFeed from "../../videoFeed/VideoFeed"; import VideoFeed from "../../videoFeed/VideoFeed";
@@ -11,11 +12,13 @@ const SightingModalContent = ({ sighting }: SightingModalContentProps) => {
const { state: cameraSettings } = useCameraSettingsContext(); const { state: cameraSettings } = useCameraSettingsContext();
const size = cameraSettings.imageSize; const size = cameraSettings.imageSize;
const modalImageSize = { width: size.width / 1.5, height: size.height / 1.5 }; const modalImageSize = { width: size.width / 1.5, height: size.height / 1.5 };
const timeStamp = timeAgo(sighting?.timeStampMillis ?? null);
return ( return (
<div> <div>
{sighting ? ( {sighting ? (
<> <>
<div className="flex flex-row items-center justify-between mb-6"> <div className="flex flex-row items-center justify-between mb-6 border-b border-gray-600">
<h2 className="text-2xl font-bold">Sighting Details</h2> <h2 className="text-2xl font-bold">Sighting Details</h2>
<NumberPlate vrm={sighting.vrm} motion={sighting.motion.toLowerCase() === "away"} size="md" /> <NumberPlate vrm={sighting.vrm} motion={sighting.motion.toLowerCase() === "away"} size="md" />
</div> </div>
@@ -24,24 +27,32 @@ const SightingModalContent = ({ sighting }: SightingModalContentProps) => {
<VideoFeed mostRecentSighting={sighting} isLoading={false} size={modalImageSize} isModal={true} /> <VideoFeed mostRecentSighting={sighting} isLoading={false} size={modalImageSize} isModal={true} />
</div> </div>
<div className="space-y-4"> <div className="space-y-4 border p-4 rounded-lg border-gray-600">
<div> <div>
<p className="text-sm text-gray-600">VRM</p> <p className="text-md text-gray-300">VRM</p>
<p className="text-lg font-semibold">{sighting.vrm}</p> <p className="text-lg font-semibold">{sighting.vrm}</p>
</div> </div>
<div> <div>
<p className="text-sm text-gray-600">Timestamp</p> <p className="text-md text-gray-300">Seen</p>
<p className="text-sm">{new Date(sighting.timeStampMillis).toLocaleString()}</p> <p className="text-md">{timeStamp}</p>
</div> </div>
<div> <div>
<p className="text-sm text-gray-600">Motion</p> <p className="text-md text-gray-300">Timestamp</p>
<p className="text-md">{new Date(sighting.timeStampMillis).toLocaleString()}</p>
</div>
<div>
<p className="text-md text-gray-300">Motion</p>
<p className="text-lg font-semibold">{sighting.motion}</p> <p className="text-lg font-semibold">{sighting.motion}</p>
</div> </div>
<div>
<p className="text-md text-gray-300">Radar Speed</p>
<p className="text-lg font-semibold">{sighting.radarSpeed} mph</p>
</div>
</div> </div>
</div> </div>
</> </>
) : ( ) : (
<p>No sighting data available.</p> <p className="text-gray-300">No sighting data available.</p>
)} )}
</div> </div>
); );

View File

@@ -1,4 +1,4 @@
import { Stage, Layer, Image, Rect } from "react-konva"; import { Stage, Layer, Image, Rect, Text } from "react-konva";
import type { SightingType } from "../../../../utils/types"; import type { SightingType } from "../../../../utils/types";
import { useCreateVideoSnapshot } from "../../hooks/useCreateVideoSnapshot"; import { useCreateVideoSnapshot } from "../../hooks/useCreateVideoSnapshot";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
@@ -96,6 +96,23 @@ const VideoFeed = ({ mostRecentSighting, isLoading, size, modeSetting, isModal =
))} ))}
</Layer> </Layer>
)} )}
<Layer>
<Rect
x={5}
y={0.955 * size.height}
width={size.width * 0.35}
height={30}
fill="rgba(255, 255, 255, 0.45)"
cornerRadius={5}
/>
<Text
text={`Overlay Mode: ${mode === 0 ? "None" : mode === 1 ? "Plate Highlight" : "Plate Track"}`}
x={10}
y={0.96 * size.height}
fontSize={16}
fill="#000000"
/>
</Layer>
</Stage> </Stage>
</div> </div>
); );

View File

@@ -5,7 +5,8 @@ export const formatNumberPlate = (plate: string) => {
return formattedPlate; return formattedPlate;
}; };
export const timeAgo = (timestampmili: number) => { export const timeAgo = (timestampmili: number | null) => {
if (timestampmili === null) return "unknown";
const diffMs = Date.now() - new Date(timestampmili).getTime(); const diffMs = Date.now() - new Date(timestampmili).getTime();
const diffMins = Math.floor(diffMs / 60000); const diffMins = Math.floor(diffMs / 60000);
if (diffMins < 60) { if (diffMins < 60) {