import React, { useState, useEffect, useCallback } from 'react'; import { toast } from 'sonner'; import { ChevronDown, Trash2, ToggleLeft, ToggleRight, Settings2 } from 'lucide-react'; import { api } from '@/api'; import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; export default function BillRulesManager() { const [open, setOpen] = useState(false); const [rules, setRules] = useState([]); const [loading, setLoading] = useState(false); const load = useCallback(async () => { setLoading(true); try { const d = await api.allBillMerchantRules(); setRules(d.rules || []); } catch (err) { toast.error(err.message || 'Failed to load bill matching rules'); } finally { setLoading(false); } }, []); useEffect(() => { if (open) load(); }, [open, load]); const handleDelete = async (billId, ruleId, merchant) => { try { await api.deleteMerchantRule(billId, ruleId); setRules(prev => prev.filter(r => r.id !== ruleId)); toast.success(`Rule "${merchant}" removed`); } catch (err) { toast.error(err.message || 'Failed to delete rule'); } }; const handleToggleAutoLate = async (billId, ruleId, current) => { try { await api.toggleRuleAutoAttribute(billId, ruleId, !current); setRules(prev => prev.map(r => r.id === ruleId ? { ...r, auto_attribute_late: current ? 0 : 1 } : r )); } catch (err) { toast.error(err.message || 'Failed to update rule'); } }; // Group rules by bill const byBill = rules.reduce((acc, r) => { const key = r.bill_id; if (!acc[key]) acc[key] = { bill_name: r.bill_name, bill_id: r.bill_id, rules: [] }; acc[key].rules.push(r); return acc; }, {}); const groups = Object.values(byBill); return (
Loading…
) : groups.length === 0 ? (No rules saved yet. Open a bill and add merchant matching rules to auto-match bank transactions.
) : ({group.bill_name}
Merchant patterns are matched with word-boundary rules. Toggle icon = auto-apply late month attribution.