'use client'; import { useState, useEffect } from 'react'; import { formatCurrency } from '@/lib/utils'; import Link from 'next/link'; import { useRouter } from 'next/navigation'; import { ArrowLeft, Loader2, TrendingUp, TrendingDown, AlertCircle, Edit2, Download, Plus, Trash2, } from 'lucide-react'; interface Account { id: string; accountCode: string; accountName: string; accountType: string; isActive: boolean; level: number; description: string; parentAccount: string | null; } interface Transaction { id: string; journalEntryId: string; entryNumber: string; entryDate: string; status: string; description: string; entityName: string; sourceModule?: string; debitAmount: number; creditAmount: number; } interface SubAccount { id: string; accountCode: string; accountName: string; accountType: string; balance: number; } interface MonthlyData { month: string; debits: number; credits: number; balance: number; } interface AccountDetailData { account: Account; balance: number; totalDebits: number; totalCredits: number; transactions: Transaction[]; subAccounts: SubAccount[]; monthlyData: MonthlyData[]; } export default function AccountDetailPage({ params, }: { params: { accountId: string }; }) { const router = useRouter(); const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [activeTab, setActiveTab] = useState<'transactions' | 'sub-accounts' | 'analysis' | 'audit'>('transactions'); const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('desc'); // Edit Account State const [isEditing, setIsEditing] = useState(false); const [editForm, setEditForm] = useState({ name: '', description: '', status: '' }); const [isSaving, setIsSaving] = useState(false); // Delete Account State const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); const [isDeleting, setIsDeleting] = useState(false); useEffect(() => { const fetchAccountData = async () => { try { setLoading(true); setError(null); const response = await fetch(`/api/accounts/${params.accountId}`); if (!response.ok) { throw new Error('Failed to fetch account data'); } const result = await response.json(); // Transform API response to match expected shape const transformed: AccountDetailData = { account: { id: result.id, accountCode: result.accountCode, accountName: result.accountName, accountType: result.accountType, isActive: result.status === 'ACTIVE', level: result.level || 1, description: result.description || '', parentAccount: result.parentAccount?.accountName || null, }, balance: result.balance ?? 0, totalDebits: result.totalDebits ?? 0, totalCredits: result.totalCredits ?? 0, transactions: (result.transactions || []).map((t: any) => ({ id: t.id, journalEntryId: t.journalEntryId || t.journalEntry?.id, entryNumber: t.journalEntry?.entryNumber || t.entryNumber || '', entryDate: t.journalEntry?.entryDate || t.entryDate || '', status: t.journalEntry?.status || t.status || '', description: t.description || t.journalEntry?.description || '', entityName: t.entity?.name || t.entityName || '', debitAmount: t.debitAmount ?? 0, creditAmount: t.creditAmount ?? 0, })), subAccounts: (result.subAccounts || []).map((s: any) => ({ id: s.id, accountCode: s.accountCode, accountName: s.accountName, accountType: s.accountType, balance: s.balance ?? 0, })), monthlyData: result.monthlyData ? (typeof result.monthlyData === 'object' && !Array.isArray(result.monthlyData) ? Object.entries(result.monthlyData) .map(([month, data]: [string, any]) => ({ month, debits: data.debits ?? 0, credits: data.credits ?? 0, balance: data.balance ?? 0, })) .sort((a, b) => a.month.localeCompare(b.month)) : result.monthlyData) : [], }; setData(transformed); } catch (err) { setError(err instanceof Error ? err.message : 'An error occurred'); } finally { setLoading(false); } }; fetchAccountData(); }, [params.accountId]); const handleEditClick = () => { if (data) { setEditForm({ name: data.account.accountName, description: data.account.description, status: data.account.isActive ? 'ACTIVE' : 'INACTIVE', }); setIsEditing(true); } }; const handleEditCancel = () => { setIsEditing(false); setEditForm({ name: '', description: '', status: '' }); }; const handleSave = async () => { if (!data) return; try { setIsSaving(true); const res = await fetch(`/api/accounts`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'update', id: data.account.id, accountName: editForm.name, description: editForm.description, status: editForm.status, }), }); if (res.ok) { // Refetch account data const response = await fetch(`/api/accounts/${params.accountId}`); if (response.ok) { const result = await response.json(); const transformed: AccountDetailData = { account: { id: result.id, accountCode: result.accountCode, accountName: result.accountName, accountType: result.accountType, isActive: result.status === 'ACTIVE', level: result.level || 1, description: result.description || '', parentAccount: result.parentAccount?.accountName || null, }, balance: result.balance ?? 0, totalDebits: result.totalDebits ?? 0, totalCredits: result.totalCredits ?? 0, transactions: (result.transactions || []).map((t: any) => ({ id: t.id, journalEntryId: t.journalEntryId || t.journalEntry?.id, entryNumber: t.journalEntry?.entryNumber || t.entryNumber || '', entryDate: t.journalEntry?.entryDate || t.entryDate || '', status: t.journalEntry?.status || t.status || '', description: t.description || t.journalEntry?.description || '', entityName: t.entity?.name || t.entityName || '', debitAmount: t.debitAmount ?? 0, creditAmount: t.creditAmount ?? 0, })), subAccounts: (result.subAccounts || []).map((s: any) => ({ id: s.id, accountCode: s.accountCode, accountName: s.accountName, accountType: s.accountType, balance: s.balance ?? 0, })), monthlyData: result.monthlyData ? (typeof result.monthlyData === 'object' && !Array.isArray(result.monthlyData) ? Object.entries(result.monthlyData) .map(([month, monthData]: [string, any]) => ({ month, debits: monthData.debits ?? 0, credits: monthData.credits ?? 0, balance: monthData.balance ?? 0, })) .sort((a, b) => a.month.localeCompare(b.month)) : result.monthlyData) : [], }; setData(transformed); } setIsEditing(false); setEditForm({ name: '', description: '', status: '' }); } } catch (err) { console.error('Error saving account:', err); } finally { setIsSaving(false); } }; const handleStatusToggle = async () => { if (!data) return; try { setIsSaving(true); const newStatus = data.account.isActive ? 'INACTIVE' : 'ACTIVE'; const res = await fetch(`/api/accounts`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'update', id: data.account.id, status: newStatus, }), }); if (res.ok) { setData({ ...data, account: { ...data.account, isActive: newStatus === 'ACTIVE' }, }); } } catch (err) { console.error('Error toggling status:', err); } finally { setIsSaving(false); } }; const handleExport = () => { if (!data) return; const headers = ['Date', 'Entry #', 'Description', 'Entity', 'Source', 'Debit', 'Credit']; const rows = data.transactions.map((tx) => [ new Date(tx.entryDate).toLocaleDateString('en-US'), tx.entryNumber, tx.description, tx.entityName, tx.sourceModule || 'Manual', tx.debitAmount > 0 ? tx.debitAmount.toFixed(2) : '', tx.creditAmount > 0 ? tx.creditAmount.toFixed(2) : '', ]); const csv = [ headers.join(','), ...rows.map((row) => row.map((cell) => `"${cell}"`).join(',')), ].join('\n'); const blob = new Blob([csv], { type: 'text/csv' }); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `${data.account.accountCode}-transactions.csv`; document.body.appendChild(a); a.click(); document.body.removeChild(a); window.URL.revokeObjectURL(url); }; const handleDelete = async () => { if (!data) return; try { setIsDeleting(true); const res = await fetch(`/api/accounts`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'delete', id: data.account.id, }), }); if (res.ok) { router.push('/finance/general-ledger'); } } catch (err) { console.error('Error deleting account:', err); } finally { setIsDeleting(false); setShowDeleteConfirm(false); } }; if (loading) { return (

Loading account details...

); } if (error || !data) { return (
Back to General Ledger

Error Loading Account

{error || 'Account not found'}

); } const { account, balance, totalDebits, totalCredits, transactions, subAccounts, monthlyData } = data; const sortedTransactions = [...transactions].sort((a, b) => { const dateA = new Date(a.entryDate).getTime(); const dateB = new Date(b.entryDate).getTime(); return sortOrder === 'desc' ? dateB - dateA : dateA - dateB; }); const getAccountTypeBadge = (type: string) => { const colors: Record = { ASSET: { bg: 'bg-blue-900/25', text: 'text-blue-700' }, LIABILITY: { bg: 'bg-red-900/25', text: 'text-red-700' }, EQUITY: { bg: 'bg-purple-900/25', text: 'text-purple-700' }, REVENUE: { bg: 'bg-green-900/25', text: 'text-green-700' }, EXPENSE: { bg: 'bg-orange-900/25', text: 'text-orange-700' }, }; const color = colors[type] || { bg: 'bg-[#1A1A1F]', text: 'text-[#8B8B9E]' }; return ( {type} ); }; const getMaxMonthlyValue = () => { return Math.max(...monthlyData.map(m => Math.max(m.debits, m.credits, Math.abs(m.balance))), 1); }; const maxValue = getMaxMonthlyValue(); return (
{/* Header */}

{account.accountCode}

{getAccountTypeBadge(account.accountType)}

{account.accountName}

{!isEditing && (
New Entry
)}

Status

{account.isActive ? ( Active ) : ( Inactive )}

{!isEditing && ( )}
{/* Edit Mode Header */} {isEditing && (
setEditForm({ ...editForm, name: e.target.value })} className="w-full px-3 py-2 border border-[#3A3A45] rounded-lg focus:ring-2 focus:ring-blue-600 focus:border-transparent" />