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:
2025-12-23 10:37:02 +00:00
parent a299960dfb
commit 3b7487da09
15 changed files with 574 additions and 717 deletions

View File

@@ -7,26 +7,36 @@ import { useCameraSettingsContext } from "../../../../app/context/CameraSettings
type VideoFeedProps = {
mostRecentSighting: SightingType;
isLoading: boolean;
size: { width: number; height: number };
modeSetting?: number;
isModal?: boolean;
};
const VideoFeed = ({ mostRecentSighting, isLoading }: VideoFeedProps) => {
const VideoFeed = ({ mostRecentSighting, isLoading, size, modeSetting, isModal = false }: VideoFeedProps) => {
const { state: cameraSettings, dispatch } = useCameraSettingsContext();
const mode = cameraSettings.mode;
const [size, setSize] = useState<{ width: number; height: number }>({ width: 1280, height: 960 });
const contextMode = cameraSettings.mode;
const [localMode, setLocalMode] = useState(0);
const mode = isModal ? localMode : contextMode;
const { image, plateRect, plateTrack } = useCreateVideoSnapshot(mostRecentSighting);
const handleModeChange = (newMode: number) => {
if (newMode > 2) dispatch({ type: "SET_MODE", payload: 0 });
else dispatch({ type: "SET_MODE", payload: newMode });
if (modeSetting) return;
const nextMode = newMode > 2 ? 0 : newMode;
if (isModal) {
setLocalMode(nextMode);
} else {
dispatch({ type: "SET_MODE", payload: nextMode });
}
};
useEffect(() => {
const updateSize = () => {
const width = window.innerWidth * 0.48;
const height = (width * 2) / 3;
setSize({ width, height });
dispatch({ type: "SET_IMAGE_SIZE", payload: { width, height } });
};
updateSize();
window.addEventListener("resize", updateSize);
@@ -39,20 +49,22 @@ const VideoFeed = ({ mostRecentSighting, isLoading }: VideoFeedProps) => {
<div className="w-[70%] mt-[2%]">
<Stage width={size.width} height={size.height} onClick={() => handleModeChange(mode + 1)}>
<Layer>
<Image
image={image}
height={size.height}
width={size.width}
onMouseEnter={(e) => {
const container = e.target.getStage()?.container();
if (container) container.style.cursor = "pointer";
}}
onMouseLeave={(e) => {
const container = e.target.getStage()?.container();
if (container) container.style.cursor = "default";
}}
cornerRadius={10}
/>
{image && (
<Image
image={image}
height={size.height}
width={size.width}
onMouseEnter={(e) => {
const container = e.target.getStage()?.container();
if (container) container.style.cursor = "pointer";
}}
onMouseLeave={(e) => {
const container = e.target.getStage()?.container();
if (container) container.style.cursor = "default";
}}
cornerRadius={10}
/>
)}
</Layer>
{plateRect && mode === 1 && (
<Layer>