'use client'; import { useState, useEffect, useCallback } from 'react'; import { api } from '@/lib/api'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import { FormModal } from '@/components/ui/form-modal'; import { Modal } from '@/components/ui/modal'; import { ActionIcon } from '@/components/ui/action-icon'; import { useToast } from '@/components/ui/toast'; const typeColors: Record = { asset: 'info', liability: 'error', equity: 'purple', revenue: 'success', expense: 'warning', }; export default function ChartOfAccountsPage() { const { toast } = useToast(); const [accounts, setAccounts] = useState([]); const [loading, setLoading] = useState(true); const [showCreate, setShowCreate] = useState(false); const [deleteTarget, setDeleteTarget] = useState(null); const load = useCallback(async () => { try { const r = await api.get('/accounting/chart-of-accounts'); setAccounts(r.data.data); } catch { toast('Failed to load', 'error'); } finally { setLoading(false); } }, [toast]); useEffect(() => { load(); }, [load]); async function handleDelete() { if (!deleteTarget) return; try { await api.delete(`/accounting/chart-of-accounts/${deleteTarget.id}`); toast('Account deleted', 'success'); setDeleteTarget(null); load(); } catch (e: any) { toast(e.response?.data?.error || 'Failed', 'error'); } } // Group by type const grouped: Record = {}; for (const a of accounts) { (grouped[a.type] = grouped[a.type] || []).push(a); } const typeOrder = ['asset', 'liability', 'equity', 'revenue', 'expense']; const typeLabels: Record = { asset: 'Assets', liability: 'Liabilities', equity: 'Equity', revenue: 'Revenue', expense: 'Expenses' }; return (

Manage your chart of accounts for double-entry bookkeeping

{loading ?

Loading...

: (
{typeOrder.map((type) => { const accts = grouped[type]; if (!accts) return null; return (

{accts.map((a: any) => ( ))}
{a.code} {a.name} {a.isSystem ? System : (
e.stopPropagation()}> setDeleteTarget(a)} />
)}
); })}
)} setShowCreate(false)} onSuccess={load} /> setDeleteTarget(null)} title="Delete Account" description={`Delete "${deleteTarget?.code} — ${deleteTarget?.name}"?`} variant="danger" confirmLabel="Delete" onConfirm={handleDelete} />
); } function CreateCoAModal({ open, onClose, onSuccess }: { open: boolean; onClose: () => void; onSuccess: () => void }) { const { toast } = useToast(); const [form, setForm] = useState({ code: '', name: '', type: 'asset' }); const [submitting, setSubmitting] = useState(false); const ic = 'mt-1 block w-full rounded-lg border border-surface-200 dark:border-surface-700 px-3.5 py-2.5 text-sm text-surface-900 dark:text-surface-200 focus:border-primary-500 focus:outline-none focus:ring-2 focus:ring-primary-500/20 transition-all duration-200'; useEffect(() => { if (open) setForm({ code: '', name: '', type: 'asset' }); }, [open]); async function handleSubmit(e: React.FormEvent) { e.preventDefault(); setSubmitting(true); try { await api.post('/accounting/chart-of-accounts', form); toast('Account created', 'success'); onSuccess(); onClose(); } catch (e: any) { toast(e.response?.data?.error || 'Failed', 'error'); } finally { setSubmitting(false); } } return (
setForm({ ...form, code: e.target.value })} className={ic} placeholder="1050" />
setForm({ ...form, name: e.target.value })} className={ic} placeholder="Account name" />
); }