diff --git a/src/components/apontamento/historico/ApontamentosListItem.tsx b/src/components/apontamento/historico/ApontamentosListItem.tsx index d44ec85..263ac37 100644 --- a/src/components/apontamento/historico/ApontamentosListItem.tsx +++ b/src/components/apontamento/historico/ApontamentosListItem.tsx @@ -45,16 +45,30 @@ export const ApontamentosListItem: React.FC = ({ )}
-
+
{getMarcaItem(apontamento)} {apontamento.of_number || 'N/A'} + {apontamento.is_forcado && ( + + ⚡ FORÇADO {apontamento.status_confirmacao === 'pendente_confirmacao' ? '(Pendente)' : '(Confirmado)'} + + )}
-
- {apontamento.processo?.nome || 'N/A'} • {formatDate(apontamento.data_apontamento)} +
+ {apontamento.processo?.nome || 'N/A'} • {formatDate(apontamento.data_apontamento)} + {(apontamento.usuario_nome || apontamento.forcado_por_user_nome) && ( + + • Por: {apontamento.forcado_por_user_nome || apontamento.usuario_nome} + + )}
diff --git a/src/hooks/useApontamentosProducao.tsx b/src/hooks/useApontamentosProducao.tsx index 9f1de0c..9ebdff4 100644 --- a/src/hooks/useApontamentosProducao.tsx +++ b/src/hooks/useApontamentosProducao.tsx @@ -47,6 +47,15 @@ export interface ApontamentoProducao { observacoes?: string; created_at: string; created_by?: string; + usuario_nome?: string; + is_forcado?: boolean; + status_confirmacao?: 'confirmado' | 'pendente_confirmacao' | string; + forcado_por_user_nome?: string; + forcado_por_user_id?: string; + forcado_para_processo_id?: string; + data_confirmacao?: string; + confirmado_por_user_nome?: string; + confirmado_por_user_id?: string; peca?: { marca: string; descricao: string; diff --git a/src/index.css b/src/index.css index a3e3114..8180bf5 100644 --- a/src/index.css +++ b/src/index.css @@ -211,4 +211,23 @@ 50% { opacity: 0.15; } +} + +@keyframes pulse-red-fast { + 0%, 100% { + border-color: rgba(239, 68, 68, 1); + background-color: rgba(239, 68, 68, 0.18); + box-shadow: 0 0 16px rgba(239, 68, 68, 0.65); + transform: scale(1); + } + 50% { + border-color: rgba(239, 68, 68, 0.35); + background-color: rgba(239, 68, 68, 0.04); + box-shadow: 0 0 4px rgba(239, 68, 68, 0.15); + transform: scale(0.99); + } +} + +.animate-pulse-red-fast { + animation: pulse-red-fast 0.5s ease-in-out infinite !important; } \ No newline at end of file diff --git a/src/pages/smart/components/SmartForcarApontamentoModal.tsx b/src/pages/smart/components/SmartForcarApontamentoModal.tsx new file mode 100644 index 0000000..d330aa7 --- /dev/null +++ b/src/pages/smart/components/SmartForcarApontamentoModal.tsx @@ -0,0 +1,442 @@ +import React, { useState, useMemo } from 'react'; +import { supabase } from '@/integrations/supabase/client'; +import { smartAudio } from '@/utils/smartAudio'; +import { useAuth } from '@/hooks/useAuth'; +import { ProcessoFabricacao } from '@/hooks/useProcessosFabricacao'; +import { OFAtiva } from '@/hooks/useOFsAtivas'; +import { Button } from '@/components/ui/button'; +import { toast } from 'sonner'; +import { + AlertTriangle, + X, + Zap, + Check, + Plus, + Minus, + ArrowRight, + Sparkles, + RefreshCw, + Scissors, + Ruler, + Puzzle, + Paintbrush, + ShieldAlert +} from 'lucide-react'; + +interface PecaData { + id: string; + marca: string; + descricao: string; + etapa_fase: string; + quantidade: number; + peso_unitario: number; + perfil_principal?: string; + tem_componentes?: boolean | null; +} + +interface SmartForcarApontamentoModalProps { + isOpen: boolean; + onClose: () => void; + obra: OFAtiva; + faseSelecionada: string; + processoAtual: ProcessoFabricacao; + todosProcessos: ProcessoFabricacao[]; + pecas: PecaData[]; + mapaProducao: Map; + onSucesso: (pecasCount: number, pesoKg: number) => void; +} + +export const SmartForcarApontamentoModal: React.FC = ({ + isOpen, + onClose, + obra, + faseSelecionada, + processoAtual, + todosProcessos, + pecas, + mapaProducao, + onSucesso, +}) => { + const { user } = useAuth(); + const [pecaSelecionada, setPecaSelecionada] = useState(null); + const [qtdForcar, setQtdForcar] = useState(1); + const [salvando, setSalvando] = useState(false); + + const getIconeProcesso = (nome: string) => { + const n = (nome || '').toLowerCase(); + if (n.includes('corte')) return ; + if (n.includes('dobra') || n.includes('fura')) return ; + if (n.includes('montag')) return ; + if (n.includes('solda')) return ; + if (n.includes('pintura')) return ; + return ; + }; + + // Encontra o processo anterior para uma determinada peça considerando regra S/M + const getProcessoAnteriorPeca = (peca: PecaData): ProcessoFabricacao | null => { + const procsOrdenados = [...todosProcessos].sort((a, b) => a.ordem - b.ordem); + const indexAtual = procsOrdenados.findIndex((p) => p.id === processoAtual.id); + if (indexAtual <= 0) return null; + + const ehSemMontagem = peca.tem_componentes === false; + + for (let i = indexAtual - 1; i >= 0; i--) { + const proc = procsOrdenados[i]; + const nomeP = (proc.nome || '').toLowerCase(); + // Peças sem montagem (S/M) pulam solda + if (ehSemMontagem && nomeP.includes('solda')) { + continue; + } + return proc; + } + return null; + }; + + // Peças da fase que ainda NÃO foram totalmente apontadas no processo anterior + const pecasPendentesProcessoAnterior = useMemo(() => { + return pecas + .filter((p) => { + if (!faseSelecionada || faseSelecionada === 'Geral') return true; + return (p.etapa_fase || 'Geral').trim() === faseSelecionada; + }) + .map((p) => { + const procAnterior = getProcessoAnteriorPeca(p); + if (!procAnterior) { + return { ...p, procAnterior: null, saldoPendenteAnterior: 0, jaApontadoAnterior: 0 }; + } + const keyAnt = `${p.id}_${procAnterior.id}`; + const jaApontadoAnterior = mapaProducao.get(keyAnt) || 0; + const saldoPendenteAnterior = Math.max(0, p.quantidade - jaApontadoAnterior); + + return { + ...p, + procAnterior, + saldoPendenteAnterior, + jaApontadoAnterior, + }; + }) + .filter((p) => p.procAnterior !== null && p.saldoPendenteAnterior > 0) + .sort((a, b) => a.marca.localeCompare(b.marca, undefined, { numeric: true, sensitivity: 'base' })); + }, [pecas, faseSelecionada, processoAtual, todosProcessos, mapaProducao]); + + const handleSelecionarPeca = (peca: any) => { + smartAudio.playClick(); + setPecaSelecionada(peca); + setQtdForcar(peca.saldoPendenteAnterior > 0 ? (peca.saldoPendenteAnterior >= 1 ? 1 : peca.saldoPendenteAnterior) : 1); + }; + + const handleConfirmarForcamento = async () => { + if (!pecaSelecionada || !user) return; + + const procAnterior = getProcessoAnteriorPeca(pecaSelecionada); + if (!procAnterior) { + toast.error('Processo anterior não identificado para esta peça'); + return; + } + + if (qtdForcar <= 0) { + smartAudio.playAlert(); + toast.error('Informe uma quantidade válida'); + return; + } + + try { + setSalvando(true); + const hoje = new Date().toISOString().split('T')[0]; + const nomeUsuario = user.name || user.username || user.email?.split('@')[0] || 'Operador Chão de Fábrica'; + + // 1. Inserir apontamento no Processo Anterior com flag de FORÇADO e PENDENTE DE CONFIRMAÇÃO + const payloadAnterior = { + of_number: obra.of_number, + peca_id: pecaSelecionada.id, + tipo_apontamento: 'peca' as const, + processo_id: procAnterior.id, + quantidade_produzida: qtdForcar, + data_apontamento: hoje, + created_by: user.id, + usuario_nome: nomeUsuario, + is_forcado: true, + status_confirmacao: 'pendente_confirmacao', + forcado_por_user_nome: nomeUsuario, + forcado_por_user_id: user.id, + forcado_para_processo_id: processoAtual.id, + observacoes: `Forçado por ${nomeUsuario} no posto ${processoAtual.nome}`, + }; + + // 2. Inserir apontamento no Processo Atual (pois o operador já produziu/está com as peças) + const payloadAtual = { + of_number: obra.of_number, + peca_id: pecaSelecionada.id, + tipo_apontamento: 'peca' as const, + processo_id: processoAtual.id, + quantidade_produzida: qtdForcar, + data_apontamento: hoje, + created_by: user.id, + usuario_nome: nomeUsuario, + is_forcado: false, + status_confirmacao: 'confirmado', + observacoes: `Apontamento regular decorrente de força de ${procAnterior.nome}`, + }; + + const { error: erroAnt } = await supabase.from('apontamentos_producao').insert(payloadAnterior); + if (erroAnt) throw erroAnt; + + const { error: erroAtual } = await supabase.from('apontamentos_producao').insert(payloadAtual); + if (erroAtual) throw erroAtual; + + // Sucesso! + smartAudio.playSuccess(); + toast.success( + `⚡ Apontamento forçado com sucesso! ${qtdForcar}x ${pecaSelecionada.marca} liberadas de ${procAnterior.nome} e apontadas em ${processoAtual.nome}.` + ); + + const pesoTotal = qtdForcar * (pecaSelecionada.peso_unitario || 0); + onSucesso(qtdForcar, pesoTotal); + onClose(); + } catch (e: any) { + smartAudio.playAlert(); + console.error('Erro ao forçar apontamento:', e); + toast.error('Falha ao forçar apontamento: ' + (e?.message || 'Erro de conexão')); + } finally { + setSalvando(false); + } + }; + + if (!isOpen) return null; + + return ( +
+
e.stopPropagation()} + > + {/* Cabeçalho */} +
+
+
+ +
+
+
+

+ Forçar Apontamento +

+ + {processoAtual.nome} + +
+

+ Aponte peças esquecidas no processo anterior para liberar seu posto +

+
+
+ + +
+ + {/* Aviso de Destaque */} +
+ + + Ao forçar o apontamento, a peça será automaticamente registrada no processo anterior (com pendência de confirmação) e apontada no seu processo atual. + +
+ + {/* Conteúdo Principal */} +
+ {pecasPendentesProcessoAnterior.length === 0 ? ( +
+ +

+ Tudo em ordem! +

+

+ Não há peças da fase {faseSelecionada} pendentes no processo anterior. Todas as peças disponíveis já foram apontadas! +

+
+ ) : !pecaSelecionada ? ( +
+ + Selecione a peça que deseja forçar: + + {pecasPendentesProcessoAnterior.map((item) => ( + + ))} +
+ ) : ( +
+ {/* Card da Peça Selecionada */} +
+
+ + {pecaSelecionada.marca} + + +
+
+ {pecaSelecionada.descricao || pecaSelecionada.perfil_principal} +
+
+ Total da Peça: {pecaSelecionada.quantidade} un + + Pendente no anterior: {(pecaSelecionada as any).saldoPendenteAnterior} un + +
+
+ + {/* Seletor de Quantidade */} +
+ + Quantas unidades você está forçando agora? + + +
+ + +
+ + {qtdForcar} + +
+ + +
+ +
+ +
+
+ + {/* Botão de Confirmação */} + +
+ )} +
+ + {/* Rodapé */} +
+ +
+
+
+ ); +}; diff --git a/src/pages/smart/components/SmartHeader.tsx b/src/pages/smart/components/SmartHeader.tsx index 9bac076..940db22 100644 --- a/src/pages/smart/components/SmartHeader.tsx +++ b/src/pages/smart/components/SmartHeader.tsx @@ -25,7 +25,7 @@ export const SmartHeader: React.FC = ({ const { theme, setTheme } = useTheme(); const [soundOn, setSoundOn] = useState(() => smartAudio.isSoundEnabled()); const [isNotificationsOpen, setIsNotificationsOpen] = useState(false); - const { unreadCount, hasNewAlert, clearAlert } = useSmartNotificationsAlert(); + const { unreadCount, hasNewAlert, hasPendingForced, clearAlert, refetch } = useSmartNotificationsAlert(); // Detecta se está efetivamente em modo escuro const isDark = @@ -140,20 +140,27 @@ export const SmartHeader: React.FC = ({ setIsNotificationsOpen(true); }} className={`relative h-10 w-8 sm:w-9 rounded-xl flex items-center justify-center border transition-all active:scale-90 ${ - hasNewAlert + hasPendingForced + ? 'animate-pulse-red-fast bg-red-100 border-red-500 text-red-700 dark:bg-red-950/80 dark:border-red-500 dark:text-red-400 shadow-md shadow-red-500/30' + : hasNewAlert ? 'bg-amber-100 border-amber-300 text-amber-700 dark:bg-amber-950/70 dark:border-amber-600/50 dark:text-amber-400' : 'bg-slate-100 border-slate-200 text-slate-600 dark:bg-slate-800/80 dark:border-slate-700 dark:text-slate-300 hover:bg-slate-200' }`} - title="Notificações de Apontamentos de Produção" + title={hasPendingForced ? '⚠️ Existem apontamentos forçados pendentes de confirmação!' : 'Notificações de Apontamentos de Produção'} > - - {hasNewAlert && ( + + {hasPendingForced ? ( + + + + + ) : hasNewAlert ? ( - )} - {unreadCount > 0 && !hasNewAlert && ( + ) : null} + {unreadCount > 0 && !hasNewAlert && !hasPendingForced && ( {unreadCount > 99 ? '99+' : unreadCount} @@ -202,6 +209,7 @@ export const SmartHeader: React.FC = ({ setIsNotificationsOpen(false)} + onApontamentoConfirmado={refetch} /> ); diff --git a/src/pages/smart/components/SmartNotificationsModal.tsx b/src/pages/smart/components/SmartNotificationsModal.tsx index ea920f9..5fb449b 100644 --- a/src/pages/smart/components/SmartNotificationsModal.tsx +++ b/src/pages/smart/components/SmartNotificationsModal.tsx @@ -1,6 +1,8 @@ import React, { useEffect, useState, useCallback } from 'react'; import { supabase } from '@/integrations/supabase/client'; import { smartAudio } from '@/utils/smartAudio'; +import { useAuth } from '@/hooks/useAuth'; +import { toast } from 'sonner'; import { Bell, X, @@ -14,7 +16,9 @@ import { Paintbrush, Truck, Scissors, - Box + Box, + AlertTriangle, + CheckCheck } from 'lucide-react'; export interface ApontamentoNotificacao { @@ -29,21 +33,28 @@ export interface ApontamentoNotificacao { processo_nome: string; processo_cor: string; usuario_nome: string; + is_forcado?: boolean; + status_confirmacao?: 'confirmado' | 'pendente_confirmacao' | string; + forcado_por_user_nome?: string; } interface SmartNotificationsModalProps { isOpen: boolean; onClose: () => void; ofFiltrar?: string; + onApontamentoConfirmado?: () => void; } export const SmartNotificationsModal: React.FC = ({ isOpen, onClose, ofFiltrar, + onApontamentoConfirmado, }) => { + const { user } = useAuth(); const [apontamentos, setApontamentos] = useState([]); const [carregando, setCarregando] = useState(false); + const [confirmandoId, setConfirmandoId] = useState(null); const formatarTempo = (dataIso?: string) => { if (!dataIso) return 'Recente'; @@ -76,16 +87,21 @@ export const SmartNotificationsModal: React.FC = ( const carregarNotificacoes = useCallback(async () => { setCarregando(true); try { - // 1. Buscar os últimos 30 apontamentos + // Filtrar APENAS apontamentos de HOJE e do DIA ANTERIOR (ONTEM) + const dataOntem = new Date(Date.now() - 86400000); + const dataOntemIso = dataOntem.toISOString().split('T')[0]; + let query = supabase .from('apontamentos_producao' as any) .select(` id, of_number, quantidade_produzida, data_apontamento, created_at, created_by, + is_forcado, status_confirmacao, forcado_por_user_nome, usuario_nome, peca:pecas!apontamentos_producao_peca_id_fkey(marca, etapa_fase, perfil_principal, descricao), processo:processos_fabricacao!apontamentos_producao_processo_id_fkey(nome, cor, ordem) `) + .gte('data_apontamento', dataOntemIso) .order('created_at', { ascending: false }) - .limit(30); + .limit(100); if (ofFiltrar) { query = query.eq('of_number', ofFiltrar); @@ -94,7 +110,7 @@ export const SmartNotificationsModal: React.FC = ( const { data: apontamentosData, error } = await query; if (error) throw error; - // 2. Buscar nomes dos usuários dos apontamentos + // Buscar nomes dos usuários dos apontamentos caso não estejam gravados diretamente const userIds = Array.from(new Set((apontamentosData || []).map((ap: any) => ap.created_by).filter(Boolean))); const profilesMap = new Map(); @@ -116,11 +132,11 @@ export const SmartNotificationsModal: React.FC = ( } } - // 3. Montar lista tratada + // Montar lista tratada const lista: ApontamentoNotificacao[] = (apontamentosData || []).map((ap: any) => { const peca = ap.peca || {}; const processo = ap.processo || {}; - const userName = (ap.created_by && profilesMap.get(ap.created_by)) || 'Chão de Fábrica'; + const userName = ap.usuario_nome || (ap.created_by && profilesMap.get(ap.created_by)) || 'Chão de Fábrica'; return { id: String(ap.id), @@ -134,6 +150,9 @@ export const SmartNotificationsModal: React.FC = ( processo_nome: processo.nome || 'Produção', processo_cor: processo.cor || '#10b981', usuario_nome: userName, + is_forcado: Boolean(ap.is_forcado), + status_confirmacao: ap.status_confirmacao || 'confirmado', + forcado_por_user_nome: ap.forcado_por_user_nome, }; }); @@ -145,6 +164,45 @@ export const SmartNotificationsModal: React.FC = ( } }, [ofFiltrar]); + const handleConfirmarBaixaForcada = async (item: ApontamentoNotificacao) => { + try { + smartAudio.playClick(); + setConfirmandoId(item.id); + + const nomeOperador = user?.name || user?.email?.split('@')[0] || 'Operador'; + + const { error } = await supabase + .from('apontamentos_producao' as any) + .update({ + status_confirmacao: 'confirmado', + data_confirmacao: new Date().toISOString(), + confirmado_por_user_nome: nomeOperador, + confirmado_por_user_id: user?.id, + }) + .eq('id', item.id); + + if (error) throw error; + + smartAudio.playSuccess(); + toast.success(`✅ Baixa confirmada: ${item.marca} (${item.processo_nome})`); + + // Atualiza lista local + setApontamentos((prev) => + prev.map((ap) => (ap.id === item.id ? { ...ap, status_confirmacao: 'confirmado' } : ap)) + ); + + if (onApontamentoConfirmado) { + onApontamentoConfirmado(); + } + } catch (err: any) { + smartAudio.playAlert(); + console.error('Erro ao confirmar baixa:', err); + toast.error('Erro ao confirmar baixa: ' + (err?.message || 'Falha de conexão')); + } finally { + setConfirmandoId(null); + } + }; + useEffect(() => { if (isOpen) { carregarNotificacoes(); @@ -153,6 +211,13 @@ export const SmartNotificationsModal: React.FC = ( if (!isOpen) return null; + const pendentesConfirmacao = apontamentos.filter( + (ap) => ap.is_forcado && ap.status_confirmacao === 'pendente_confirmacao' + ); + const outrosApontamentos = apontamentos.filter( + (ap) => !(ap.is_forcado && ap.status_confirmacao === 'pendente_confirmacao') + ); + return (
= ( )}

- Histórico em tempo real das peças produzidas + Mostrando apontamentos de hoje e ontem

@@ -210,22 +275,94 @@ export const SmartNotificationsModal: React.FC = ( - {/* Lista de Notificações de Apontamentos */} -
+ {/* Conteúdo com Apontamentos */} +
+ {/* Seção 1: Apontamentos Forçados Pendentes de Confirmação */} + {pendentesConfirmacao.length > 0 && ( +
+
+
+ + Apontamentos Forçados Pendentes ({pendentesConfirmacao.length}) +
+ + Ação Necessária + +
+

+ Peças foram apontadas no processo posterior e aguardam sua confirmação de baixa: +

+ +
+ {pendentesConfirmacao.map((item) => ( +
+
+
+ + {item.marca} + + + OF {item.of_number} • F{item.fase} + + + {item.processo_nome} + +
+ +
+ Qtd: {item.quantidade} un + {item.forcado_por_user_nome && ( + + Forçado por: {item.forcado_por_user_nome} + + )} + {formatarTempo(item.created_at)} +
+
+ + +
+ ))} +
+
+ )} + + {/* Seção 2: Histórico de Apontamentos Recentes (Hoje e Ontem) */} {carregando && apontamentos.length === 0 ? (
Buscando novos apontamentos...
- ) : apontamentos.length === 0 ? ( + ) : outrosApontamentos.length === 0 && pendentesConfirmacao.length === 0 ? (

- Nenhum apontamento registrado recentemente{ofFiltrar ? ` para a OF ${ofFiltrar}` : ''}. + Nenhum apontamento registrado hoje ou ontem{ofFiltrar ? ` para a OF ${ofFiltrar}` : ''}.

) : ( - apontamentos.map((item) => ( + outrosApontamentos.map((item) => (
= ( > {item.processo_nome} + {item.is_forcado && ( + + ⚡ Forçado (Confirmado) + + )}
{item.perfil && ( @@ -291,7 +433,7 @@ export const SmartNotificationsModal: React.FC = ( {/* Rodapé */}
- {apontamentos.length} apontamentos listados + {apontamentos.length} apontamentos listados (hoje e ontem)
- - - )) + + + ); + }) ) : ( - processos.map((proc) => ( -
- - - )) + + + ); + }) )}
@@ -479,7 +595,6 @@ export const SmartProducaoFlow: React.FC = ({ if (etapaAtual === 'fase') { return (
- {/* Breadcrumb de Processo */} {/* Breadcrumb de Processo */}
@@ -512,19 +627,35 @@ export const SmartProducaoFlow: React.FC = ({
{fasesDisponiveis.map((fase) => { const countFase = pecas.filter((p) => (p.etapa_fase || 'Geral').trim() === fase).length; + const pendentesFaseCount = contagemPendentesPorFase.get(fase) || 0; + const hasPendFase = pendentesFaseCount > 0; + return (
- - {pecasComSaldo.length} itens - +
+ {!isPrimeiroProcesso && processoSelecionado && ( + + )} + + + {pecasComSaldo.length} itens + +
{/* Lista de Peças */} @@ -605,19 +755,24 @@ export const SmartProducaoFlow: React.FC = ({
) : ( pecasComSaldo.map((item) => { + const pendenciasItem = pecasPendentesMap.get(item.id) || []; + const temPendencia = pendenciasItem.length > 0; const concluida = item.saldo <= 0; + return (
-
+
{item.marca} @@ -700,6 +855,27 @@ export const SmartProducaoFlow: React.FC = ({ />
+ {/* ALERTA VISUAL: BAIXA FORÇADA PENDENTE DE CONFIRMAÇÃO */} + {temPendencia && ( +
+
+ + + Baixa forçada ({pendenciasItem.reduce((acc, p) => acc + (p.quantidade_produzida || 0), 0)} un) + {pendenciasItem[0]?.forcado_por_user_nome && ` • Por: ${pendenciasItem[0].forcado_por_user_nome}`} + +
+ +
+ )} + {/* Botões de Ação no Card */}
+ + {/* Modal de Forçar Apontamento */} + {processoSelecionado && ( + setIsForcarModalOpen(false)} + obra={obra} + faseSelecionada={faseSelecionada} + processoAtual={processoSelecionado} + todosProcessos={processos} + pecas={pecas} + mapaProducao={mapaProducao} + onSucesso={(qtd, peso) => { + carregarDadosOF(); + onApontamentoRealizado(qtd, peso); + }} + /> + )}
); } @@ -785,7 +979,6 @@ export const SmartProducaoFlow: React.FC = ({ const handleDigitoTeclado = (digito: number) => { smartAudio.playClick(); setQtdApontar((prev) => { - // Se estiver em 0 ou for primeira digitação const strAtual = prev <= 0 ? '' : prev.toString(); const novaStr = strAtual + digito.toString(); const novoValor = parseInt(novaStr, 10) || 0; @@ -845,7 +1038,7 @@ export const SmartProducaoFlow: React.FC = ({ {pecaSelecionada.tem_componentes === false && ( S/M @@ -883,7 +1076,7 @@ export const SmartProducaoFlow: React.FC = ({ - {/* Input Numérico Editável Direto (Toque para digitar ou use o teclado da tela) */} + {/* Input Numérico Editável Direto */}