import React, { useState, useEffect, useMemo } from 'react'; import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { Badge } from '@/components/ui/badge'; import { ScrollArea } from '@/components/ui/scroll-area'; import { Card, CardContent } from '@/components/ui/card'; import { Checkbox } from '@/components/ui/checkbox'; import { toast } from 'sonner'; import { Package, Plus, Wrench, Expand } from 'lucide-react'; import { RomaneioExpedicao } from '@/hooks/useRomaneios'; import { useProcessosFabricacao } from '@/hooks/useProcessosFabricacao'; import { usePecas } from '@/hooks/usePecas'; import { useMobileResponsive } from '@/hooks/useMobileResponsive'; import { supabase } from '@/integrations/supabase/client'; import { PecasRomaneioExpandido } from './PecasRomaneioExpandido'; interface ItensRomaneioModalProps { romaneio: RomaneioExpedicao; isOpen: boolean; onClose: () => void; } interface PecaDisponivel { id: string; marca: string; descricao: string; etapa_fase: string; quantidade_disponivel: number; peso_unitario: number; prioridade: string; } interface ItemRomaneioPeca { id: string; peca_id: string; quantidade: number; peso_unitario: number; peso_total: number; marca: string; descricao: string; etapa_fase: string; prioridade: string; } interface ItemRomaneioInsumo { id: string; nome: string; quantidade: number; unidade: string; } export const ItensRomaneioModal: React.FC = ({ romaneio, isOpen, onClose }) => { const { isMobile, isTablet } = useMobileResponsive(); const { data: processos } = useProcessosFabricacao(); const { pecas: todasPecas } = usePecas(); // Estados para filtros const [processoSelecionado, setProcessoSelecionado] = useState('Pintura/Galv'); const [faseFilter, setFaseFilter] = useState('Todas as fases'); const [marcaFilter, setMarcaFilter] = useState(''); const [pecaDisponivel, setPecaDisponivel] = useState(''); const [quantidadePeca, setQuantidadePeca] = useState(''); // Estados para dados dinâmicos const [pecasDisponiveis, setPecasDisponiveis] = useState([]); const [fasesDisponiveis, setFasesDisponiveis] = useState([]); const [marcasDisponiveis, setMarcasDisponiveis] = useState([]); const [loading, setLoading] = useState(false); // Estados para itens do romaneio const [itensPeca, setItensPeca] = useState([]); const [itensInsumo, setItensInsumo] = useState([]); const [loadingItens, setLoadingItens] = useState(false); // Estados para insumos const [nomeInsumo, setNomeInsumo] = useState(''); const [quantidadeInsumo, setQuantidadeInsumo] = useState(''); const [unidadeInsumo, setUnidadeInsumo] = useState(''); // Estados para adicionar todas as peças const [adicionarTodas, setAdicionarTodas] = useState(false); // Novo estado para o modal expandido const [showExpandedModal, setShowExpandedModal] = useState(false); // Buscar peças disponíveis baseadas no processo selecionado const buscarPecasDisponiveis = async (processo: string) => { if (!romaneio.of_number) return; setLoading(true); try { // Buscar peças que estão no processo selecionado e disponíveis para expedição const { data: apontamentosData, error } = await supabase .from('apontamentos_producao') .select(` peca_id, quantidade_produzida, processo_id, processos_fabricacao!inner(nome), peca:pecas!inner!apontamentos_producao_peca_id_fkey( id, marca, descricao, etapa_fase, peso_unitario, prioridade, of_number ) `) .eq('peca.of_number', romaneio.of_number) .eq('processos_fabricacao.nome', processo); if (error) { console.error('Erro ao buscar peças disponíveis:', error); return; } // Agrupar por peça e calcular quantidade disponível const pecasAgrupadas = new Map(); // eslint-disable-next-line @typescript-eslint/no-explicit-any (apontamentosData as any[])?.forEach((apontamento: any) => { const pecaId = apontamento.peca?.id; if (!pecaId) return; const quantidade = apontamento.quantidade_produzida || 0; if (pecasAgrupadas.has(pecaId)) { const pecaExistente = pecasAgrupadas.get(pecaId)!; pecaExistente.quantidade_disponivel += quantidade; } else { pecasAgrupadas.set(pecaId, { id: apontamento.peca.id, marca: apontamento.peca.marca, descricao: apontamento.peca.descricao || '', etapa_fase: apontamento.peca.etapa_fase || '', quantidade_disponivel: quantidade, peso_unitario: apontamento.peca.peso_unitario || 0, prioridade: apontamento.peca.prioridade || 'P4' }); } }); const pecasArray = Array.from(pecasAgrupadas.values()); setPecasDisponiveis(pecasArray); // Extrair fases e marcas únicas const fasesUnicas = [...new Set(pecasArray.map(p => p.etapa_fase).filter(Boolean))]; const marcasUnicas = [...new Set(pecasArray.map(p => p.marca).filter(Boolean))]; setFasesDisponiveis(fasesUnicas); setMarcasDisponiveis(marcasUnicas); } catch (error) { console.error('Erro ao buscar peças disponíveis:', error); toast.error('Erro ao carregar peças disponíveis'); } finally { setLoading(false); } }; // Carregar itens existentes do romaneio const carregarItensRomaneio = async () => { setLoadingItens(true); try { // Carregar peças do romaneio - usando a tabela correta const { data: pecasData, error: pecasError } = await supabase .from('itens_romaneio_pecas') .select(` *, pecas!inner(marca, descricao, etapa_fase, peso_unitario, prioridade) `) .eq('romaneio_id', romaneio.id); if (pecasError) { console.error('Erro ao carregar peças do romaneio:', pecasError); } else if (pecasData) { // eslint-disable-next-line @typescript-eslint/no-explicit-any const itensPecaFormatados = pecasData.map((item: any) => ({ id: item.id, peca_id: item.peca_id, quantidade: item.quantidade_expedida, peso_unitario: item.peso_unitario, peso_total: item.peso_total, marca: item.marca, descricao: item.descricao || '', etapa_fase: item.fase || '', prioridade: 'P4' })); setItensPeca(itensPecaFormatados); } // Carregar insumos do romaneio - usando a tabela correta const { data: insumosData, error: insumosError } = await supabase .from('itens_romaneio_insumos') .select('*') .eq('romaneio_id', romaneio.id); if (insumosError) { console.error('Erro ao carregar insumos do romaneio:', insumosError); } else if (insumosData) { // eslint-disable-next-line @typescript-eslint/no-explicit-any const itensInsumoFormatados = insumosData.map((item: any) => ({ id: item.id, nome: item.descricao, quantidade: item.quantidade_expedida, unidade: item.unidade })); setItensInsumo(itensInsumoFormatados); } } catch (error) { console.error('Erro ao carregar itens do romaneio:', error); toast.error('Erro ao carregar itens do romaneio'); } finally { setLoadingItens(false); } }; // Carregar peças quando processo selecionado mudar useEffect(() => { if (processoSelecionado && isOpen) { buscarPecasDisponiveis(processoSelecionado); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [processoSelecionado, isOpen, romaneio.of_number]); // Definir processo padrão quando abrir o modal useEffect(() => { if (isOpen) { setProcessoSelecionado('Pintura/Galv'); setFaseFilter('Todas as fases'); setMarcaFilter(''); setPecaDisponivel(''); setQuantidadePeca(''); setAdicionarTodas(false); carregarItensRomaneio(); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [isOpen]); // Filtrar peças baseado nos filtros selecionados const pecasFiltradas = useMemo(() => { let filtradas = [...pecasDisponiveis]; if (faseFilter !== 'Todas as fases') { filtradas = filtradas.filter(p => p.etapa_fase === faseFilter); } if (marcaFilter.trim()) { filtradas = filtradas.filter(p => p.marca.toLowerCase().includes(marcaFilter.toLowerCase()) ); } return filtradas.sort((a, b) => { const aNum = a.marca.match(/\d+/); const bNum = b.marca.match(/\d+/); if (aNum && bNum) { return parseInt(aNum[0]) - parseInt(bNum[0]); } return a.marca.localeCompare(b.marca); }); }, [pecasDisponiveis, faseFilter, marcaFilter]); const handleAdicionarPeca = async () => { if (adicionarTodas) { // Adicionar todas as peças filtradas com suas quantidades disponíveis for (const peca of pecasFiltradas) { try { const { error } = await supabase .from('itens_romaneio_pecas') .insert({ romaneio_id: romaneio.id, peca_id: peca.id, quantidade_expedida: peca.quantidade_disponivel, peso_unitario: peca.peso_unitario, peso_total: peca.quantidade_disponivel * peca.peso_unitario, marca: peca.marca, descricao: peca.descricao, fase: peca.etapa_fase }); if (error) throw error; } catch (error) { console.error('Erro ao adicionar peça:', error); toast.error(`Erro ao adicionar peça ${peca.marca}`); } } toast.success('Todas as peças foram adicionadas ao romaneio'); } else { // Adicionar peça individual if (!pecaDisponivel || !quantidadePeca) { toast.error('Selecione uma peça e informe a quantidade'); return; } const pecaSelecionada = pecasDisponiveis.find(p => p.id === pecaDisponivel); if (!pecaSelecionada) { toast.error('Peça não encontrada'); return; } try { const quantidade = parseInt(quantidadePeca); const { error } = await supabase .from('itens_romaneio_pecas') .insert({ romaneio_id: romaneio.id, peca_id: pecaDisponivel, quantidade_expedida: quantidade, peso_unitario: pecaSelecionada.peso_unitario, peso_total: quantidade * pecaSelecionada.peso_unitario, marca: pecaSelecionada.marca, descricao: pecaSelecionada.descricao, fase: pecaSelecionada.etapa_fase }); if (error) throw error; toast.success('Peça adicionada ao romaneio'); } catch (error) { console.error('Erro ao adicionar peça:', error); toast.error('Erro ao adicionar peça ao romaneio'); } } // Recarregar itens e limpar formulário carregarItensRomaneio(); setPecaDisponivel(''); setQuantidadePeca(''); setAdicionarTodas(false); }; const handleAdicionarInsumo = async () => { if (!nomeInsumo || !quantidadeInsumo || !unidadeInsumo) { toast.error('Preencha todos os campos do insumo'); return; } try { const { error } = await supabase .from('itens_romaneio_insumos') .insert({ romaneio_id: romaneio.id, descricao: nomeInsumo, quantidade_expedida: parseFloat(quantidadeInsumo), unidade: unidadeInsumo, tipo_insumo: 'Manual' }); if (error) throw error; toast.success('Insumo adicionado ao romaneio'); setNomeInsumo(''); setQuantidadeInsumo(''); setUnidadeInsumo(''); carregarItensRomaneio(); } catch (error) { console.error('Erro ao adicionar insumo:', error); toast.error('Erro ao adicionar insumo ao romaneio'); } }; const handleRemoverItemPeca = async (itemId: string) => { try { const { error } = await supabase .from('itens_romaneio_pecas') .delete() .eq('id', itemId); if (error) throw error; toast.success('Item removido do romaneio'); carregarItensRomaneio(); } catch (error) { console.error('Erro ao remover item:', error); toast.error('Erro ao remover item do romaneio'); } }; const handleRemoverItemInsumo = async (itemId: string) => { try { const { error } = await supabase .from('itens_romaneio_insumos') .delete() .eq('id', itemId); if (error) throw error; toast.success('Insumo removido do romaneio'); carregarItensRomaneio(); } catch (error) { console.error('Erro ao remover insumo:', error); toast.error('Erro ao remover insumo do romaneio'); } }; const getPrioridadeColor = (prioridade: string) => { switch (prioridade) { case 'P1': return 'bg-red-100 text-red-800'; case 'P2': return 'bg-orange-100 text-orange-800'; case 'P3': return 'bg-blue-100 text-blue-800'; default: return 'bg-gray-100 text-gray-800'; } }; const qtdTotalPecas = itensPeca.reduce((total, item) => total + item.quantidade, 0); const pesoTotalPecas = itensPeca.reduce((total, item) => total + item.peso_total, 0); return ( <> Itens do Romaneio {romaneio.numero_romaneio} - OF: {romaneio.of_number}
Peças Insumos {/* Seção Adicionar Peça */}

Adicionar Peça

{/* Filtro de Processo */}
{/* Filtros dinâmicos */}
setMarcaFilter(e.target.value)} placeholder="Digite a marca da peça..." className={isMobile ? 'h-10' : 'h-11'} />
{/* Opção para adicionar todas as peças */}
setAdicionarTodas(checked as boolean)} className="mt-1 shrink-0" />
{!adicionarTodas && ( <> {/* Seletor de peça disponível */}
setQuantidadePeca(e.target.value)} placeholder="Quantidade" className={isMobile ? 'h-10' : 'h-11'} />
)}
{/* Seção de resumo das peças no romaneio */}

Peças no Romaneio

Qtd Total: {qtdTotalPecas} Peso Total: {pesoTotalPecas.toFixed(2)} kg
{/* Seção Adicionar Insumo */}

Adicionar Insumo

setNomeInsumo(e.target.value)} placeholder="Nome do insumo" className={isMobile ? 'h-10' : 'h-11'} />
setQuantidadeInsumo(e.target.value)} placeholder="Quantidade" className={isMobile ? 'h-10' : 'h-11'} />
setUnidadeInsumo(e.target.value)} placeholder="Ex: kg, m, unid" className={isMobile ? 'h-10' : 'h-11'} />
{/* Lista de insumos no romaneio */}

Insumos no Romaneio

{loadingItens ? (
Carregando...
) : itensInsumo.length === 0 ? (
Nenhum insumo adicionado
) : (
Nome
{!isMobile &&
Quantidade
} {!isMobile &&
Unidade
}
{isMobile ? 'Qtd/Unid/Ações' : 'Ações'}
{itensInsumo.map((item) => (
{item.nome}
{isMobile ? (
{item.quantidade} {item.unidade}
) : ( <>
{item.quantidade}
{item.unidade}
)}
))}
)}
{/* Modal expandido para peças */} setShowExpandedModal(false)} romaneio={romaneio} onRefresh={carregarItensRomaneio} /> ); };