import { useCallback, useEffect, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import { isDesktop } from "react-device-detect"; import { FaCalendarAlt } from "react-icons/fa"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { Popover, PopoverContent, PopoverTrigger, } from "@/components/ui/popover"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Label } from "@/components/ui/label"; import { Calendar } from "@/components/ui/calendar"; type CustomSuspensionDialogProps = { open: boolean; onOpenChange: (open: boolean) => void; onConfirm: (minutes: number) => void; }; const ONE_HOUR_MS = 60 * 60 * 1000; function pad(n: number): string { return n.toString().padStart(2, "0"); } function isValidDate(d: Date): boolean { return !Number.isNaN(d.getTime()); } function parsePositive(value: string): number { const n = Number.parseInt(value, 10); if (Number.isNaN(n)) return 0; return Math.max(0, n); } type Tabs = "duration" | "untilTime"; export default function CustomSuspensionDialog({ open, onOpenChange, onConfirm, }: CustomSuspensionDialogProps) { const { t } = useTranslation(["views/settings"]); const [tab, setTab] = useState("duration"); const [hours, setHours] = useState(1); const [minutes, setMinutes] = useState(0); const [until, setUntil] = useState( () => new Date(Date.now() + ONE_HOUR_MS), ); const [calendarOpen, setCalendarOpen] = useState(false); // Reset to defaults whenever the dialog re-opens. useEffect(() => { if (!open) return; setTab("duration"); setHours(1); setMinutes(0); setUntil(new Date(Date.now() + ONE_HOUR_MS)); }, [open]); const totalMinutes = useMemo(() => { if (tab === "duration") { return Math.max(0, Math.floor(hours) * 60 + Math.floor(minutes)); } if (!isValidDate(until)) return 0; return Math.ceil((until.getTime() - Date.now()) / 60_000); }, [hours, minutes, tab, until]); const canApply = useMemo(() => totalMinutes > 0, [totalMinutes]); const handleApply = useCallback(() => { if (!canApply) return; onConfirm(totalMinutes); onOpenChange(false); }, [canApply, onConfirm, onOpenChange, totalMinutes]); return ( {t("notification.customSuspension.title")} {t("notification.customSuspension.description")} setTab(v as Tabs)}> {t("notification.customSuspension.tabDuration")} {t("notification.customSuspension.tabUntilTime")}
setHours(parsePositive(e.target.value))} />
setMinutes(parsePositive(e.target.value))} />
{ if (!day) return; const next = new Date(day); // If `until` is invalid, don't propagate // NaN hours/minutes into the new date - fall back to now. const carry = isValidDate(until) ? until : new Date(); next.setHours( carry.getHours(), carry.getMinutes(), carry.getSeconds(), 0, ); setUntil(next); setCalendarOpen(false); }} /> { // Ignore anything that doesn't parse to a real HH:MM pair. const [h, m] = e.target.value.split(":"); const hh = Number.parseInt(h ?? "", 10); const mm = Number.parseInt(m ?? "", 10); if (Number.isNaN(hh) || Number.isNaN(mm)) return; const base = isValidDate(until) ? until : new Date(); const next = new Date(base); next.setHours(hh, mm, 0, 0); setUntil(next); }} />
{!canApply && (

{t("notification.customSuspension.invalidTime")}

)}
); }