fix: exclusao em cascata de pecas e importacao inteligente sem duplicidade

This commit is contained in:
2026-09-16 15:19:09 +00:00
parent 6570f50a1a
commit 74336b0da0
5 changed files with 285 additions and 190 deletions
+13 -6
View File
@@ -18,6 +18,7 @@ interface PecasTableProps {
pecas: Peca[]; pecas: Peca[];
onOpenComponentPopup: (pecaId: string) => void; onOpenComponentPopup: (pecaId: string) => void;
onDeletePeca?: (pecaId: string) => void; onDeletePeca?: (pecaId: string) => void;
onDeletePecasBatch?: (pecaIds: string[]) => Promise<any>;
onEditPeca?: (peca: Peca) => void; onEditPeca?: (peca: Peca) => void;
onDeleteLastImport?: () => void; onDeleteLastImport?: () => void;
onBatchUpdatePecas?: (pecaIds: string[], updates: any) => Promise<void>; onBatchUpdatePecas?: (pecaIds: string[], updates: any) => Promise<void>;
@@ -31,6 +32,7 @@ export function PecasTable({
pecas, pecas,
onOpenComponentPopup, onOpenComponentPopup,
onDeletePeca, onDeletePeca,
onDeletePecasBatch,
onEditPeca, onEditPeca,
onDeleteLastImport, onDeleteLastImport,
onBatchUpdatePecas, onBatchUpdatePecas,
@@ -89,19 +91,24 @@ export function PecasTable({
}; };
const handleDeleteSelected = async () => { const handleDeleteSelected = async () => {
if (!canDelete || !onDeletePeca) { if (!canDelete || (!onDeletePecasBatch && !onDeletePeca)) {
toast.error('Você não tem permissão para excluir peças'); toast.error('Você não tem permissão para excluir peças');
return; return;
} }
if (window.confirm(`Tem certeza que deseja excluir ${selectedPecas.size} peças?`)) { if (window.confirm(`Tem certeza que deseja excluir ${selectedPecas.size} peças selecionadas e seus vínculos?`)) {
try { try {
for (const pecaId of selectedPecas) { const pecaIdsArray = Array.from(selectedPecas);
await onDeletePeca(pecaId); if (onDeletePecasBatch) {
await onDeletePecasBatch(pecaIdsArray);
} else if (onDeletePeca) {
for (const pecaId of pecaIdsArray) {
await onDeletePeca(pecaId);
}
toast.success('Peças excluídas com sucesso!');
} }
toast.success('Peças excluídas com sucesso!');
} catch (error) { } catch (error) {
toast.error('Erro ao excluir peças.'); console.error('Erro ao excluir peças:', error);
} }
} }
}; };
+7
View File
@@ -172,6 +172,13 @@ export function useComponentesPeca(pecaIds: string | string[] = []) {
} }
try { try {
// 1. Apagar apontamentos de produção vinculados ao componente
await supabase
.from('apontamentos_producao')
.delete()
.eq('componente_id', id);
// 2. Apagar o componente
const { error } = await supabase const { error } = await supabase
.from('componentes_peca') .from('componentes_peca')
.delete() .delete()
+194 -107
View File
@@ -241,6 +241,83 @@ export function usePecas() {
} }
}; };
const deletePecasCascade = async (pecaIds: string[]): Promise<boolean> => {
if (!pecaIds || pecaIds.length === 0) return true;
try {
console.log('🗑️ Iniciando exclusão em cascata para peças:', pecaIds);
// 1. Obter todos os IDs de componentes vinculados a essas peças
const { data: componentes } = await supabase
.from('componentes_peca')
.select('id')
.in('peca_id', pecaIds);
const componenteIds = componentes?.map(c => c.id) || [];
// 2. Apagar apontamentos de produção vinculados aos componentes
if (componenteIds.length > 0) {
const { error: apCompError } = await supabase
.from('apontamentos_producao')
.delete()
.in('componente_id', componenteIds);
if (apCompError) console.warn('Aviso ao apagar apontamentos de componentes:', apCompError);
}
// 3. Apagar apontamentos de produção vinculados diretamente às peças
const { error: apPecaError } = await supabase
.from('apontamentos_producao')
.delete()
.in('peca_id', pecaIds);
if (apPecaError) console.warn('Aviso ao apagar apontamentos de peças:', apPecaError);
// 4. Apagar itens de prioridades de fabricação
const { error: prioridadesError } = await supabase
.from('itens_prioridade_fabricacao')
.delete()
.in('peca_id', pecaIds);
if (prioridadesError) console.warn('Aviso ao apagar itens de prioridade:', prioridadesError);
// 5. Apagar itens de romaneio de peças
const { error: romaneioError } = await supabase
.from('itens_romaneio_pecas')
.delete()
.in('peca_id', pecaIds);
if (romaneioError) console.warn('Aviso ao apagar itens de romaneio:', romaneioError);
// 6. Apagar datas de processos
const { error: processosError } = await supabase
.from('processos_pecas_datas')
.delete()
.in('peca_id', pecaIds);
if (processosError) console.warn('Aviso ao apagar processos datas:', processosError);
// 7. Apagar componentes das peças
const { error: compError } = await supabase
.from('componentes_peca')
.delete()
.in('peca_id', pecaIds);
if (compError) console.warn('Aviso ao apagar componentes:', compError);
// 8. Apagar as peças principais
const { error: deleteError } = await supabase
.from('pecas')
.delete()
.in('id', pecaIds);
if (deleteError) {
console.error('❌ Erro ao apagar peças do banco:', deleteError);
throw deleteError;
}
console.log('✅ Peças e vínculos apagados com sucesso');
return true;
} catch (error) {
console.error('❌ Erro na exclusão em cascata das peças:', error);
throw error;
}
};
const deletePeca = async (pecaId: string): Promise<boolean> => { const deletePeca = async (pecaId: string): Promise<boolean> => {
if (!user) { if (!user) {
toast.error('Usuário não autenticado'); toast.error('Usuário não autenticado');
@@ -248,17 +325,7 @@ export function usePecas() {
} }
try { try {
const { error } = await supabase await deletePecasCascade([pecaId]);
.from('pecas')
.delete()
.eq('id', pecaId);
if (error) {
console.error('Erro ao apagar peça:', error);
toast.error('Erro ao apagar peça');
return false;
}
toast.success('Peça apagada com sucesso!'); toast.success('Peça apagada com sucesso!');
await loadPecas(); await loadPecas();
return true; return true;
@@ -269,6 +336,24 @@ export function usePecas() {
} }
}; };
const deletePecasBatch = async (pecaIds: string[]): Promise<boolean> => {
if (!user) {
toast.error('Usuário não autenticado');
return false;
}
try {
await deletePecasCascade(pecaIds);
toast.success(`${pecaIds.length} peça(s) apagada(s) com sucesso!`);
await loadPecas();
return true;
} catch (error) {
console.error('Erro ao apagar peças selecionadas:', error);
toast.error('Erro ao apagar peças selecionadas');
return false;
}
};
const importCSV = async (file: File) => { const importCSV = async (file: File) => {
console.log('📄 Importando CSV...'); console.log('📄 Importando CSV...');
if (!user) { if (!user) {
@@ -313,25 +398,7 @@ export function usePecas() {
return; return;
} }
const { error } = await supabase await importPecas(pecasData);
.from('pecas')
.insert(pecasData);
if (error) {
console.error('❌ Erro ao importar CSV:', error);
throw error;
}
console.log('✅ CSV importado com sucesso:', pecasData.length, 'peças');
toast.success(`${pecasData.length} peça(s) importada(s) com sucesso!`);
setHasRecentImport(true);
// Sincronização manual apenas após importação
setTimeout(() => {
sincronizarPrioridades(false);
}, 3000);
await loadPecas();
} catch (error) { } catch (error) {
console.error('❌ Erro ao importar CSV:', error); console.error('❌ Erro ao importar CSV:', error);
toast.error('Erro ao importar arquivo CSV'); toast.error('Erro ao importar arquivo CSV');
@@ -340,7 +407,7 @@ export function usePecas() {
}; };
const importPecas = async (pecasData: any[]) => { const importPecas = async (pecasData: any[]) => {
console.log('📦 Iniciando importação de peças:', pecasData.length); console.log('📦 Iniciando importação inteligente de peças:', pecasData.length);
if (!user) { if (!user) {
toast.error('Usuário não autenticado'); toast.error('Usuário não autenticado');
return; return;
@@ -353,8 +420,6 @@ export function usePecas() {
console.log('🔍 Separando dados de peças e componentes...'); console.log('🔍 Separando dados de peças e componentes...');
pecasData.forEach((item, index) => { pecasData.forEach((item, index) => {
console.log(`📋 Processando item ${index + 1}:`, item);
const pecaKey = `${item.of_number || ''}-${item.etapa_fase || ''}-${item.marca || ''}`; const pecaKey = `${item.of_number || ''}-${item.etapa_fase || ''}-${item.marca || ''}`;
const pecaData = { const pecaData = {
@@ -394,75 +459,135 @@ export function usePecas() {
} }
}); });
const pecasParaInserir = Array.from(pecasMap.values()); const pecasParaProcessar = Array.from(pecasMap.values());
console.log('✅ Peças para inserir:', pecasParaInserir.length); console.log('✅ Peças únicas a processar:', pecasParaProcessar.length);
console.log('✅ Peças com componentes:', componentesMap.size); console.log('✅ Peças com componentes:', componentesMap.size);
if (pecasParaInserir.length === 0) { if (pecasParaProcessar.length === 0) {
toast.error('Nenhuma peça válida encontrada para importação'); toast.error('Nenhuma peça válida encontrada para importação');
return; return;
} }
console.log('💾 Inserindo peças principais...'); // 1. Consultar peças existentes para não duplicar (mesma OF, Fase e Marca)
const { data: pecasInseridas, error: pecasError } = await supabase const ofsParaConsultar = Array.from(new Set(pecasParaProcessar.map(p => p.of_number).filter(Boolean)));
const { data: pecasExistentes, error: queryExistentesError } = await supabase
.from('pecas') .from('pecas')
.insert(pecasParaInserir) .select('id, of_number, etapa_fase, marca')
.select('id, of_number, etapa_fase, marca'); .eq('user_id', user.id)
.in('of_number', ofsParaConsultar);
if (pecasError) { if (queryExistentesError) {
console.error('❌ Erro ao inserir peças:', pecasError); console.warn('Aviso ao consultar peças existentes:', queryExistentesError);
toast.error(`Erro ao inserir peças: ${pecasError.message}`);
throw pecasError;
} }
console.log('✅ Peças inseridas com sucesso:', pecasInseridas?.length || 0); const existingPecasMap = new Map<string, string>();
if (pecasExistentes) {
pecasExistentes.forEach(ep => {
const key = `${ep.of_number || ''}-${ep.etapa_fase || ''}-${ep.marca || ''}`;
existingPecasMap.set(key, ep.id);
});
}
const pecaIdResolvedMap = new Map<string, string>();
const pecasNovasParaInserir: any[] = [];
let totalAtualizadas = 0;
// 2. Atualizar existentes mantendo ID (preservando apontamentos e prioridades)
for (const peca of pecasParaProcessar) {
const key = `${peca.of_number || ''}-${peca.etapa_fase || ''}-${peca.marca || ''}`;
const existingId = existingPecasMap.get(key);
if (existingId) {
const { error: updateError } = await supabase
.from('pecas')
.update({
descricao: peca.descricao,
quantidade: peca.quantidade,
peso_unitario: peca.peso_unitario,
peso_total: peca.peso_total,
tratamento_superficial: peca.tratamento_superficial,
material: peca.material,
perfil_principal: peca.perfil_principal,
tem_componentes: peca.tem_componentes
})
.eq('id', existingId);
if (!updateError) {
pecaIdResolvedMap.set(key, existingId);
totalAtualizadas++;
}
} else {
pecasNovasParaInserir.push(peca);
}
}
// 3. Inserir novas peças
let totalNovas = 0;
if (pecasNovasParaInserir.length > 0) {
console.log('💾 Inserindo novas peças principais:', pecasNovasParaInserir.length);
const { data: pecasInseridas, error: pecasError } = await supabase
.from('pecas')
.insert(pecasNovasParaInserir)
.select('id, of_number, etapa_fase, marca');
if (pecasError) {
console.error('❌ Erro ao inserir novas peças:', pecasError);
toast.error(`Erro ao inserir peças: ${pecasError.message}`);
throw pecasError;
}
if (pecasInseridas) {
totalNovas = pecasInseridas.length;
pecasInseridas.forEach(p => {
const key = `${p.of_number || ''}-${p.etapa_fase || ''}-${p.marca || ''}`;
pecaIdResolvedMap.set(key, p.id);
});
}
}
// 4. Inserir/Sincronizar Componentes
let totalComponentesInseridos = 0; let totalComponentesInseridos = 0;
if (componentesMap.size > 0) {
if (componentesMap.size > 0 && pecasInseridas) { console.log('🔧 Inserindo e sincronizando componentes...');
console.log('🔧 Inserindo componentes...');
for (const [pecaKey, componentes] of componentesMap.entries()) { for (const [pecaKey, componentes] of componentesMap.entries()) {
const [of_number, etapa_fase, marca] = pecaKey.split('-'); const pecaId = pecaIdResolvedMap.get(pecaKey);
const pecaInserida = pecasInseridas.find(p => if (pecaId && componentes.length > 0) {
p.of_number === of_number && // Limpar componentes antigos desta peça para atualizar de forma limpa
p.etapa_fase === etapa_fase && await supabase
p.marca === marca .from('componentes_peca')
); .delete()
.eq('peca_id', pecaId);
if (pecaInserida && componentes.length > 0) {
const componentesComPecaId = componentes.map(comp => ({ const componentesComPecaId = componentes.map(comp => ({
...comp, ...comp,
peca_id: pecaInserida.id peca_id: pecaId
})); }));
console.log(`🔧 Inserindo ${componentesComPecaId.length} componentes para peça ${marca}...`);
const { error: componentesError } = await supabase const { error: componentesError } = await supabase
.from('componentes_peca') .from('componentes_peca')
.insert(componentesComPecaId); .insert(componentesComPecaId);
if (componentesError) { if (componentesError) {
console.error('❌ Erro ao inserir componentes:', componentesError); console.error(`❌ Erro ao inserir componentes para ${pecaKey}:`, componentesError);
} else { } else {
totalComponentesInseridos += componentesComPecaId.length; totalComponentesInseridos += componentesComPecaId.length;
console.log(`✅ Componentes inseridos para peça ${marca}: ${componentesComPecaId.length}`);
} }
} }
} }
} }
let successMessage = `✅ ${pecasInseridas?.length || 0} peça(s) importada(s) com sucesso!`; let successMessage = `✅ Importação concluída!`;
if (totalComponentesInseridos > 0) { if (totalNovas > 0) successMessage += ` ${totalNovas} nova(s) peça(s).`;
successMessage += ` ${totalComponentesInseridos} componente(s) também foram criados.`; if (totalAtualizadas > 0) successMessage += ` ${totalAtualizadas} peça(s) atualizada(s).`;
} if (totalComponentesInseridos > 0) successMessage += ` ${totalComponentesInseridos} componente(s) vinculados.`;
console.log('🎉 Importação concluída:', successMessage); console.log('🎉 Importação concluída:', successMessage);
toast.success(successMessage); toast.success(successMessage);
setHasRecentImport(true); setHasRecentImport(true);
// Sincronização manual apenas após importação // Sincronização manual de prioridades
setTimeout(() => { setTimeout(() => {
sincronizarPrioridades(false); sincronizarPrioridades(false);
}, 3000); }, 3000);
@@ -500,27 +625,7 @@ export function usePecas() {
} }
const pecaIds = pecasParaApagar.map(peca => peca.id); const pecaIds = pecasParaApagar.map(peca => peca.id);
const { error: deleteComponentesError } = await supabase await deletePecasCascade(pecaIds);
.from('componentes_peca')
.delete()
.in('peca_id', pecaIds);
if (deleteComponentesError) {
console.error('Erro ao apagar componentes das peças:', deleteComponentesError);
toast.error('Erro ao apagar componentes das peças');
return;
}
const { error: deleteError } = await supabase
.from('pecas')
.delete()
.in('id', pecaIds);
if (deleteError) {
console.error('Erro ao apagar peças:', deleteError);
toast.error('Erro ao apagar peças');
return;
}
toast.success('Última importação desfeita com sucesso!'); toast.success('Última importação desfeita com sucesso!');
setHasRecentImport(false); setHasRecentImport(false);
@@ -556,27 +661,7 @@ export function usePecas() {
} }
const pecaIds = pecasParaApagar.map(peca => peca.id); const pecaIds = pecasParaApagar.map(peca => peca.id);
const { error: deleteComponentesError } = await supabase await deletePecasCascade(pecaIds);
.from('componentes_peca')
.delete()
.in('peca_id', pecaIds);
if (deleteComponentesError) {
console.error('Erro ao apagar componentes das peças:', deleteComponentesError);
toast.error('Erro ao apagar componentes das peças');
return;
}
const { error: deleteError } = await supabase
.from('pecas')
.delete()
.in('id', pecaIds);
if (deleteError) {
console.error('Erro ao apagar peças:', deleteError);
toast.error('Erro ao apagar peças');
return;
}
toast.success('Última importação apagada com sucesso!'); toast.success('Última importação apagada com sucesso!');
setHasRecentImport(false); setHasRecentImport(false);
@@ -635,6 +720,7 @@ export function usePecas() {
savePeca, savePeca,
updatePeca, updatePeca,
deletePeca, deletePeca,
deletePecasBatch,
importCSV, importCSV,
importPecas, importPecas,
undoLastImport, undoLastImport,
@@ -645,3 +731,4 @@ export function usePecas() {
sincronizarPrioridades sincronizarPrioridades
}; };
} }
+8 -1
View File
@@ -23,6 +23,7 @@ export default function CadastroPecas() {
savePeca, savePeca,
updatePeca, updatePeca,
deletePeca, deletePeca,
deletePecasBatch,
importCSV, importCSV,
importPecas, importPecas,
undoLastImport, undoLastImport,
@@ -70,11 +71,16 @@ export default function CadastroPecas() {
const handleDelete = async (pecaId: string) => { const handleDelete = async (pecaId: string) => {
if (!canDelete()) return; if (!canDelete()) return;
if (confirm('Tem certeza que deseja apagar esta peça?')) { if (confirm('Tem certeza que deseja apagar esta peça e seus vínculos?')) {
await deletePeca(pecaId); await deletePeca(pecaId);
} }
}; };
const handleDeleteBatch = async (pecaIds: string[]) => {
if (!canDelete()) return;
await deletePecasBatch(pecaIds);
};
const handleEdit = (peca: Peca) => { const handleEdit = (peca: Peca) => {
if (!canEdit()) return; if (!canEdit()) return;
setEditingPeca(peca); setEditingPeca(peca);
@@ -233,6 +239,7 @@ export default function CadastroPecas() {
pecas={pecas} pecas={pecas}
onOpenComponentPopup={handleOpenComponentPopup} onOpenComponentPopup={handleOpenComponentPopup}
onDeletePeca={canDelete() ? handleDelete : undefined} onDeletePeca={canDelete() ? handleDelete : undefined}
onDeletePecasBatch={canDelete() ? handleDeleteBatch : undefined}
onEditPeca={canEdit() ? handleEdit : undefined} onEditPeca={canEdit() ? handleEdit : undefined}
onDeleteLastImport={canDelete() ? handleDeleteLastImport : undefined} onDeleteLastImport={canDelete() ? handleDeleteLastImport : undefined}
hasRecentImport={hasRecentImport} hasRecentImport={hasRecentImport}
+60 -73
View File
@@ -24,6 +24,7 @@ export default function CadastroPecasFiltrado() {
savePeca, savePeca,
updatePeca, updatePeca,
deletePeca, deletePeca,
deletePecasBatch,
importCSV, importCSV,
importPecas, importPecas,
undoLastImport, undoLastImport,
@@ -45,12 +46,10 @@ export default function CadastroPecasFiltrado() {
if (!canCreate()) return false; if (!canCreate()) return false;
setSaving(true); setSaving(true);
try { try {
// Garantir que a peça seja salva com a OF selecionada const pecaComOF = { ...formData, of_number: ofSelecionada };
const formDataComOF = { ...formData, of_number: ofSelecionada }; const success = await savePeca(pecaComOF);
const success = await savePeca(formDataComOF);
if (success) { if (success) {
setShowForm(false); setShowForm(false);
// Reload data after successful save
loadPecas(); loadPecas();
} }
return success; return success;
@@ -59,15 +58,15 @@ export default function CadastroPecasFiltrado() {
} }
}; };
const handleUpdate = async (id: string, formData: any) => { const handleUpdate = async (formData: any) => {
if (!canEdit()) return false; if (!canEdit() || !editingPeca) return false;
setSaving(true); setSaving(true);
try { try {
const success = await updatePeca(id, formData); const pecaComOF = { ...formData, of_number: ofSelecionada };
const success = await updatePeca(editingPeca.id, pecaComOF);
if (success) { if (success) {
setEditingPeca(null); setEditingPeca(null);
setShowForm(false); setShowForm(false);
// Reload data after successful update
loadPecas(); loadPecas();
} }
return success; return success;
@@ -78,15 +77,22 @@ export default function CadastroPecasFiltrado() {
const handleDelete = async (pecaId: string) => { const handleDelete = async (pecaId: string) => {
if (!canDelete()) return; if (!canDelete()) return;
if (confirm('Tem certeza que deseja apagar esta peça?')) { if (confirm('Tem certeza que deseja apagar esta peça e seus vínculos?')) {
const success = await deletePeca(pecaId); const success = await deletePeca(pecaId);
if (success) { if (success) {
// Reload data after successful delete
loadPecas(); loadPecas();
} }
} }
}; };
const handleDeleteBatch = async (pecaIds: string[]) => {
if (!canDelete()) return;
const success = await deletePecasBatch(pecaIds);
if (success) {
loadPecas();
}
};
const handleEdit = (peca: Peca) => { const handleEdit = (peca: Peca) => {
if (!canEdit()) return; if (!canEdit()) return;
setEditingPeca(peca); setEditingPeca(peca);
@@ -102,7 +108,6 @@ export default function CadastroPecasFiltrado() {
if (!canDelete()) return; if (!canDelete()) return;
if (confirm('Tem certeza que deseja apagar todas as peças da última importação?')) { if (confirm('Tem certeza que deseja apagar todas as peças da última importação?')) {
await deleteLastImport(); await deleteLastImport();
// Reload data after successful delete
loadPecas(); loadPecas();
} }
}; };
@@ -122,13 +127,11 @@ export default function CadastroPecasFiltrado() {
throw new Error('Sem permissão'); throw new Error('Sem permissão');
} }
try { try {
// Adicionar a OF selecionada a todas as peças importadas
const pecasComOF = pecasData.map(peca => ({ const pecasComOF = pecasData.map(peca => ({
...peca, ...peca,
of_number: ofSelecionada of_number: ofSelecionada
})); }));
await importPecas(pecasComOF); await importPecas(pecasComOF);
// Reload data after successful import
loadPecas(); loadPecas();
} catch (error) { } catch (error) {
throw error; throw error;
@@ -142,38 +145,25 @@ export default function CadastroPecasFiltrado() {
} }
try { try {
await importCSV(file); await importCSV(file);
// Reload data after successful import
loadPecas(); loadPecas();
return true; return true;
} catch (error) { } catch (error) {
console.error('Erro ao importar CSV:', error);
return false; return false;
} }
}; };
const handleBatchUpdatePecas = async (pecaIds: string[], updates: any) => {
if (!canEdit()) {
toast.error('Você não tem permissão para editar peças');
throw new Error('Sem permissão');
}
try {
await batchUpdatePecas(pecaIds, updates);
// Reload data after successful batch update
loadPecas();
} catch (error) {
throw error;
}
};
const handleUndoLastImport = async () => { const handleUndoLastImport = async () => {
await undoLastImport(); if (!canDelete()) return;
// Reload data after successful undo if (confirm('Tem certeza que deseja desfazer a última importação?')) {
loadPecas(); await undoLastImport();
loadPecas();
}
}; };
const handleVoltar = () => { const handleBatchUpdatePecas = async (pecaIds: string[], updates: any) => {
navigate('/seletor-of'); if (!canEdit()) return;
await batchUpdatePecas(pecaIds, updates);
loadPecas();
}; };
useEffect(() => { useEffect(() => {
@@ -197,56 +187,52 @@ export default function CadastroPecasFiltrado() {
} }
return ( return (
<div className="min-h-screen bg-background p-6"> <StandardPageLayout
<div className="max-w-7xl mx-auto space-y-6"> title="Cadastro de Peças"
{/* Header */} description="Gerencie as peças da OF selecionada"
<div className="flex items-center justify-between"> badges={[
<div> { label: `OF: ${ofSelecionada}`, variant: "secondary" }
<div className="flex items-center gap-4 mb-2"> ]}
<h1 className="text-3xl font-bold text-foreground">Cadastro de Peças</h1> actions={
<Badge variant="secondary" className="text-lg px-3 py-1"> <div className="flex gap-2">
OF: {ofSelecionada} <Button
</Badge> variant="outline"
</div> onClick={() => navigate('/ordens-fabricacao')}
<p className="text-muted-foreground">Gerencie as peças da OF selecionada</p> className="flex items-center gap-2"
</div> >
<div className="flex items-center gap-4"> <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 <Button
onClick={handleVoltar} onClick={() => {
variant="outline" setEditingPeca(null);
setShowForm(!showForm);
}}
className="flex items-center gap-2" className="flex items-center gap-2"
> >
<ArrowLeft className="h-4 w-4" /> <Plus className="h-4 w-4" />
Voltar {showForm ? 'Fechar' : 'Nova Peça'}
</Button> </Button>
<Badge variant="secondary" className="bg-secondary text-secondary-foreground border-border"> )}
{pecasFiltradas.length} {pecasFiltradas.length === 1 ? 'peça' : 'peças'}
</Badge>
{canCreate() && (
<Button
onClick={() => setShowForm(true)}
className="bg-primary hover:bg-primary/90 text-primary-foreground flex items-center gap-2"
>
<Plus className="h-4 w-4" />
Nova Peça
</Button>
)}
</div>
</div> </div>
}
>
<div className="space-y-6">
{/* Form Card */} {/* Form Card */}
{showForm && canCreate() && ( {showForm && canCreate() && (
<Card className="bg-card border-border"> <Card className="bg-card border-border">
<CardHeader> <CardHeader>
<CardTitle className="text-card-foreground flex items-center gap-2"> <CardTitle className="text-card-foreground">
<Package className="h-5 w-5" /> {editingPeca ? 'Editar Peça' : 'Nova Peça'}
{editingPeca ? 'Editar Peça' : 'Nova Peça'} - OF: {ofSelecionada}
</CardTitle> </CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<PecaForm <PecaForm
ofNumbers={[ofSelecionada]} // Apenas a OF selecionada ofNumber={ofSelecionada}
ofDefault={ofSelecionada}
onSave={handleSave} onSave={handleSave}
onUpdate={handleUpdate} onUpdate={handleUpdate}
onImportCSV={handleImportCSV} onImportCSV={handleImportCSV}
@@ -278,6 +264,7 @@ export default function CadastroPecasFiltrado() {
pecas={pecasFiltradas} pecas={pecasFiltradas}
onOpenComponentPopup={handleOpenComponentPopup} onOpenComponentPopup={handleOpenComponentPopup}
onDeletePeca={canDelete() ? handleDelete : undefined} onDeletePeca={canDelete() ? handleDelete : undefined}
onDeletePecasBatch={canDelete() ? handleDeleteBatch : undefined}
onEditPeca={canEdit() ? handleEdit : undefined} onEditPeca={canEdit() ? handleEdit : undefined}
onDeleteLastImport={canDelete() ? handleDeleteLastImport : undefined} onDeleteLastImport={canDelete() ? handleDeleteLastImport : undefined}
onBatchUpdatePecas={canEdit() ? handleBatchUpdatePecas : undefined} onBatchUpdatePecas={canEdit() ? handleBatchUpdatePecas : undefined}
@@ -301,6 +288,6 @@ export default function CadastroPecasFiltrado() {
/> />
)} )}
</div> </div>
</div> </StandardPageLayout>
); );
} }