"use client"; import { useState } from "react"; import { useQuery, useMutation } from "@tanstack/react-query"; import { toast } from "sonner"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/Card"; import { Button } from "@/components/ui/Button"; import { Input } from "@/components/ui/Input"; import { Table, TableHead, TableBody, TableRow, Th, Td, EmptyState } from "@/components/ui/Table"; import { Badge } from "@/components/ui/Badge"; import { Modal } from "@/components/ui/Modal"; import { AccountingNav } from "@/components/accounting/AccountingNav"; import api from "@/lib/api"; import type { Account, AccountType } from "@/types/index"; const ACCOUNT_TYPES: AccountType[] = ["ASSET", "LIABILITY", "EQUITY", "REVENUE", "EXPENSE"]; const TYPE_TABS: { key: AccountType | "ALL"; label: string }[] = [ { key: "ALL", label: "All" }, { key: "ASSET", label: "Assets" }, { key: "LIABILITY", label: "Liabilities" }, { key: "EQUITY", label: "Equity" }, { key: "REVENUE", label: "Revenue" }, { key: "EXPENSE", label: "Expenses" }, ]; const TYPE_COLORS: Record = { ASSET: "success", LIABILITY: "danger", EQUITY: "warning", REVENUE: "default", EXPENSE: "muted", }; export default function ChartOfAccountsPage() { const [activeType, setActiveType] = useState("ALL"); const [showAdd, setShowAdd] = useState(false); const [form, setForm] = useState({ code: "", name: "", type: "ASSET" as AccountType }); const { data, isLoading, refetch } = useQuery({ queryKey: ["accounts"], queryFn: async () => { const res = await api.get("/api/v1/accounts"); const d = res.data; return Array.isArray(d) ? d : (d as { data: Account[] }).data ?? []; }, }); const accounts = data ?? []; const hasAccounts = accounts.length > 0; const filtered = activeType === "ALL" ? accounts : accounts.filter((a) => a.type === activeType); const addMutation = useMutation({ mutationFn: async () => { await api.post("/api/v1/accounts", form); }, onSuccess: () => { toast.success("Account created"); setShowAdd(false); setForm({ code: "", name: "", type: "ASSET" }); refetch(); }, onError: () => toast.error("Failed to create account"), }); const seedMutation = useMutation({ mutationFn: async () => { await api.post("/api/v1/accounts/seed", {}); }, onSuccess: () => { toast.success("Default accounts seeded"); refetch(); }, onError: () => toast.error("Failed to seed accounts"), }); const toggleMutation = useMutation({ mutationFn: async ({ id, isActive }: { id: string; isActive: boolean }) => { await api.patch(`/api/v1/accounts/${id}`, { isActive: !isActive }); }, onSuccess: () => { toast.success("Account updated"); refetch(); }, onError: () => toast.error("Failed to update account"), }); return (

Accounting

Chart of accounts, journals, and financial reports

{!hasAccounts && ( )}
{/* Type filter tabs */}
{TYPE_TABS.map(({ key, label }) => ( ))}
{activeType === "ALL" ? "All Accounts" : activeType} ({filtered.length}) {isLoading ? ( Array.from({ length: 4 }).map((_, i) => ( {[1,2,3,4,5].map((j) => ( ))} )) ) : filtered.length === 0 ? ( ) : ( filtered.map((a) => ( )) )}
Code Name Type Status Actions
{a.code} {a.name} {a.type} {a.isActive ? "Active" : "Inactive"}
setShowAdd(false)} title="Add Account">
{ e.preventDefault(); addMutation.mutate(); }} className="space-y-4" > setForm((f) => ({ ...f, code: e.target.value }))} placeholder="e.g. 1001" /> setForm((f) => ({ ...f, name: e.target.value }))} placeholder="e.g. Cash on Hand" />
); }