"use client"; import { useState } from "react"; import { AnimatedModal } from "~/components/ui/AnimatedModal.js"; import { ConfirmDialog } from "~/components/ui/ConfirmDialog.js"; import { DateInput } from "~/components/ui/DateInput.js"; import { trpc } from "~/lib/trpc/client.js"; import { toDateInputValue } from "~/lib/format.js"; const RECURRENCE_OPTIONS = [ { value: "", label: "None" }, { value: "daily", label: "Daily" }, { value: "weekly", label: "Weekly" }, { value: "monthly", label: "Monthly" }, ] as const; interface ReminderModalProps { reminder?: { id: string; title: string; body?: string | null; remindAt?: string | Date | null; recurrence?: string | null; link?: string | null; } | null; onClose: () => void; onSuccess: () => void; } function toTimeInputValue(date: Date | string | null | undefined): string { if (!date) return "09:00"; const d = typeof date === "string" ? new Date(date) : date; return `${String(d.getHours()).padStart(2, "0")}:${String(d.getMinutes()).padStart(2, "0")}`; } export function ReminderModal({ reminder, onClose, onSuccess }: ReminderModalProps) { const isEdit = !!reminder; const [title, setTitle] = useState(reminder?.title ?? ""); const [body, setBody] = useState(reminder?.body ?? ""); const [remindDate, setRemindDate] = useState(toDateInputValue(reminder?.remindAt)); const [remindTime, setRemindTime] = useState(toTimeInputValue(reminder?.remindAt)); const [recurrence, setRecurrence] = useState(reminder?.recurrence ?? ""); const [link, setLink] = useState(reminder?.link ?? ""); const [serverError, setServerError] = useState(null); const [confirmDelete, setConfirmDelete] = useState(false); const utils = trpc.useUtils(); const createMutation = trpc.notification.createReminder.useMutation({ onSuccess: async () => { await utils.notification.listReminders.invalidate(); await utils.notification.list.invalidate(); onSuccess(); }, onError: (err) => setServerError(err.message), }); const updateMutation = trpc.notification.updateReminder.useMutation({ onSuccess: async () => { await utils.notification.listReminders.invalidate(); await utils.notification.list.invalidate(); onSuccess(); }, onError: (err) => setServerError(err.message), }); const deleteMutation = trpc.notification.deleteReminder.useMutation({ onSuccess: async () => { await utils.notification.listReminders.invalidate(); await utils.notification.list.invalidate(); onSuccess(); }, onError: (err) => setServerError(err.message), }); const isPending = createMutation.isPending || updateMutation.isPending || deleteMutation.isPending; function buildRemindAt(): Date | null { if (!remindDate) return null; const [hours, minutes] = remindTime.split(":").map(Number); const d = new Date(remindDate + "T00:00:00"); d.setHours(hours ?? 9, minutes ?? 0, 0, 0); return d; } function handleSubmit(e: React.FormEvent) { e.preventDefault(); setServerError(null); const remindAt = buildRemindAt(); if (!title.trim()) { setServerError("Title is required."); return; } if (!remindAt) { setServerError("Remind date is required."); return; } if (isEdit && reminder) { updateMutation.mutate({ id: reminder.id, title: title.trim(), body: body.trim() || undefined, remindAt, recurrence: (recurrence || null) as "daily" | "weekly" | "monthly" | null, }); } else { createMutation.mutate({ title: title.trim(), body: body.trim() || undefined, remindAt, ...(recurrence ? { recurrence: recurrence as "daily" | "weekly" | "monthly" } : {}), ...(link.trim() ? { link: link.trim() } : {}), }); } } function handleDelete() { if (!reminder) return; setConfirmDelete(true); } const inputClass = "w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-brand-500 text-sm dark:bg-gray-900 dark:text-gray-100"; const labelClass = "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"; return ( <> {/* Header */}

{isEdit ? "Edit Reminder" : "New Reminder"}

{/* Title */}
setTitle(e.target.value)} maxLength={200} className={inputClass} required placeholder="Reminder title..." />
{/* Body */}