import { useCallback, useState } from "react"; import { Slider } from "@/components/ui/slider"; import { Button } from "@/components/ui/button"; import { Popover, PopoverContent, PopoverTrigger } from "../../ui/popover"; import { useDetailStream } from "@/context/detail-stream-context"; import axios from "axios"; import { useSWRConfig } from "swr"; import { toast } from "sonner"; import { Trans, useTranslation } from "react-i18next"; import { LuExternalLink, LuInfo, LuMinus, LuPlus } from "react-icons/lu"; import { cn } from "@/lib/utils"; import { isMobile } from "react-device-detect"; import { useIsAdmin } from "@/hooks/use-is-admin"; import { useDocDomain } from "@/hooks/use-doc-domain"; import { Link } from "react-router-dom"; const OFFSET_MIN = -2500; const OFFSET_MAX = 2500; const OFFSET_STEP = 50; type Props = { className?: string; }; export default function AnnotationOffsetSlider({ className }: Props) { const { annotationOffset, setAnnotationOffset, camera } = useDetailStream(); const isAdmin = useIsAdmin(); const { getLocaleDocUrl } = useDocDomain(); const { mutate } = useSWRConfig(); const { t } = useTranslation(["views/explore"]); const [isSaving, setIsSaving] = useState(false); const handleChange = useCallback( (values: number[]) => { if (!values || values.length === 0) return; const valueMs = values[0]; setAnnotationOffset(valueMs); }, [setAnnotationOffset], ); const stepOffset = useCallback( (delta: number) => { setAnnotationOffset((prev) => { const next = prev + delta; return Math.max(OFFSET_MIN, Math.min(OFFSET_MAX, next)); }); }, [setAnnotationOffset], ); const reset = useCallback(() => { setAnnotationOffset(0); }, [setAnnotationOffset]); const save = useCallback(async () => { setIsSaving(true); try { // save value in milliseconds to config await axios.put( `config/set?cameras.${camera}.detect.annotation_offset=${annotationOffset}`, { requires_restart: 0 }, ); toast.success( t("trackingDetails.annotationSettings.offset.toast.success", { camera, }), { position: "top-center" }, ); // refresh config await mutate("config"); } catch (e: unknown) { const err = e as { response?: { data?: { message?: string } }; message?: string; }; const errorMessage = err?.response?.data?.message || err?.message || "Unknown error"; toast.error(t("toast.save.error.title", { errorMessage, ns: "common" }), { position: "top-center", }); } finally { setIsSaving(false); } }, [annotationOffset, camera, mutate, t]); return (
{t("trackingDetails.annotationSettings.offset.label")}: {annotationOffset > 0 ? "+" : ""} {annotationOffset}ms
trackingDetails.annotationSettings.offset.millisecondsToOffset {t("trackingDetails.annotationSettings.offset.tips")}
{t("readTheDocumentation", { ns: "common" })}
{isAdmin && ( )}
); }