spdniloy/anycoder-380d34cb
0
1import { useState, useEffect } from 'react';2import { X, Plus, Edit2 } from 'lucide-react';3 4const INCOME_CATEGORIES = [5 'Sales',6 'Services',7 'Consulting',8 'Subscriptions',9 'Refunds',10 'Other Income',11];12 13const EXPENSE_CATEGORIES = [14 'Supplies',15 'Equipment',16 'Marketing',17 'Utilities',18 'Software',19 'Travel',20 'Professional Services',21 'Taxes',22 'Other',23];24 25export default function TransactionModal({26 isOpen,27 onClose,28 onSubmit,29 type = 'income',30 editingTransaction = null,31}) {32 const [formData, setFormData] = useState({33 amount: '',34 category: '',35 description: '',36 date: new Date().toISOString().split('T')[0],37 });38 39 useEffect(() => {40 if (editingTransaction) {41 setFormData({42 amount: editingTransaction.amount.toString(),43 category: editingTransaction.category,44 description: editingTransaction.description || '',45 date: editingTransaction.date,46 });47 } else {48 setFormData({49 amount: '',50 category: '',51 description: '',52 date: new Date().toISOString().split('T')[0],53 });54 }55 }, [editingTransaction, isOpen]);56 57 if (!isOpen) return null;58 59 const categories = type === 'income' ? INCOME_CATEGORIES : EXPENSE_CATEGORIES;60 61 const handleSubmit = (e) => {62 e.preventDefault();63 const amount = parseFloat(formData.amount);64 if (!amount || isNaN(amount)) return;65 66 onSubmit({67 id: editingTransaction?.id || Date.now(),68 type,69 amount: Math.abs(amount),70 category: formData.category,71 description: formData.description,72 date: formData.date,73 createdAt: editingTransaction?.createdAt || new Date().toISOString(),74 });75 onClose();76 };77 78 return (79 <div className="fixed inset-0 z-50 overflow-y-auto">80 <div className="flex min-h-full items-center justify-center p-4">81 {/* Backdrop */}82 <div83 className="fixed inset-0 bg-neutral-900/50 transition-opacity"84 onClick={onClose}85 />86 87 {/* Modal */}88 <div className="relative bg-white rounded-xl shadow-xl max-w-md w-full animate-fadeIn">89 {/* Header */}90 <div className="flex items-center justify-between p-6 border-b border-neutral-100">91 <h2 className="text-lg font-semibold text-neutral-800">92 {editingTransaction ? 'Edit' : 'Add'} {type === 'income' ? 'Income' : 'Expense'}93 </h2>94 <button95 onClick={onClose}96 className="p-2 text-neutral-400 hover:text-neutral-600 rounded-lg hover:bg-neutral-100 transition-colors"97 >98 <X className="w-5 h-5" />99 </button>100 </div>101 102 {/* Form */}103 <form onSubmit={handleSubmit} className="p-6 space-y-4">104 {/* Amount */}105 <div>106 <label className="label">Amount</label>107 <div className="relative">108 <span className="absolute left-4 top-1/2 -translate-y-1/2 text-neutral-400">109 $110 </span>111 <input112 type="number"113 step="0.01"114 min="0"115 value={formData.amount}116 onChange={(e) => setFormData({ ...formData, amount: e.target.value })}117 className="input-field pl-8"118 placeholder="0.00"119 required120 autoFocus121 />122 </div>123 </div>124 125 {/* Category */}126 <div>127 <label className="label">Category</label>128 <select129 value={formData.category}130 onChange={(e) => setFormData({ ...formData, category: e.target.value })}131 className="input-field"132 required133 >134 <option value="">Select a category</option>135 {categories.map((cat) => (136 <option key={cat} value={cat}>137 {cat}138 </option>139 ))}140 </select>141 </div>142 143 {/* Description */}144 <div>145 <label className="label">Description (optional)</label>146 <input147 type="text"148 value={formData.description}149 onChange={(e) => setFormData({ ...formData, description: e.target.value })}150 className="input-field"151 placeholder="What was this for?"152 />153 </div>154 155 {/* Date */}156 <div>157 <label className="label">Date</label>158 <input159 type="date"160 value={formData.date}161 onChange={(e) => setFormData({ ...formData, date: e.target.value })}162 className="input-field"163 required164 />165 </div>166 167 {/* Actions */}168 <div className="flex gap-3 pt-4">169 <button type="button" onClick={onClose} className="btn-secondary flex-1">170 Cancel171 </button>172 <button type="submit" className={type === 'income' ? 'btn-success flex-1' : 'btn-danger flex-1'}>173 {editingTransaction ? (174 <>175 <Edit2 className="w-4 h-4 inline mr-2" />176 Save Changes177 </>178 ) : (179 <>180 <Plus className="w-4 h-4 inline mr-2" />181 Add {type === 'income' ? 'Income' : 'Expense'}182 </>183 )}184 </button>185 </div>186 </form>187 </div>188 </div>189 </div>190 );191}