import { baseUrl } from "@/api/baseUrl"; import ExportCard from "@/components/card/ExportCard"; import { AlertDialog, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from "@/components/ui/alert-dialog"; import { Button } from "@/components/ui/button"; import { Calendar } from "@/components/ui/calendar"; import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog"; import { Drawer, DrawerContent, DrawerTrigger } from "@/components/ui/drawer"; import { DropdownMenuRadioGroup, DropdownMenuTrigger, DropdownMenu, DropdownMenuContent, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuRadioItem, } from "@/components/ui/dropdown-menu"; import { Toaster } from "@/components/ui/sonner"; import { FrigateConfig } from "@/types/frigateConfig"; import axios from "axios"; import { format } from "date-fns"; import { useCallback, useEffect, useState } from "react"; import { DateRange } from "react-day-picker"; import { isDesktop } from "react-device-detect"; import { useLocation } from "react-router-dom"; import { toast } from "sonner"; import useSWR from "swr"; type ExportItem = { name: string; }; function Export() { const { data: config } = useSWR("config"); const { data: exports, mutate } = useSWR( "exports/", (url: string) => axios({ baseURL: baseUrl, url }).then((res) => res.data), ); const location = useLocation(); const [dialogOpen, setDialogOpen] = useState(false); // Export States const [camera, setCamera] = useState(); const [playback, setPlayback] = useState(); const currentDate = new Date(); currentDate.setHours(0, 0, 0, 0); const [date, setDate] = useState({ from: currentDate, }); const [startTime, setStartTime] = useState("00:00:00"); const [endTime, setEndTime] = useState("23:59:59"); const [deleteClip, setDeleteClip] = useState(); const onHandleExport = () => { if (!camera) { toast.error("A camera needs to be selected.", { position: "top-center" }); return; } if (!playback) { toast.error("A playback factor needs to be selected.", { position: "top-center", }); return; } if (!date?.from || !startTime || !endTime) { toast.error("A start and end time needs to be selected", { position: "top-center", }); return; } const startDate = new Date(date.from.getTime()); const [startHour, startMin, startSec] = startTime.split(":"); startDate.setHours( parseInt(startHour), parseInt(startMin), parseInt(startSec), 0, ); const start = startDate.getTime() / 1000; const endDate = new Date((date.to || date.from).getTime()); const [endHour, endMin, endSec] = endTime.split(":"); endDate.setHours(parseInt(endHour), parseInt(endMin), parseInt(endSec), 0); const end = endDate.getTime() / 1000; if (end <= start) { toast.error("The end time must be after the start time.", { position: "top-center", }); return; } axios .post(`export/${camera}/start/${start}/end/${end}`, { playback }) .then((response) => { if (response.status == 200) { toast.success( "Successfully started export. View the file in the /exports folder.", { position: "top-center" }, ); } mutate(); }) .catch((error) => { if (error.response?.data?.message) { toast.error( `Failed to start export: ${error.response.data.message}`, { position: "top-center" }, ); } else { toast.error(`Failed to start export: ${error.message}`, { position: "top-center", }); } }); }; const onHandleDelete = useCallback(() => { if (!deleteClip) { return; } axios.delete(`export/${deleteClip}`).then((response) => { if (response.status == 200) { setDeleteClip(undefined); mutate(); } }); }, [deleteClip, mutate]); const Create = isDesktop ? Dialog : Drawer; const Trigger = isDesktop ? DialogTrigger : DrawerTrigger; const Content = isDesktop ? DialogContent : DrawerContent; useEffect(() => { if (location.state && location.state.start && location.state.end) { const startTimeString = format( new Date(location.state.start * 1000), "HH:mm:ss", ); const endTimeString = format( new Date(location.state.end * 1000), "HH:mm:ss", ); setStartTime(startTimeString); setEndTime(endTimeString); setDialogOpen(true); } }, [location.state]); return (
setDeleteClip(undefined)} > Delete Export Confirm deletion of {deleteClip}. Cancel
Select Camera {Object.keys(config?.cameras || {}).map((item) => ( {item.replaceAll("_", " ")} ))} Select Playback Realtime Timelapse
setStartTime(e.target.value)} /> setEndTime(e.target.value)} />
{`${ date?.from ? format(date?.from, "LLL dd, y") : "" } ${startTime} -> ${ date?.to ? format(date?.to, "LLL dd, y") : "" } ${endTime}`}
{exports && (
{Object.values(exports).map((item) => ( setDeleteClip(file)} /> ))}
)}
); } export default Export;