import { Modal, Tag, Skeleton, Typography, Row, Col, Statistic, Divider } from 'antd'; import { BarcodeOutlined, InboxOutlined, PercentageOutlined, TagsOutlined, } from '@ant-design/icons'; import type { PautaPreco } from '@sar/api-interface'; import { useProdutoDetail } from '../../lib/queries/catalog'; import { useCondicoesComerciais, type CondicaoComercial } from '../../lib/condicoes-comerciais'; import { CondicaoTag } from '../../components/CondicaoTag'; const { Text, Title } = Typography; function fmtPrice(v: string | null | undefined): string { const n = Number(v ?? 0); return n > 0 ? n.toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' }) : '—'; } function fmtNum(v: string | null | undefined, decimals = 3): string { const n = Number(v ?? 0); return n > 0 ? n.toLocaleString('pt-BR', { minimumFractionDigits: decimals, maximumFractionDigits: decimals, }) : '—'; } // ─── Bloco de seção ─────────────────────────────────────────────────────────── function Section({ icon, title, children, }: { icon: React.ReactNode; title: string; children: React.ReactNode; }) { return (
{icon} {title}
{children}
); } // ─── Campo label/valor ──────────────────────────────────────────────────────── function Field({ label, value, span = 1, }: { label: string; value: React.ReactNode; span?: number; }) { return (
1 ? 'span 2' : undefined, marginBottom: 12 }}> {label} {value ?? '—'}
); } // ─── Card de preço ──────────────────────────────────────────────────────────── function PrecoCard({ label, value, highlight, }: { label: string; value: string; highlight?: boolean; }) { const n = Number(value ?? 0); const empty = n <= 0; return (
{label} {fmtPrice(value)}
); } // ─── Lista de pautas ────────────────────────────────────────────────────────── function PautaPrecoList({ items }: { items: PautaPreco[] }) { if (items.length === 0) { return (
Produto não está em nenhuma pauta ativa.
); } return (
{items.map((item) => (
Pauta {item.codigo} {item.descricao}
{fmtPrice(item.preco)}
))}
); } // ─── Condições comerciais vigentes ──────────────────────────────────────────── function fmtData(iso: string): string { const [y, m, d] = iso.split('-'); return `${d}/${m}/${y}`; } function CondicoesList({ conds }: { conds: CondicaoComercial[] }) { return (
{conds.map((c, i) => (
{c.tipo === 'promocao' ? 'Promoção' : 'Condição especial'} · válida até{' '} {fmtData(c.dataFim)} {c.descricao}
{c.descPct.toLocaleString('pt-BR')}% desc.
))}
); } // ─── Modal principal ────────────────────────────────────────────────────────── interface Props { idErp: number | null; onClose: () => void; } export function ProductDetailDrawer({ idErp, onClose }: Props) { const { data, isLoading } = useProdutoDetail(idErp ?? undefined); const condicoesDe = useCondicoesComerciais(); const conds = data ? condicoesDe(data) : []; return ( {isLoading || !data ? (
) : ( <> {/* ── Cabeçalho ──────────────────────────────────────────── */}
Código {data.codigo.trim()} {data.referencia ? ` · Ref. ${data.referencia.trim()}` : ''} {data.descricao.trim()} {data.descricaoDetalhada && ( {data.descricaoDetalhada.trim()} )}
{data.marca && {data.marca.trim()}} {data.unidade && {data.unidade}} {data.ativo ? 'Ativo' : 'Inativo'}
{/* ── Corpo ──────────────────────────────────────────────── */}
{/* Coluna esquerda */} {/* Condições comerciais vigentes */} {conds.length > 0 && (
} title="Condições Comerciais">
)} {/* Classificação */}
} title="Classificação">
{/* Preços Base */}
} title="Preços Base">
Alíq. IPI {data.aliqIpi ? `${Number(data.aliqIpi).toLocaleString('pt-BR')}%` : '—'}
{/* Estoque & Logística */}
} title="Estoque & Logística"> 0 ? '#1F2937' : '#EF4444', }} formatter={(v) => (v != null ? Number(v).toLocaleString('pt-BR') : '—')} /> (v != null ? String(v) : '—')} /> fmtNum(String(v))} /> fmtNum(String(v), 0)} />
{/* Divisor vertical */} {/* Coluna direita — Pautas */}
} title={`Preços por Pauta (${data.pautaPrecos.length})`} >
)}
); }