Files
tracksteel_app/src/components/pecas/PecasTable.tsx
T

248 lines
7.9 KiB
TypeScript

import React from 'react';
import { Table, TableBody, TableHeader } from '@/components/ui/table';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Package, FileText, AlertTriangle } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Peca } from '@/hooks/usePecas';
import { usePecasTable } from '@/hooks/usePecasTable';
import { TableFilters } from './table/TableFilters';
import { TableActions } from './table/TableActions';
import { TableHeaderSortable } from './table/TableHeaderSortable';
import { PDFGenerator } from './table/PDFGenerator';
import { BatchEditButton } from './table/BatchEditButton';
import { TableRow as PecaTableRow } from './table/TableRow';
import { EmptyState } from './table/EmptyState';
import { toast } from 'sonner';
interface PecasTableProps {
pecas: Peca[];
onOpenComponentPopup: (pecaId: string) => void;
onDeletePeca?: (pecaId: string) => void;
onDeletePecasBatch?: (pecaIds: string[]) => Promise<any>;
onEditPeca?: (peca: Peca) => void;
onDeleteLastImport?: () => void;
onBatchUpdatePecas?: (pecaIds: string[], updates: any) => Promise<void>;
onOpenRevisaoPeca?: (peca: Peca) => void;
onOpenPainelRevisoes?: () => void;
totalRevisoesOF?: number;
hasRecentImport: boolean;
canEdit?: boolean;
canDelete?: boolean;
ofNumber?: string;
}
export function PecasTable({
pecas,
onOpenComponentPopup,
onDeletePeca,
onDeletePecasBatch,
onEditPeca,
onDeleteLastImport,
onBatchUpdatePecas,
onOpenRevisaoPeca,
onOpenPainelRevisoes,
totalRevisoesOF,
hasRecentImport,
canEdit = true,
canDelete = true,
ofNumber = ''
}: PecasTableProps) {
const {
ofFilter,
setOfFilter,
faseFilter,
setFaseFilter,
pecaFilter,
setPecaFilter,
descricaoFilter,
setDescricaoFilter,
priorityFilter,
setPriorityFilter,
semComponentesFilter,
setSemComponentesFilter,
sortField,
sortOrder,
handleSort,
filteredAndSortedPecas,
selectedPecas,
selectAll,
handleSelectAll,
handleSelectPeca,
searchPecasByComponent,
pesoTotal
} = usePecasTable(pecas);
const handleExportCSV = () => {
const selectedPecasArray = Array.from(selectedPecas);
const pecasToExport = pecas.filter(peca => selectedPecasArray.includes(peca.id));
if (pecasToExport.length === 0) {
toast.error('Nenhuma peça selecionada para exportar.');
return;
}
const csvContent = "data:text/csv;charset=utf-8," +
[
Object.keys(pecasToExport[0]).join(','),
...pecasToExport.map(peca => Object.values(peca).join(','))
].join('\n');
const encodedUri = encodeURI(csvContent);
const link = document.createElement("a");
link.setAttribute("href", encodedUri);
link.setAttribute("download", "pecas.csv");
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
};
const handleDeleteSelected = async () => {
if (!canDelete || (!onDeletePecasBatch && !onDeletePeca)) {
toast.error('Você não tem permissão para excluir peças');
return;
}
if (window.confirm(`Tem certeza que deseja excluir ${selectedPecas.size} peças selecionadas e seus vínculos?`)) {
try {
const pecaIdsArray = Array.from(selectedPecas);
if (onDeletePecasBatch) {
await onDeletePecasBatch(pecaIdsArray);
} else if (onDeletePeca) {
for (const pecaId of pecaIdsArray) {
await onDeletePeca(pecaId);
}
toast.success('Peças excluídas com sucesso!');
}
} catch (error) {
console.error('Erro ao excluir peças:', error);
}
}
};
const handleBatchUpdate = async (updates: any) => {
if (!canEdit || !onBatchUpdatePecas) {
toast.error('Você não tem permissão para editar peças');
throw new Error('Sem permissão');
}
const selectedPecasArray = Array.from(selectedPecas);
await onBatchUpdatePecas(selectedPecasArray, updates);
};
const handleEditPeca = (peca: Peca) => {
if (!onEditPeca) {
return;
}
onEditPeca(peca);
};
const handleDeletePeca = (pecaId: string) => {
if (!canDelete || !onDeletePeca) {
toast.error('Você não tem permissão para excluir peças');
return;
}
onDeletePeca(pecaId);
};
const hasActiveFilters = Boolean(ofFilter || faseFilter || pecaFilter || descricaoFilter || priorityFilter !== 'all' || semComponentesFilter !== 'all');
return (
<div className="space-y-4">
<TableFilters
ofFilter={ofFilter}
onOfFilterChange={setOfFilter}
faseFilter={faseFilter}
onFaseFilterChange={setFaseFilter}
pecaFilter={pecaFilter}
onPecaFilterChange={setPecaFilter}
descricaoFilter={descricaoFilter}
onDescricaoFilterChange={setDescricaoFilter}
priorityFilter={priorityFilter}
onPriorityFilterChange={setPriorityFilter}
semComponentesFilter={semComponentesFilter}
onSemComponentesFilterChange={setSemComponentesFilter}
onSearchComponent={searchPecasByComponent}
pesoTotal={pesoTotal}
/>
<div className="flex justify-between items-center">
<TableActions
selectedPecas={selectedPecas}
onExportCSV={handleExportCSV}
onDeleteSelected={handleDeleteSelected}
hasRecentImport={hasRecentImport}
onDeleteLastImport={onDeleteLastImport || (() => {})}
/>
<div className="flex items-center gap-2">
{onOpenPainelRevisoes && (
<Button
type="button"
variant="outline"
size="sm"
onClick={onOpenPainelRevisoes}
className="h-8 border-red-500/60 bg-red-950/20 text-red-400 hover:bg-red-900/40 hover:text-red-200 font-bold flex items-center gap-1.5 transition-all shadow-sm"
title="Abrir Registro e Gestão de Revisões da OF"
>
<FileText className="h-3.5 w-3.5 text-red-400" />
<span>REG.REVISOES</span>
{totalRevisoesOF !== undefined && totalRevisoesOF > 0 && (
<span className="ml-1 px-1.5 py-0.2 rounded-full text-[10px] bg-red-500 text-white font-black">
{totalRevisoesOF}
</span>
)}
</Button>
)}
{canEdit && onBatchUpdatePecas && (
<BatchEditButton
selectedPecas={selectedPecas}
onBatchUpdate={handleBatchUpdate}
disabled={!canEdit}
/>
)}
<PDFGenerator
selectedPecas={selectedPecas}
allPecas={filteredAndSortedPecas}
ofNumber={ofNumber}
/>
</div>
</div>
{filteredAndSortedPecas.length === 0 ? (
<EmptyState hasActiveFilters={hasActiveFilters} />
) : (
<div className="rounded-md border border-border bg-card">
<Table>
<TableHeader>
<TableHeaderSortable
selectAll={selectAll}
onSelectAll={handleSelectAll}
sortField={sortField}
sortOrder={sortOrder}
onSort={handleSort}
/>
</TableHeader>
<TableBody>
{filteredAndSortedPecas.map((peca) => (
<PecaTableRow
key={peca.id}
peca={peca}
isSelected={selectedPecas.has(peca.id)}
onSelect={(checked) => handleSelectPeca(peca.id, checked)}
onEdit={() => handleEditPeca(peca)}
onDelete={() => handleDeletePeca(peca.id)}
onOpenComponentPopup={() => onOpenComponentPopup(peca.id)}
onOpenRevisao={() => onOpenRevisaoPeca?.(peca)}
/>
))}
</TableBody>
</Table>
</div>
)}
</div>
);
}