import { useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { BookOpen, Plus, MoreVertical, Eye, Edit, Trash2, RefreshCw, Search, FolderTree, CheckCircle, XCircle, } from 'lucide-react'; import { Button } from '@components/atoms/Button'; import { Card, CardHeader, CardTitle, CardContent } from '@components/molecules/Card'; import { DataTable, type Column } from '@components/organisms/DataTable'; import { Dropdown, type DropdownItem } from '@components/organisms/Dropdown'; import { Breadcrumbs } from '@components/organisms/Breadcrumbs'; import { ConfirmModal } from '@components/organisms/Modal'; import { NoDataEmptyState, ErrorEmptyState } from '@components/templates/EmptyState'; import { useAccounts, useAccountTypes } from '@features/financial/hooks'; import type { Account, AccountTypeEnum } from '@features/financial/types'; import { formatNumber } from '@utils/formatters'; const accountTypeLabels: Record = { asset: 'Activo', liability: 'Pasivo', equity: 'Capital', income: 'Ingreso', expense: 'Gasto', }; const accountTypeColors: Record = { asset: 'bg-blue-100 text-blue-700', liability: 'bg-red-100 text-red-700', equity: 'bg-purple-100 text-purple-700', income: 'bg-green-100 text-green-700', expense: 'bg-amber-100 text-amber-700', }; // Helper function to format currency with 2 decimals const formatCurrency = (value: number): string => { return formatNumber(value, 'es-MX', { minimumFractionDigits: 2, maximumFractionDigits: 2 }); }; export function AccountsPage() { const navigate = useNavigate(); const [selectedType, setSelectedType] = useState(''); const [searchTerm, setSearchTerm] = useState(''); const [showDeprecated, setShowDeprecated] = useState(false); const [accountToDelete, setAccountToDelete] = useState(null); const { accountTypes } = useAccountTypes(); const { accounts, total, page, totalPages, isLoading, error, setPage, refresh, deleteAccount, } = useAccounts({ search: searchTerm || undefined, isDeprecated: showDeprecated ? undefined : false, limit: 20, }); // Filter accounts by type if selected const filteredAccounts = selectedType ? accounts.filter(a => { const accountType = accountTypes.find(t => t.id === a.accountTypeId); return accountType?.accountType === selectedType; }) : accounts; const getActionsMenu = (account: Account): DropdownItem[] => { return [ { key: 'view', label: 'Ver detalle', icon: , onClick: () => navigate(`/financial/accounts/${account.id}`), }, { key: 'edit', label: 'Editar', icon: , onClick: () => navigate(`/financial/accounts/${account.id}/edit`), }, { key: 'children', label: 'Ver subcuentas', icon: , onClick: () => navigate(`/financial/accounts?parentId=${account.id}`), }, { key: 'delete', label: 'Eliminar', icon: , danger: true, onClick: () => setAccountToDelete(account), }, ]; }; const columns: Column[] = [ { key: 'code', header: 'Cuenta', render: (account) => (
{account.code}
{account.name}
), }, { key: 'accountType', header: 'Tipo', render: (account) => { const accountType = accountTypes.find(t => t.id === account.accountTypeId); const typeKey = accountType?.accountType as AccountTypeEnum; return ( {accountTypeLabels[typeKey] || accountType?.name || 'Desconocido'} ); }, }, { key: 'parent', header: 'Cuenta Padre', render: (account) => ( {account.parentName || '-'} ), }, { key: 'balance', header: 'Saldo', sortable: true, render: (account) => (
${formatCurrency(account.balance || 0)}
), }, { key: 'reconcilable', header: 'Conciliable', render: (account) => ( account.isReconcilable ? ( ) : ( ) ), }, { key: 'status', header: 'Estado', render: (account) => ( {account.isDeprecated ? 'Obsoleta' : 'Activa'} ), }, { key: 'actions', header: '', render: (account) => ( } items={getActionsMenu(account)} align="right" /> ), }, ]; const handleDelete = async () => { if (accountToDelete) { await deleteAccount(accountToDelete.id); setAccountToDelete(null); } }; // Calculate summary stats const assetAccounts = accounts.filter(a => { const type = accountTypes.find(t => t.id === a.accountTypeId); return type?.accountType === 'asset'; }).length; const liabilityAccounts = accounts.filter(a => { const type = accountTypes.find(t => t.id === a.accountTypeId); return type?.accountType === 'liability'; }).length; const incomeAccounts = accounts.filter(a => { const type = accountTypes.find(t => t.id === a.accountTypeId); return type?.accountType === 'income'; }).length; const expenseAccounts = accounts.filter(a => { const type = accountTypes.find(t => t.id === a.accountTypeId); return type?.accountType === 'expense'; }).length; if (error) { return (
); } return (

Plan de Cuentas

Gestiona el catalogo de cuentas contables

{/* Summary Stats */}
setSelectedType('asset')}>
Activos
{assetAccounts}
setSelectedType('liability')}>
Pasivos
{liabilityAccounts}
setSelectedType('income')}>
Ingresos
{incomeAccounts}
setSelectedType('expense')}>
Gastos
{expenseAccounts}
Lista de Cuentas
{/* Filters */}
setSearchTerm(e.target.value)} className="w-full rounded-md border border-gray-300 py-2 pl-10 pr-4 focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500" />
{(selectedType || searchTerm || showDeprecated) && ( )}
{/* Table */} {filteredAccounts.length === 0 && !isLoading ? ( ) : ( )}
{/* Delete Account Modal */} setAccountToDelete(null)} onConfirm={handleDelete} title="Eliminar cuenta" message={`¿Eliminar la cuenta ${accountToDelete?.code} - ${accountToDelete?.name}? Esta accion no se puede deshacer.`} variant="danger" confirmText="Eliminar" />
); } export default AccountsPage;