feat: add modal component for sighting details with content display
- Implemented ModalComponent for reusable modal functionality. - Created SightingItemModal to manage modal state and display sighting details. - Developed SightingModalContent to render sighting information including video feed and metadata.
This commit is contained in:
@@ -4,25 +4,34 @@ import NumberPlate from "../platePatch/NumberPlate";
|
||||
|
||||
type SightingItemProps = {
|
||||
sighting: SightingType;
|
||||
onOpenModal: () => void;
|
||||
};
|
||||
|
||||
const SightingItem = ({ sighting }: SightingItemProps) => {
|
||||
const SightingItem = ({ sighting, onOpenModal }: SightingItemProps) => {
|
||||
const motion = sighting.motion.toLowerCase() === "away" ? true : false;
|
||||
|
||||
const timeStamp = timeAgo(sighting.timeStampMillis);
|
||||
|
||||
return (
|
||||
<div className="flex flex-row items-center border p-2 mb-2 rounded-lg border-gray-500 justify-between hover:bg-[#233241] hover:cursor-pointer">
|
||||
<div>
|
||||
<>
|
||||
<div
|
||||
className="flex flex-row items-center border p-2 mb-2 rounded-lg border-gray-500 justify-between hover:bg-[#233241] hover:cursor-pointer"
|
||||
onClick={onOpenModal}
|
||||
>
|
||||
<div>
|
||||
<span className="font-light border bg-blue-400 text-blue-800 px-2 rounded">{timeStamp}</span>
|
||||
</div>
|
||||
<div className="text-xl">
|
||||
<span className="font-semibold text-gray-200">{sighting.vrm}</span>
|
||||
<div>
|
||||
<span className="font-light border bg-blue-400 text-blue-800 px-2 rounded">{timeStamp}</span>
|
||||
</div>
|
||||
<div className="text-xl">
|
||||
<span className="font-semibold text-gray-200">{sighting.vrm}</span>
|
||||
</div>
|
||||
</div>
|
||||
{window.innerWidth > 768 ? (
|
||||
<NumberPlate vrm={sighting.vrm} motion={motion} size="md" />
|
||||
) : (
|
||||
<NumberPlate vrm={sighting.vrm} motion={motion} size="sm" />
|
||||
)}
|
||||
</div>
|
||||
<NumberPlate vrm={sighting.vrm} motion={motion} size="md" />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,21 +1,38 @@
|
||||
import { useState } from "react";
|
||||
import CardHeader from "../../../../components/CardHeader";
|
||||
import Card from "../../../../components/ui/Card";
|
||||
import type { SightingType } from "../../../../utils/types";
|
||||
import SightingItem from "./SightingItem";
|
||||
import SightingItemModal from "./sightingItemModal/SightingItemModal";
|
||||
|
||||
type SightingStackProps = {
|
||||
sightings: SightingType[];
|
||||
};
|
||||
const SightingStack = ({ sightings }: SightingStackProps) => {
|
||||
const [isSightingModalOpen, setIsSightingModalOpen] = useState(false);
|
||||
const [currentSighting, setCurrentSighting] = useState<SightingType | null>(null);
|
||||
const handleOpenModal = (sighting: SightingType | null) => {
|
||||
if (!sighting) return;
|
||||
setCurrentSighting(sighting);
|
||||
setIsSightingModalOpen(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<Card className="p-4 w-full h-full ">
|
||||
<CardHeader title="Live Sightings" />
|
||||
<div className="md:h-[65%]">
|
||||
{sightings.map((sighting) => (
|
||||
<SightingItem key={sighting.ref} sighting={sighting} />
|
||||
))}
|
||||
</div>
|
||||
</Card>
|
||||
<>
|
||||
<Card className="p-4 w-full h-full ">
|
||||
<CardHeader title="Live Sightings" />
|
||||
<div className="md:h-[65%]">
|
||||
{sightings.map((sighting) => (
|
||||
<SightingItem key={sighting.ref} sighting={sighting} onOpenModal={() => handleOpenModal(sighting)} />
|
||||
))}
|
||||
</div>
|
||||
</Card>
|
||||
<SightingItemModal
|
||||
isOpen={isSightingModalOpen}
|
||||
close={() => setIsSightingModalOpen(false)}
|
||||
sighting={currentSighting}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import ModalComponent from "../../../../../components/ui/ModalComponent";
|
||||
import type { SightingType } from "../../../../../utils/types";
|
||||
import SightingModalContent from "./SightingModalContent";
|
||||
|
||||
type SightingItemModalProps = {
|
||||
isOpen: boolean;
|
||||
close: () => void;
|
||||
sighting: SightingType | null;
|
||||
};
|
||||
const SightingItemModal = ({ isOpen, close, sighting }: SightingItemModalProps) => {
|
||||
return (
|
||||
<ModalComponent isModalOpen={isOpen} close={close}>
|
||||
<SightingModalContent sighting={sighting} />
|
||||
</ModalComponent>
|
||||
);
|
||||
};
|
||||
|
||||
export default SightingItemModal;
|
||||
@@ -0,0 +1,50 @@
|
||||
import { useCameraSettingsContext } from "../../../../../app/context/CameraSettingsContext";
|
||||
import type { SightingType } from "../../../../../utils/types";
|
||||
import NumberPlate from "../../platePatch/NumberPlate";
|
||||
import VideoFeed from "../../videoFeed/VideoFeed";
|
||||
|
||||
type SightingModalContentProps = {
|
||||
sighting: SightingType | null;
|
||||
};
|
||||
|
||||
const SightingModalContent = ({ sighting }: SightingModalContentProps) => {
|
||||
const { state: cameraSettings } = useCameraSettingsContext();
|
||||
const size = cameraSettings.imageSize;
|
||||
const modalImageSize = { width: size.width / 1.5, height: size.height / 1.5 };
|
||||
return (
|
||||
<div>
|
||||
{sighting ? (
|
||||
<>
|
||||
<div className="flex flex-row items-center justify-between mb-6">
|
||||
<h2 className="text-2xl font-bold">Sighting Details</h2>
|
||||
<NumberPlate vrm={sighting.vrm} motion={sighting.motion.toLowerCase() === "away"} size="md" />
|
||||
</div>
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||
<div className="lg:col-span-2">
|
||||
<VideoFeed mostRecentSighting={sighting} isLoading={false} size={modalImageSize} isModal={true} />
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<p className="text-sm text-gray-600">VRM</p>
|
||||
<p className="text-lg font-semibold">{sighting.vrm}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm text-gray-600">Timestamp</p>
|
||||
<p className="text-sm">{new Date(sighting.timeStampMillis).toLocaleString()}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm text-gray-600">Motion</p>
|
||||
<p className="text-lg font-semibold">{sighting.motion}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<p>No sighting data available.</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SightingModalContent;
|
||||
Reference in New Issue
Block a user