erp-core-frontend-v2/src/pages/companies/CompaniesListPage.tsx

227 lines
6.3 KiB
TypeScript

import { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import {
Plus,
MoreVertical,
Eye,
Edit,
Trash2,
Building2,
} 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 { ConfirmModal } from '@components/organisms/Modal';
import { Breadcrumbs } from '@components/organisms/Breadcrumbs';
import { NoDataEmptyState, ErrorEmptyState } from '@components/templates/EmptyState';
import { useCompanies } from '@features/companies/hooks';
import { CompanyFiltersPanel } from '@features/companies/components/CompanyFiltersPanel';
import type { Company } from '@features/companies/types';
import { formatDate } from '@utils/formatters';
export function CompaniesListPage() {
const navigate = useNavigate();
const [companyToDelete, setCompanyToDelete] = useState<Company | null>(null);
const {
companies,
total,
page,
totalPages,
isLoading,
error,
filters,
setFilters,
deleteCompany,
refresh,
} = useCompanies({ page: 1, limit: 10 });
const getActionsMenu = (company: Company): DropdownItem[] => {
return [
{
key: 'view',
label: 'Ver detalle',
icon: <Eye className="h-4 w-4" />,
onClick: () => navigate(`/companies/${company.id}`),
},
{
key: 'edit',
label: 'Editar',
icon: <Edit className="h-4 w-4" />,
onClick: () => navigate(`/companies/${company.id}/edit`),
},
{
key: 'delete',
label: 'Eliminar',
icon: <Trash2 className="h-4 w-4" />,
danger: true,
onClick: () => setCompanyToDelete(company),
},
];
};
const columns: Column<Company>[] = [
{
key: 'company',
header: 'Empresa',
render: (company) => (
<div className="flex items-center gap-3">
<div className="flex h-10 w-10 items-center justify-center rounded-lg bg-primary-100">
<Building2 className="h-5 w-5 text-primary-600" />
</div>
<div>
<div className="font-medium text-gray-900">{company.name}</div>
<div className="text-sm text-gray-500">{company.taxId || '-'}</div>
</div>
</div>
),
},
{
key: 'legalName',
header: 'Razón social',
render: (company) => (
<span className="text-sm text-gray-600">{company.legalName || '-'}</span>
),
},
{
key: 'parent',
header: 'Empresa matriz',
render: (company) => (
<span className="text-sm text-gray-600">
{company.parentCompanyName || '-'}
</span>
),
},
{
key: 'currency',
header: 'Moneda',
render: (company) => (
<span className="inline-flex rounded-full bg-gray-100 px-2 py-1 text-xs font-medium text-gray-700">
{company.currencyCode || 'MXN'}
</span>
),
},
{
key: 'createdAt',
header: 'Creado',
sortable: true,
render: (company) => (
<span className="text-sm text-gray-500">
{formatDate(company.createdAt, 'short')}
</span>
),
},
{
key: 'actions',
header: '',
render: (company) => (
<Dropdown
trigger={
<button className="rounded p-1 hover:bg-gray-100">
<MoreVertical className="h-4 w-4 text-gray-500" />
</button>
}
items={getActionsMenu(company)}
align="right"
/>
),
},
];
const handlePageChange = (newPage: number) => {
setFilters({ ...filters, page: newPage });
};
const handleSort = (key: string) => {
const newOrder = filters.sortBy === key && filters.sortOrder === 'asc' ? 'desc' : 'asc';
setFilters({ ...filters, sortBy: key, sortOrder: newOrder });
};
const handleDeleteConfirm = async () => {
if (companyToDelete) {
await deleteCompany(companyToDelete.id);
setCompanyToDelete(null);
}
};
if (error) {
return (
<div className="p-6">
<ErrorEmptyState onRetry={refresh} />
</div>
);
}
return (
<div className="space-y-6 p-6">
<Breadcrumbs items={[{ label: 'Empresas' }]} />
<div className="flex items-center justify-between">
<div>
<h1 className="text-2xl font-bold text-gray-900">Empresas</h1>
<p className="text-sm text-gray-500">
Gestiona las empresas del sistema
</p>
</div>
<Button onClick={() => navigate('/companies/new')}>
<Plus className="mr-2 h-4 w-4" />
Nueva empresa
</Button>
</div>
<Card>
<CardHeader>
<CardTitle>Lista de empresas</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-4">
<CompanyFiltersPanel
filters={filters}
onFiltersChange={setFilters}
/>
{companies.length === 0 && !isLoading ? (
<NoDataEmptyState
entityName="empresas"
onCreateNew={() => navigate('/companies/new')}
/>
) : (
<DataTable
data={companies}
columns={columns}
isLoading={isLoading}
pagination={{
page,
totalPages,
total,
limit: filters.limit || 10,
onPageChange: handlePageChange,
}}
sorting={{
sortBy: filters.sortBy || null,
sortOrder: (filters.sortOrder as 'asc' | 'desc') || 'asc',
onSort: handleSort,
}}
/>
)}
</div>
</CardContent>
</Card>
{/* Delete confirmation modal */}
<ConfirmModal
isOpen={!!companyToDelete}
onClose={() => setCompanyToDelete(null)}
onConfirm={handleDeleteConfirm}
title="Eliminar empresa"
message={`¿Estás seguro de que deseas eliminar "${companyToDelete?.name}"? Esta acción no se puede deshacer.`}
variant="danger"
confirmText="Eliminar"
/>
</div>
);
}
export default CompaniesListPage;