Files
acmcc/src/components/CollectionDialog.jsx
T
2026-06-01 20:19:26 -04:00

231 lines
8.6 KiB
React

import React, { useState, useEffect } from 'react';
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
import { Label } from '@/components/ui/label';
import { supabase } from '@/integrations/supabase/client';
import { useToast } from '@/hooks/use-toast';
const STATUS_OPTIONS = [
"open",
"in_progress",
"resolved",
"closed"
];
const normalizeCollectionStatus = (status) => status === 'resolved' ? 'closed' : status;
function CollectionDialog({ open, onOpenChange, collection, onSuccess }) {
const { toast } = useToast();
const db = supabase;
const [associations, setAssociations] = useState([]);
const [owners, setOwners] = useState([]);
const [units, setUnits] = useState([]);
const [formData, setFormData] = useState({
association_id: '',
owner_id: '',
unit_id: '',
notes: '',
status: 'open',
last_notice_date: '',
amount_owed: ''
});
const [loading, setLoading] = useState(false);
useEffect(() => {
const fetchAssociations = async () => {
const { data, error } = await db.from('associations').select('id, name').eq('status', 'active').order('name');
if (!error) setAssociations(data || []);
};
if (open) fetchAssociations();
}, [open]);
useEffect(() => {
if (formData.association_id) {
const fetchOwnersAndUnits = async () => {
const [ownersRes, unitsRes] = await Promise.all([
db.from('owners').select('id, first_name, last_name').eq('association_id', formData.association_id).eq('status', 'active').order('last_name'),
db.from('units').select('id, unit_number, address').eq('association_id', formData.association_id).order('unit_number'),
]);
if (!ownersRes.error) setOwners(ownersRes.data || []);
if (!unitsRes.error) setUnits(unitsRes.data || []);
};
fetchOwnersAndUnits();
} else {
setOwners([]);
setUnits([]);
}
}, [formData.association_id]);
useEffect(() => {
if (collection) {
setFormData({
association_id: collection.association_id || '',
owner_id: collection.owner_id || '',
unit_id: collection.unit_id || '',
notes: collection.notes || '',
status: collection.status || 'open',
last_notice_date: collection.last_notice_date || '',
amount_owed: collection.amount_owed || ''
});
} else {
setFormData({
association_id: '', owner_id: '', unit_id: '', notes: '', status: 'open', last_notice_date: '', amount_owed: ''
});
}
}, [collection, open]);
const handleSubmit = async (e) => {
e.preventDefault();
setLoading(true);
if (!formData.association_id) {
toast({ variant: 'destructive', title: 'Missing Field', description: 'Please select an association.' });
setLoading(false);
return;
}
const dataToSubmit = {
...formData,
status: normalizeCollectionStatus(formData.status),
last_notice_date: formData.last_notice_date || null,
amount_owed: formData.amount_owed || 0,
owner_id: formData.owner_id || null,
unit_id: formData.unit_id || null,
};
const { error } = collection
? await db.from('collections').update(dataToSubmit).eq('id', collection.id)
: await db.from('collections').insert([dataToSubmit]);
if (!error) {
toast({
title: collection ? 'Collection Updated' : 'Collection Created',
description: `Collection has been successfully ${collection ? 'updated' : 'created'}.`,
});
onSuccess();
onOpenChange(false);
} else {
toast({ variant: 'destructive', title: 'Error', description: error.message });
}
setLoading(false);
};
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="sm:max-w-[500px]">
<DialogHeader>
<DialogTitle>{collection ? 'Edit Collection' : 'Add New Collection'}</DialogTitle>
</DialogHeader>
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<Label htmlFor="association_id">Association *</Label>
<select
id="association_id"
value={formData.association_id}
onChange={(e) => setFormData({ ...formData, association_id: e.target.value, owner_id: '' })}
required
className="w-full mt-1 px-3 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-teal-500 focus:border-transparent"
>
<option value="">Select an association...</option>
{associations.map((a) => (
<option key={a.id} value={a.id}>{a.name}</option>
))}
</select>
</div>
<div>
<Label htmlFor="unit_id">Unit</Label>
<select
id="unit_id"
value={formData.unit_id}
onChange={(e) => setFormData({ ...formData, unit_id: e.target.value })}
className="w-full mt-1 px-3 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-teal-500 focus:border-transparent"
disabled={!formData.association_id}
>
<option value="">Select a unit...</option>
{units.map((u) => (
<option key={u.id} value={u.id}>{u.unit_number}{u.address ? ` - ${u.address}` : ''}</option>
))}
</select>
</div>
<div>
<Label htmlFor="owner_id">Owner</Label>
<select
id="owner_id"
value={formData.owner_id}
onChange={(e) => setFormData({ ...formData, owner_id: e.target.value })}
className="w-full mt-1 px-3 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-teal-500 focus:border-transparent"
disabled={!formData.association_id}
>
<option value="">Select an owner...</option>
{owners.map((o) => (
<option key={o.id} value={o.id}>{o.first_name} {o.last_name}</option>
))}
</select>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<Label htmlFor="status">Status *</Label>
<select
id="status"
value={formData.status}
onChange={(e) => setFormData({ ...formData, status: e.target.value })}
required
className="w-full mt-1 px-3 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-teal-500 focus:border-transparent"
>
{STATUS_OPTIONS.map((status) => (
<option key={status} value={status}>{status}</option>
))}
</select>
</div>
<div>
<Label htmlFor="last_notice_date">Last Notice Date</Label>
<input
id="last_notice_date"
type="date"
value={formData.last_notice_date}
onChange={(e) => setFormData({ ...formData, last_notice_date: e.target.value })}
className="w-full mt-1 px-3 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-teal-500 focus:border-transparent"
/>
</div>
</div>
<div>
<Label htmlFor="amount_owed">Amount Owed ($)</Label>
<input
id="amount_owed"
type="number"
step="0.01"
min="0"
placeholder="0.00"
value={formData.amount_owed}
onChange={(e) => setFormData({ ...formData, amount_owed: e.target.value })}
className="w-full mt-1 px-3 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-teal-500 focus:border-transparent"
/>
</div>
<div>
<Label htmlFor="notes">Notes</Label>
<textarea
id="notes"
value={formData.notes}
onChange={(e) => setFormData({ ...formData, notes: e.target.value })}
rows={3}
className="w-full mt-1 px-3 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-teal-500 focus:border-transparent"
/>
</div>
<div className="flex justify-end space-x-2 pt-4">
<Button type="button" variant="outline" onClick={() => onOpenChange(false)}>Cancel</Button>
<Button type="submit" disabled={loading}>
{loading ? 'Saving...' : collection ? 'Update' : 'Create'}
</Button>
</div>
</form>
</DialogContent>
</Dialog>
);
}
export default CollectionDialog;