"use client"; import type React from "react"; import { useEffect, useRef } from "react"; import DatePicker from "@/components/date-picker"; import TagInput from "@/components/tag-input"; import ToggleButtonGroup from "@/components/toggle-button-group"; import type { ScheduleEndCondition, ScheduleFrequency } from "@/lib/shared/types"; export type ScheduleDetailsForm = { amountDollars: string; startsOn: string; necessity: "NECESSARY" | "BOTH" | "UNNECESSARY"; notes: string; tags: string[]; entryType: "SPENDING" | "INCOME"; frequency: ScheduleFrequency; intervalCount: number; endCondition: ScheduleEndCondition; endCount: string; endDate: string; nextRunOn: string; isActive: boolean; }; type ScheduleDetailsModalProps = { isOpen: boolean; form: ScheduleDetailsForm; originalForm: ScheduleDetailsForm | null; isDirty: boolean; error: string; onClose: () => void; onSubmit: (event: React.FormEvent) => void; onRequestDelete: () => void; onRevert: () => void; onChange: (next: Partial) => void; onAddTag: (tag: string) => void; onToggleTag: (tag: string) => void; removedTags: string[]; tagSuggestions: string[]; emptyTagActionLabel?: string; emptyTagActionDisabled?: boolean; onEmptyTagAction?: () => void; }; export default function ScheduleDetailsModal({ isOpen, form, originalForm, isDirty, error, onClose, onSubmit, onRequestDelete, onRevert, onChange, onAddTag, onToggleTag, removedTags, tagSuggestions, emptyTagActionLabel, emptyTagActionDisabled = false, onEmptyTagAction }: ScheduleDetailsModalProps) { const baseline = originalForm ?? form; const removedSet = new Set(removedTags.map(tag => tag.toLowerCase())); const currentTags = form.tags.filter(tag => !removedSet.has(tag.toLowerCase())); const normalizeTags = (tags: string[]) => tags.map(tag => tag.toLowerCase()).sort().join("|"); const baselineTags = baseline.tags || []; const addedTags = currentTags.filter(tag => !baselineTags.some(base => base.toLowerCase() === tag.toLowerCase())); const formRef = useRef(null); useEffect(() => { if (!isOpen) return; function handleKeyDown(event: KeyboardEvent) { if (event.key === "Escape") onClose(); } window.addEventListener("keydown", handleKeyDown); return () => window.removeEventListener("keydown", handleKeyDown); }, [isOpen, onClose]); if (!isOpen) return null; return (
event.stopPropagation()}>

Schedule Details

{ if (event.key !== "Enter" || event.defaultPrevented || event.shiftKey) return; const target = event.target as HTMLElement; if (target?.tagName === "TEXTAREA") return; event.preventDefault(); formRef.current?.requestSubmit(); }} className="mt-3 grid gap-3 md:grid-cols-2" >
onChange({ entryType })} ariaLabel="Entry type" sizeClassName="px-4 py-2.5 text-xs font-semibold" options={[ { value: "SPENDING", label: "Spending" }, { value: "INCOME", label: "Income" } ]} /> onChange({ isActive: value === "ACTIVE" })} ariaLabel="Schedule active status" sizeClassName="px-3 py-2 text-xs font-semibold" options={[ { value: "ACTIVE", label: "Active" }, { value: "PAUSED", label: "Paused" } ]} />
onChange({ startsOn })} required className="mt-1" />
onChange({ necessity })} ariaLabel="Necessity" className="mt-1 flex items-center gap-2 rounded-full border border-accent-weak bg-panel" sizeClassName="px-3 py-2.5 text-xs font-semibold" options={[ { value: "NECESSARY", label: "Necessary", className: "flex-1" }, { value: "BOTH", label: "Both", className: "flex-1" }, { value: "UNNECESSARY", label: "Unnecessary", className: "flex-1" } ]} />
Every
onChange({ intervalCount: Number(e.target.value || 1) })} /> onChange({ endCondition })} ariaLabel="End condition" className="flex items-center gap-1 rounded-full border border-accent-weak bg-panel" sizeClassName="px-3 py-3 text-xs font-semibold" options={[ { value: "NEVER", label: "Forever" }, { value: "BY_DATE", label: "Until" }, { value: "AFTER_COUNT", label: "After" } ]} /> {form.endCondition === "AFTER_COUNT" ? ( onChange({ endCount: e.target.value })} /> ) : null} {form.endCondition === "BY_DATE" ? ( onChange({ endDate })} showWeekButtons={false} centerInput /> ) : null}
Next run onChange({ nextRunOn })} required className="mt-1" />