anycoder-380d34cb / components /TransactionModal.js
spdniloy's picture
Upload components/TransactionModal.js with huggingface_hub
d5b3857 verified
Raw
History Blame Contribute Delete
5.74 kB
import { useState, useEffect } from 'react';
import { X, Plus, Edit2 } from 'lucide-react';
const INCOME_CATEGORIES = [
'Sales',
'Services',
'Consulting',
'Subscriptions',
'Refunds',
'Other Income',
];
const EXPENSE_CATEGORIES = [
'Supplies',
'Equipment',
'Marketing',
'Utilities',
'Software',
'Travel',
'Professional Services',
'Taxes',
'Other',
];
export default function TransactionModal({
isOpen,
onClose,
onSubmit,
type = 'income',
editingTransaction = null,
}) {
const [formData, setFormData] = useState({
amount: '',
category: '',
description: '',
date: new Date().toISOString().split('T')[0],
});
useEffect(() => {
if (editingTransaction) {
setFormData({
amount: editingTransaction.amount.toString(),
category: editingTransaction.category,
description: editingTransaction.description || '',
date: editingTransaction.date,
});
} else {
setFormData({
amount: '',
category: '',
description: '',
date: new Date().toISOString().split('T')[0],
});
}
}, [editingTransaction, isOpen]);
if (!isOpen) return null;
const categories = type === 'income' ? INCOME_CATEGORIES : EXPENSE_CATEGORIES;
const handleSubmit = (e) => {
e.preventDefault();
const amount = parseFloat(formData.amount);
if (!amount || isNaN(amount)) return;
onSubmit({
id: editingTransaction?.id || Date.now(),
type,
amount: Math.abs(amount),
category: formData.category,
description: formData.description,
date: formData.date,
createdAt: editingTransaction?.createdAt || new Date().toISOString(),
});
onClose();
};
return (
<div className="fixed inset-0 z-50 overflow-y-auto">
<div className="flex min-h-full items-center justify-center p-4">
{/* Backdrop */}
<div
className="fixed inset-0 bg-neutral-900/50 transition-opacity"
onClick={onClose}
/>
{/* Modal */}
<div className="relative bg-white rounded-xl shadow-xl max-w-md w-full animate-fadeIn">
{/* Header */}
<div className="flex items-center justify-between p-6 border-b border-neutral-100">
<h2 className="text-lg font-semibold text-neutral-800">
{editingTransaction ? 'Edit' : 'Add'} {type === 'income' ? 'Income' : 'Expense'}
</h2>
<button
onClick={onClose}
className="p-2 text-neutral-400 hover:text-neutral-600 rounded-lg hover:bg-neutral-100 transition-colors"
>
<X className="w-5 h-5" />
</button>
</div>
{/* Form */}
<form onSubmit={handleSubmit} className="p-6 space-y-4">
{/* Amount */}
<div>
<label className="label">Amount</label>
<div className="relative">
<span className="absolute left-4 top-1/2 -translate-y-1/2 text-neutral-400">
$
</span>
<input
type="number"
step="0.01"
min="0"
value={formData.amount}
onChange={(e) => setFormData({ ...formData, amount: e.target.value })}
className="input-field pl-8"
placeholder="0.00"
required
autoFocus
/>
</div>
</div>
{/* Category */}
<div>
<label className="label">Category</label>
<select
value={formData.category}
onChange={(e) => setFormData({ ...formData, category: e.target.value })}
className="input-field"
required
>
<option value="">Select a category</option>
{categories.map((cat) => (
<option key={cat} value={cat}>
{cat}
</option>
))}
</select>
</div>
{/* Description */}
<div>
<label className="label">Description (optional)</label>
<input
type="text"
value={formData.description}
onChange={(e) => setFormData({ ...formData, description: e.target.value })}
className="input-field"
placeholder="What was this for?"
/>
</div>
{/* Date */}
<div>
<label className="label">Date</label>
<input
type="date"
value={formData.date}
onChange={(e) => setFormData({ ...formData, date: e.target.value })}
className="input-field"
required
/>
</div>
{/* Actions */}
<div className="flex gap-3 pt-4">
<button type="button" onClick={onClose} className="btn-secondary flex-1">
Cancel
</button>
<button type="submit" className={type === 'income' ? 'btn-success flex-1' : 'btn-danger flex-1'}>
{editingTransaction ? (
<>
<Edit2 className="w-4 h-4 inline mr-2" />
Save Changes
</>
) : (
<>
<Plus className="w-4 h-4 inline mr-2" />
Add {type === 'income' ? 'Income' : 'Expense'}
</>
)}
</button>
</div>
</form>
</div>
</div>
</div>
);
}