"use client" import { useNotification } from "@/app/(app)/context" import { analyzeFileAction, deleteUnsortedFileAction, saveFileAsTransactionAction } from "@/app/(app)/unsorted/actions" import { CurrencyConverterTool } from "@/components/agents/currency-converter" import { ItemsDetectTool } from "@/components/agents/items-detect" import ToolWindow from "@/components/agents/tool-window" import { FormError } from "@/components/forms/error" import { FormSelectCategory } from "@/components/forms/select-category" import { FormSelectCurrency } from "@/components/forms/select-currency" import { FormSelectProject } from "@/components/forms/select-project" import { FormSelectType } from "@/components/forms/select-type" import { FormInput, FormTextarea } from "@/components/forms/simple" import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" import { Category, Currency, Field, File, Project } from "@/prisma/client" import { format } from "date-fns" import { ArrowDownToLine, Brain, Loader2, Trash2 } from "lucide-react" import { startTransition, useActionState, useMemo, useState } from "react" export default function AnalyzeForm({ file, categories, projects, currencies, fields, settings, }: { file: File categories: Category[] projects: Project[] currencies: Currency[] fields: Field[] settings: Record }) { const { showNotification } = useNotification() const [isAnalyzing, setIsAnalyzing] = useState(false) const [analyzeStep, setAnalyzeStep] = useState("") const [analyzeError, setAnalyzeError] = useState("") const [deleteState, deleteAction, isDeleting] = useActionState(deleteUnsortedFileAction, null) const [isSaving, setIsSaving] = useState(false) const [saveError, setSaveError] = useState("") const fieldMap = useMemo(() => { return fields.reduce( (acc, field) => { acc[field.code] = field return acc }, {} as Record ) }, [fields]) const extraFields = useMemo(() => fields.filter((field) => field.isExtra), [fields]) const initialFormState = useMemo(() => { const baseState = { name: file.filename, merchant: "", description: "", type: settings.default_type, total: 0.0, currencyCode: settings.default_currency, convertedTotal: 0.0, convertedCurrencyCode: settings.default_currency, categoryCode: settings.default_category, projectCode: settings.default_project, issuedAt: "", note: "", text: "", items: [], } // Add extra fields const extraFieldsState = extraFields.reduce( (acc, field) => { acc[field.code] = "" return acc }, {} as Record ) // Load cached results if they exist const cachedResults = file.cachedParseResult ? Object.fromEntries( Object.entries(file.cachedParseResult as Record).filter( ([_, value]) => value !== null && value !== undefined && value !== "" ) ) : {} return { ...baseState, ...extraFieldsState, ...cachedResults, } }, [file.filename, settings, extraFields, file.cachedParseResult]) const [formData, setFormData] = useState(initialFormState) async function saveAsTransaction(formData: FormData) { setSaveError("") setIsSaving(true) startTransition(async () => { const result = await saveFileAsTransactionAction(null, formData) setIsSaving(false) if (result.success) { showNotification({ code: "global.banner", message: "Saved!", type: "success" }) showNotification({ code: "sidebar.transactions", message: "new" }) setTimeout(() => showNotification({ code: "sidebar.transactions", message: "" }), 3000) } else { setSaveError(result.error ? result.error : "Something went wrong...") showNotification({ code: "global.banner", message: "Failed to save", type: "failed" }) } }) } const startAnalyze = async () => { setIsAnalyzing(true) setAnalyzeError("") try { setAnalyzeStep("Analyzing...") const results = await analyzeFileAction(file, settings, fields, categories, projects) console.log("Analysis results:", results) if (!results.success) { setAnalyzeError(results.error ? results.error : "Something went wrong...") } else { const nonEmptyFields = Object.fromEntries( Object.entries(results.data?.output || {}).filter( ([_, value]) => value !== null && value !== undefined && value !== "" ) ) setFormData({ ...formData, ...nonEmptyFields }) } } catch (error) { console.error("Analysis failed:", error) setAnalyzeError(error instanceof Error ? error.message : "Analysis failed") } finally { setIsAnalyzing(false) setAnalyzeStep("") } } return ( <> {file.isSplitted ? (
This file has been split up
) : ( )}
{analyzeError && {analyzeError}}
setFormData((prev) => ({ ...prev, name: e.target.value }))} required={fieldMap.name.isRequired} /> setFormData((prev) => ({ ...prev, merchant: e.target.value }))} hideIfEmpty={!fieldMap.merchant.isVisibleInAnalysis} required={fieldMap.merchant.isRequired} /> setFormData((prev) => ({ ...prev, description: e.target.value }))} hideIfEmpty={!fieldMap.description.isVisibleInAnalysis} required={fieldMap.description.isRequired} />
{ const newValue = parseFloat(e.target.value || "0") !isNaN(newValue) && setFormData((prev) => ({ ...prev, total: newValue })) }} className="w-32" required={fieldMap.total.isRequired} /> setFormData((prev) => ({ ...prev, currencyCode: value }))} hideIfEmpty={!fieldMap.currencyCode.isVisibleInAnalysis} required={fieldMap.currencyCode.isRequired} /> setFormData((prev) => ({ ...prev, type: value }))} hideIfEmpty={!fieldMap.type.isVisibleInAnalysis} required={fieldMap.type.isRequired} />
{formData.total != 0 && formData.currencyCode && formData.currencyCode !== settings.default_currency && ( setFormData((prev) => ({ ...prev, convertedTotal: value }))} /> )}
setFormData((prev) => ({ ...prev, issuedAt: e.target.value }))} hideIfEmpty={!fieldMap.issuedAt.isVisibleInAnalysis} required={fieldMap.issuedAt.isRequired} />
setFormData((prev) => ({ ...prev, categoryCode: value }))} placeholder="Select Category" hideIfEmpty={!fieldMap.categoryCode.isVisibleInAnalysis} required={fieldMap.categoryCode.isRequired} /> {projects.length > 0 && ( setFormData((prev) => ({ ...prev, projectCode: value }))} placeholder="Select Project" hideIfEmpty={!fieldMap.projectCode.isVisibleInAnalysis} required={fieldMap.projectCode.isRequired} /> )}
setFormData((prev) => ({ ...prev, note: e.target.value }))} hideIfEmpty={!fieldMap.note.isVisibleInAnalysis} required={fieldMap.note.isRequired} /> {extraFields.map((field) => ( setFormData((prev) => ({ ...prev, [field.code]: e.target.value }))} hideIfEmpty={!field.isVisibleInAnalysis} required={field.isRequired} /> ))} {formData.items && formData.items.length > 0 && ( )}
setFormData((prev) => ({ ...prev, text: e.target.value }))} hideIfEmpty={!fieldMap.text.isVisibleInAnalysis} />
{deleteState?.error && {deleteState.error}} {saveError && {saveError}}
) }