"use client"; import type React from "react"; import { useEffect, useRef } from "react"; import TagInput from "@/components/tag-input"; export type EntryDetailsForm = { amountDollars: string; occurredAt: string; necessity: string; notes: string; tags: string[]; entryType: "SPENDING" | "INCOME"; isRecurring: boolean; frequency: "DAILY" | "WEEKLY" | "BIWEEKLY" | "MONTHLY" | "QUARTERLY" | "YEARLY"; intervalCount: number; endCondition: "NEVER" | "AFTER_COUNT" | "BY_DATE"; endCount: string; endDate: string; }; type EntryDetailsModalProps = { isOpen: boolean; form: EntryDetailsForm; originalForm: EntryDetailsForm | 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; onPrev: () => void; onNext: () => void; loopHintPrev: string; loopHintNext: string; canNavigate: boolean; }; export default function EntryDetailsModal({ isOpen, form, originalForm, isDirty, error, onClose, onSubmit, onRequestDelete, onRevert, onChange, onAddTag, onToggleTag, removedTags, tagSuggestions, emptyTagActionLabel, emptyTagActionDisabled = false, onEmptyTagAction, onPrev, onNext, loopHintPrev, loopHintNext, canNavigate }: EntryDetailsModalProps) { 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 tagsChanged = normalizeTags(currentTags) !== normalizeTags(baselineTags); const addedTags = currentTags.filter(tag => !baselineTags.some(base => base.toLowerCase() === tag.toLowerCase())); const amountChanged = form.amountDollars !== baseline.amountDollars; const dateChanged = form.occurredAt !== baseline.occurredAt; const necessityChanged = form.necessity !== baseline.necessity; const notesChanged = form.notes !== baseline.notes; const changedInputClass = "border-2 border-[color:var(--color-accent)]"; const formRef = useRef(null); const touchStartX = useRef(null); const touchDeltaX = useRef(0); function handleTouchStart(event: React.TouchEvent) { touchStartX.current = event.touches[0]?.clientX ?? null; touchDeltaX.current = 0; } function handleTouchMove(event: React.TouchEvent) { if (touchStartX.current === null) return; touchDeltaX.current = event.touches[0]?.clientX - touchStartX.current; } function handleTouchEnd() { if (!canNavigate) return; const delta = touchDeltaX.current; touchStartX.current = null; touchDeltaX.current = 0; if (Math.abs(delta) < 60) return; if (delta > 0) onPrev(); else onNext(); } 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()} onTouchStart={handleTouchStart} onTouchMove={handleTouchMove} onTouchEnd={handleTouchEnd} >

Entry 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({ occurredAt: e.target.value })} required />
{([ { value: "NECESSARY", label: "Necessary" }, { value: "BOTH", label: "Both" }, { value: "UNNECESSARY", label: "Unnecessary" } ] as const).map(option => ( ))}
{form.isRecurring ? (
Frequency Conditions
onChange({ intervalCount: Number(e.target.value || 1) })} />
{([ { value: "NEVER", label: "Forever" }, { value: "BY_DATE", label: "Until" }, { value: "AFTER_COUNT", label: "After" } ] as const).map(option => ( ))}
{form.endCondition === "AFTER_COUNT" ? ( onChange({ endCount: e.target.value })} /> ) : null} {form.endCondition === "BY_DATE" ? (
onChange({ endDate: e.target.value })} />
) : null}
) : null}