import React, { useState } from 'react'; import { Icon } from '@iconify/react'; import FilePreview from '../universal/FilePreview'; import { toast } from 'react-hot-toast'; import { motion, AnimatePresence } from 'framer-motion'; import type { ItemizedExpense } from '../../../schemas/pocketbase'; interface ReceiptFormData { file: File; itemized_expenses: ItemizedExpense[]; tax: number; date: string; location_name: string; location_address: string; notes: string; } interface ReceiptFormProps { onSubmit: (data: ReceiptFormData) => void; onCancel: () => void; } const EXPENSE_CATEGORIES = [ 'Travel', 'Meals', 'Supplies', 'Equipment', 'Software', 'Event Expenses', 'Other' ]; // Add these animation variants const containerVariants = { hidden: { opacity: 0 }, visible: { opacity: 1, transition: { staggerChildren: 0.1 } } }; const itemVariants = { hidden: { opacity: 0, y: 20 }, visible: { opacity: 1, y: 0, transition: { type: "spring", stiffness: 300, damping: 24 } } }; export default function ReceiptForm({ onSubmit, onCancel }: ReceiptFormProps) { const [file, setFile] = useState(null); const [previewUrl, setPreviewUrl] = useState(''); const [itemizedExpenses, setItemizedExpenses] = useState([ { description: '', amount: 0, category: '' } ]); const [tax, setTax] = useState(0); const [date, setDate] = useState(new Date().toISOString().split('T')[0]); const [locationName, setLocationName] = useState(''); const [locationAddress, setLocationAddress] = useState(''); const [notes, setNotes] = useState(''); const [error, setError] = useState(''); const handleFileChange = (e: React.ChangeEvent) => { if (e.target.files && e.target.files[0]) { const selectedFile = e.target.files[0]; // Validate file type if (!selectedFile.type.match('image/*') && selectedFile.type !== 'application/pdf') { toast.error('Only images and PDF files are allowed'); setError('Only images and PDF files are allowed'); return; } // Validate file size (5MB limit) if (selectedFile.size > 5 * 1024 * 1024) { toast.error('File size must be less than 5MB'); setError('File size must be less than 5MB'); return; } setFile(selectedFile); setPreviewUrl(URL.createObjectURL(selectedFile)); setError(''); toast.success('File uploaded successfully'); } }; const addExpenseItem = () => { setItemizedExpenses([...itemizedExpenses, { description: '', amount: 0, category: '' }]); }; const removeExpenseItem = (index: number) => { if (itemizedExpenses.length === 1) return; setItemizedExpenses(itemizedExpenses.filter((_, i) => i !== index)); }; const handleExpenseItemChange = (index: number, field: keyof ItemizedExpense, value: string | number) => { const newItems = [...itemizedExpenses]; newItems[index] = { ...newItems[index], [field]: value }; setItemizedExpenses(newItems); }; const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); if (!file) { setError('Please upload a receipt'); return; } if (!locationName.trim()) { setError('Location name is required'); return; } if (!locationAddress.trim()) { setError('Location address is required'); return; } if (itemizedExpenses.some(item => !item.description || !item.category || item.amount <= 0)) { setError('All expense items must be filled out completely'); return; } onSubmit({ file: file, itemized_expenses: itemizedExpenses, tax, date, location_name: locationName, location_address: locationAddress, notes }); }; return ( {/* Left side - Form */}
{error && ( {error} )} {/* File Upload */}
{/* Date */} setDate(e.target.value)} required /> {/* Location Name */} setLocationName(e.target.value)} required /> {/* Location Address */} setLocationAddress(e.target.value)} required /> {/* Notes */}