Files
tracksteel_app/src/pages/CadastroPecasFiltrado.tsx
T

339 lines
10 KiB
TypeScript

import React, { useState, useEffect } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { ArrowLeft, Plus, Package } from 'lucide-react';
import { PecaForm } from '@/components/pecas/PecaForm';
import { PecasTable } from '@/components/pecas/PecasTable';
import { ComponentesPopup } from '@/components/pecas/ComponentesPopup';
import { RevisaoPecaModal } from '@/components/pecas/revisoes/RevisaoPecaModal';
import { PainelRevisoesOFModal } from '@/components/pecas/revisoes/PainelRevisoesOFModal';
import { usePecas, Peca } from '@/hooks/usePecas';
import { useRevisoes } from '@/hooks/useRevisoes';
import { toast } from 'sonner';
import { usePermissionControl } from '@/hooks/usePermissionControl';
import { StandardPageLayout } from '@/components/layout/StandardPageLayout';
export default function CadastroPecasFiltrado() {
const { ofNumber } = useParams<{ ofNumber: string }>();
const navigate = useNavigate();
const ofSelecionada = ofNumber || '';
const { canCreate, canEdit, canDelete } = usePermissionControl();
const {
pecas,
loading,
ofNumbers,
savePeca,
updatePeca,
deletePeca,
deletePecasBatch,
importCSV,
importPecas,
undoLastImport,
deleteLastImport,
hasRecentImport,
batchUpdatePecas,
loadPecas
} = usePecas();
const { revisoes: revisoesOF, carregarRevisoesOF } = useRevisoes(ofSelecionada);
const [saving, setSaving] = useState(false);
const [editingPeca, setEditingPeca] = useState<Peca | null>(null);
const [showForm, setShowForm] = useState(false);
const [selectedPecaForPopup, setSelectedPecaForPopup] = useState<Peca | null>(null);
const [pecaParaRevisao, setPecaParaRevisao] = useState<Peca | null>(null);
const [showPainelRevisoes, setShowPainelRevisoes] = useState(false);
// Filtrar peças pela OF selecionada
const pecasFiltradas = pecas.filter(peca => peca.of_number === ofSelecionada);
const handleSave = async (formData: any) => {
if (!canCreate()) return false;
setSaving(true);
try {
const pecaComOF = { ...formData, of_number: ofSelecionada };
const success = await savePeca(pecaComOF);
if (success) {
setShowForm(false);
loadPecas();
}
return success;
} finally {
setSaving(false);
}
};
const handleUpdate = async (id: string, formData: any) => {
if (!canEdit()) return false;
setSaving(true);
try {
const pecaComOF = { ...formData, of_number: ofSelecionada };
const success = await updatePeca(id, pecaComOF);
if (success) {
setEditingPeca(null);
setShowForm(false);
loadPecas();
}
return success;
} finally {
setSaving(false);
}
};
const handleDelete = async (pecaId: string) => {
if (!canDelete()) return;
if (confirm('Tem certeza que deseja apagar esta peça e seus vínculos?')) {
const success = await deletePeca(pecaId);
if (success) {
loadPecas();
}
}
};
const handleDeleteBatch = async (pecaIds: string[]) => {
if (!canDelete()) return;
const success = await deletePecasBatch(pecaIds);
if (success) {
loadPecas();
}
};
const handleEdit = (peca: Peca) => {
if (!canEdit()) return;
setEditingPeca(peca);
setShowForm(true);
};
const handleCancelEdit = () => {
setEditingPeca(null);
setShowForm(false);
};
const handleDeleteLastImport = async () => {
if (!canDelete()) return;
if (confirm('Tem certeza que deseja apagar todas as peças da última importação?')) {
await deleteLastImport();
loadPecas();
}
};
const handleOpenComponentPopup = (pecaId: string) => {
const found = pecas.find(p => p.id === pecaId);
if (found) {
setSelectedPecaForPopup(found);
} else {
toast.error('Peça não encontrada');
}
};
const handleImportPecas = async (pecasData: any[]) => {
if (!canCreate()) {
toast.error('Você não tem permissão para importar peças');
throw new Error('Sem permissão');
}
try {
const pecasComOF = pecasData.map(peca => ({
...peca,
of_number: ofSelecionada
}));
await importPecas(pecasComOF);
loadPecas();
} catch (error) {
throw error;
}
};
const handleImportCSV = async (file: File): Promise<boolean> => {
if (!canCreate()) {
toast.error('Você não tem permissão para importar peças');
return false;
}
try {
await importCSV(file);
loadPecas();
return true;
} catch (error) {
return false;
}
};
const handleUndoLastImport = async () => {
if (!canDelete()) return;
if (confirm('Tem certeza que deseja desfazer a última importação?')) {
await undoLastImport();
loadPecas();
}
};
const handleBatchUpdatePecas = async (pecaIds: string[], updates: any) => {
if (!canEdit()) return;
await batchUpdatePecas(pecaIds, updates);
loadPecas();
};
useEffect(() => {
if (!ofSelecionada) {
navigate('/seletor-of');
} else {
carregarRevisoesOF(ofSelecionada);
}
}, [ofSelecionada, navigate, carregarRevisoesOF]);
if (loading) {
return (
<div className="min-h-screen bg-background p-6 flex items-center justify-center">
<div className="text-center space-y-4">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary mx-auto"></div>
<p className="text-muted-foreground">Carregando peças da OF {ofSelecionada}...</p>
</div>
</div>
);
}
const handleVoltar = () => {
if (window.history.state && window.history.state.idx > 0) {
navigate(-1);
} else {
navigate('/seletor-of');
}
};
if (!ofSelecionada) {
return null;
}
return (
<StandardPageLayout
title="Cadastro de Peças"
subtitle="Gerencie as peças da OF selecionada"
badge={{ text: `OF: ${ofSelecionada}`, variant: "secondary" }}
actions={
<div className="flex gap-2">
<Button
variant="outline"
onClick={handleVoltar}
className="flex items-center gap-2"
>
<ArrowLeft className="h-4 w-4" />
Voltar
</Button>
<Badge variant="outline" className="text-sm px-3 py-1">
{pecasFiltradas.length} peças
</Badge>
{canCreate() && (
<Button
onClick={() => {
setEditingPeca(null);
setShowForm(!showForm);
}}
className="flex items-center gap-2"
>
<Plus className="h-4 w-4" />
{showForm ? 'Fechar' : 'Nova Peça'}
</Button>
)}
</div>
}
>
<div className="space-y-6">
{/* Form Card */}
{showForm && canCreate() && (
<Card className="bg-card border-border">
<CardHeader>
<CardTitle className="text-card-foreground">
{editingPeca ? 'Editar Peça' : 'Nova Peça'}
</CardTitle>
</CardHeader>
<CardContent>
<PecaForm
ofNumbers={[ofSelecionada]}
ofDefault={ofSelecionada}
onSave={handleSave}
onUpdate={handleUpdate}
onImportCSV={handleImportCSV}
saving={saving}
editingPeca={editingPeca}
onCancelEdit={handleCancelEdit}
hasRecentImport={hasRecentImport}
onDeleteLastImport={handleDeleteLastImport}
pecas={pecasFiltradas}
onImportPecas={handleImportPecas}
onUndoLastImport={handleUndoLastImport}
canImport={canCreate()}
canDelete={canDelete()}
/>
</CardContent>
</Card>
)}
{/* Table Card */}
<Card className="bg-card border-border">
<CardHeader>
<CardTitle className="text-card-foreground flex items-center gap-2">
<Package className="h-5 w-5" />
Peças da OF {ofSelecionada}
</CardTitle>
</CardHeader>
<CardContent>
<PecasTable
pecas={pecasFiltradas}
onOpenComponentPopup={handleOpenComponentPopup}
onDeletePeca={canDelete() ? handleDelete : undefined}
onDeletePecasBatch={canDelete() ? handleDeleteBatch : undefined}
onEditPeca={canEdit() ? handleEdit : undefined}
onDeleteLastImport={canDelete() ? handleDeleteLastImport : undefined}
onBatchUpdatePecas={canEdit() ? handleBatchUpdatePecas : undefined}
onOpenRevisaoPeca={(peca) => setPecaParaRevisao(peca)}
onOpenPainelRevisoes={() => setShowPainelRevisoes(true)}
totalRevisoesOF={revisoesOF.length}
hasRecentImport={hasRecentImport}
canEdit={canEdit()}
canDelete={canDelete()}
ofNumber={ofSelecionada}
/>
</CardContent>
</Card>
{/* Modal de Gerenciamento de Componentes */}
{selectedPecaForPopup && (
<ComponentesPopup
isOpen={!!selectedPecaForPopup}
onClose={() => {
setSelectedPecaForPopup(null);
loadPecas();
}}
peca={selectedPecaForPopup}
/>
)}
{/* Modal de Gestão de Revisão da Peça */}
{pecaParaRevisao && (
<RevisaoPecaModal
isOpen={!!pecaParaRevisao}
onClose={() => setPecaParaRevisao(null)}
peca={pecaParaRevisao}
onPecaAtualizada={() => {
loadPecas();
carregarRevisoesOF(ofSelecionada);
}}
/>
)}
{/* Modal Painel Geral de Revisões da OF */}
{showPainelRevisoes && (
<PainelRevisoesOFModal
isOpen={showPainelRevisoes}
onClose={() => setShowPainelRevisoes(false)}
ofNumber={ofSelecionada}
pecas={pecasFiltradas}
onOpenRevisaoPeca={(peca) => setPecaParaRevisao(peca)}
/>
)}
</div>
</StandardPageLayout>
);
}