import { useState } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; import { Pencil, XCircle, AlertTriangle, Info, DollarSign } from 'lucide-react'; import { PageContainer, PageHeader } from '../../components/layout'; import { Button, Badge } from '../../components/ui'; import { Tabs, type TabItem } from '../../components/ui/Tabs'; import { useToast } from '../../components/ui/Toast'; import { useBreadcrumbs } from '../../hooks/useBreadcrumbs'; import { useReadOnly } from '../../hooks/useReadOnly'; import { useFieldVisibility } from '../../hooks/useFieldVisibility'; import { useWorkOrder, useWorkOrderSummary, useCancelWorkOrder } from '../../hooks/useWorkOrders'; import { getWorkOrderStatusConfig } from '../../constants/work-order-status'; import { OrdemServicoSummaryTab } from './components/OrdemServicoSummaryTab'; import { OrdemServicoDeliverablesTab } from './components/OrdemServicoDeliverablesTab'; import { OrdemServicoStatusHistoryTab } from './components/OrdemServicoStatusHistoryTab'; import { CancelWorkOrderModal } from './components/CancelWorkOrderModal'; function formatNumber(value: number) { return new Intl.NumberFormat('pt-BR', { maximumFractionDigits: 2 }).format(value); } function formatCurrency(value: number) { return new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(value); } function formatPercent(value: number) { return `${value.toFixed(1)}%`; } export function OrdemServicoDetailPage() { const { id } = useParams<{ id: string }>(); const navigate = useNavigate(); const { showToast } = useToast(); const { isReadOnly } = useReadOnly(); const isVisible = useFieldVisibility(); const [cancelOpen, setCancelOpen] = useState(false); const { data: workOrder, isLoading, isError } = useWorkOrder(id ?? ''); const { data: summary } = useWorkOrderSummary(id ?? ''); const cancelMutation = useCancelWorkOrder(); const breadcrumbs = useBreadcrumbs({ ':name': workOrder?.code ?? '' }); if (isLoading) { return (
); } if (isError || !workOrder) { return (

Ordem de serviço não encontrada

); } const statusConfig = getWorkOrderStatusConfig(workOrder.status); const isEditable = workOrder.status === 'RASCUNHO' || workOrder.status === 'EMITIDA'; const canCancel = workOrder.status === 'RASCUNHO' && (workOrder._count.deliverables ?? 0) === 0; const tabs: TabItem[] = [ { id: 'summary', label: 'Resumo' }, { id: 'deliverables', label: 'Entregáveis' }, { id: 'history', label: 'Histórico de status' }, ]; async function handleCancel(observation: string) { if (!id) return; try { await cancelMutation.mutateAsync({ id, observation }); showToast('Ordem de serviço cancelada', 'success'); setCancelOpen(false); } catch { showToast('Erro ao cancelar ordem de serviço', 'error'); } } return ( {isEditable && ( )} {canCancel && ( )} ) : undefined } />
{statusConfig.label} Contrato: {workOrder.contract.name} Item: {workOrder.contractItem.code} — {workOrder.contractItem.name}
{workOrder.description &&

{workOrder.description}

} {summary?.lowBalanceAlert && (
Saldo baixo: menos de 20% disponível ({formatNumber(Number(summary.ustAvailable))} de{' '} {formatNumber(Number(summary.ustReserved))} UST).
)} {/* Card de Valoração — visível apenas para perfis com acesso financeiro */} {isVisible('totalValue') && (

Valor da Ordem de Serviço

{workOrder.totalValue != null ? formatCurrency(Number(workOrder.totalValue)) : 'Não calculado'}

{workOrder.contractItem.itemType === 'SAAS_LICENSE' && workOrder.contractItem.ustValue != null && (

{formatNumber(Number(workOrder.reservedUst))} licenças × R${' '} {Number(workOrder.contractItem.ustValue).toLocaleString('pt-BR', { minimumFractionDigits: 2, })} /unidade — faturamento anual

)} {workOrder.contractItem.itemType === 'UST' && (

Soma dos Entregáveis vinculados ({workOrder._count?.deliverables ?? 0} ativos)

)}
)} {isVisible('reservedUst') && (

{workOrder.contractItem.itemType === 'SAAS_LICENSE' ? 'Licenças reservadas' : 'Pool reservado'}

{formatNumber(Number(workOrder.reservedUst))}{' '} {workOrder.contractItem.itemType === 'SAAS_LICENSE' ? 'licenças' : 'UST'}

Pool consumido

{summary ? formatNumber(Number(summary.ustConsumed)) : '—'} UST

Saldo disponível

{summary ? formatNumber(Number(summary.ustAvailable)) : '—'} UST

% de consumo

{summary ? formatPercent(Number(summary.consumptionPercent)) : '—'}

)} {(activeTabId: string) => (
{activeTabId === 'summary' && } {activeTabId === 'deliverables' && ( )} {activeTabId === 'history' && ( )}
)}
void handleCancel(obs)} onCancel={() => setCancelOpen(false)} />
); }