"use client"; import type React from "react"; import { useEffect, useRef } from "react"; import TagInput from "@/shared/components/forms/tag-input"; import ToggleButtonGroup from "@/shared/components/forms/toggle-button-group"; import DatePicker from "@/shared/components/forms/date-picker"; export type EntryDetailsForm = { amountDollars: string; occurredAt: string; necessity: "NECESSARY" | "BOTH" | "UNNECESSARY"; notes: string; tags: string[]; entryType: "SPENDING" | "INCOME"; }; 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({ entryType })} ariaLabel="Entry type" sizeClassName="px-4 py-2.5 text-xs font-semibold" options={[ { value: "SPENDING", label: "Spending" }, { value: "INCOME", label: "Income" } ]} />
onChange({ occurredAt })} required className={`mt-1 ${dateChanged ? changedInputClass : ""}`} />
onChange({ necessity })} ariaLabel="Necessity" className={`flex items-center gap-2 rounded-full border border-accent-weak bg-panel ${necessityChanged ? changedInputClass : ""}`} 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" } ]} />