import Heading from "../ui/heading"; import { Separator } from "../ui/separator"; import { Button } from "@/components/ui/button"; import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover"; import { Drawer, DrawerContent, DrawerTrigger } from "../ui/drawer"; import { useEffect, useMemo, useState } from "react"; import { GeneralFilterContent } from "../filter/ReviewFilterGroup"; import { FaObjectGroup } from "react-icons/fa"; import { ATTRIBUTES, FrigateConfig } from "@/types/frigateConfig"; import useSWR from "swr"; import { isMobile } from "react-device-detect"; import { zodResolver } from "@hookform/resolvers/zod"; import { useForm } from "react-hook-form"; import { z } from "zod"; import { Polygon } from "@/types/canvas"; import { Switch } from "../ui/switch"; import { Label } from "../ui/label"; type ZoneObjectSelectorProps = { camera: string; zoneName: string; updateLabelFilter: (labels: string[] | undefined) => void; }; export function ZoneObjectSelector({ camera, zoneName, updateLabelFilter, }: ZoneObjectSelectorProps) { const { data: config } = useSWR("config"); const cameraConfig = useMemo(() => { if (config && camera) { return config.cameras[camera]; } }, [config, camera]); const allLabels = useMemo(() => { if (!config) { return []; } const labels = new Set(); Object.values(config.cameras).forEach((camera) => { camera.objects.track.forEach((label) => { if (!ATTRIBUTES.includes(label)) { labels.add(label); } }); }); return [...labels].sort(); }, [config]); const zoneLabels = useMemo(() => { if (!cameraConfig || !zoneName) { return []; } const labels = new Set(); cameraConfig.objects.track.forEach((label) => { if (!ATTRIBUTES.includes(label)) { labels.add(label); } }); if (cameraConfig.zones[zoneName]) { cameraConfig.zones[zoneName].objects.forEach((label) => { if (!ATTRIBUTES.includes(label)) { labels.add(label); } }); } return [...labels].sort() || []; }, [cameraConfig, zoneName]); const [currentLabels, setCurrentLabels] = useState( zoneLabels, ); useEffect(() => { updateLabelFilter(currentLabels); }, [currentLabels, updateLabelFilter]); return ( <>
{ if (isChecked) { setCurrentLabels(undefined); } }} />
{allLabels.map((item) => (
{ if (isChecked) { const updatedLabels = currentLabels ? [...currentLabels] : []; updatedLabels.push(item); setCurrentLabels(updatedLabels); } else { const updatedLabels = currentLabels ? [...currentLabels] : []; // can not deselect the last item if (updatedLabels.length > 1) { updatedLabels.splice(updatedLabels.indexOf(item), 1); setCurrentLabels(updatedLabels); } } }} />
))}
); } const formSchema = z.object({ name: z.string().min(2, { message: "Zone name must be at least 2 characters.", }), inertia: z.number(), loitering_time: z.number(), }); type ZoneEditPaneProps = { polygons: Polygon[]; activePolygonIndex?: number; onCancel: () => void; }; export function ZoneEditPane({ polygons, activePolygonIndex, onCancel, }: ZoneEditPaneProps) { const polygon = useMemo(() => { if (polygons && activePolygonIndex !== undefined) { return polygons[activePolygonIndex]; } else { return null; } }, [polygons, activePolygonIndex]); const form = useForm>({ resolver: zodResolver(formSchema), defaultValues: { name: "", inertia: 3, loitering_time: 10, }, }); function onSubmit(values: z.infer) { console.log(values); } if (!polygon) { return; } return ( <> Edit Zone
( Name )} />
( Inertia Specifies how many frames that an object must be in a zone before they are considered in the zone. )} />
( Loitering Time Sets a minimum amount of time in seconds that the object must be in the zone for it to activate. )} />
Objects List of objects that apply to this zone. { // console.log(objects); }} />
); }