import { useState } from 'react'; import { Button, Card, Col, Drawer, Dropdown, Empty, Grid, Row, Select, Space, Spin, Table, Tag, Timeline, Typography, } from 'antd'; import type { TableColumnsType } from 'antd'; import type { MenuProps } from 'antd'; import { CheckCircleOutlined, ClockCircleOutlined, CloseCircleOutlined, CopyOutlined, DollarOutlined, EllipsisOutlined, EyeOutlined, FilePdfOutlined, PlusOutlined, ShoppingCartOutlined, } from '@ant-design/icons'; import { Link, useNavigate } from '@tanstack/react-router'; import type { PedidoSummary } from '@sar/api-interface'; import { SITUA_LABEL } from '@sar/api-interface'; import { useOrderList, useOrderDetail } from '../../lib/queries/orders'; const { Title, Text } = Typography; const { useBreakpoint } = Grid; // ─── Helpers ────────────────────────────────────────────────────────────────── function fmt(v: number | string) { return Number(v).toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' }); } function fmtDate(v: string) { return new Date(v).toLocaleDateString('pt-BR'); } function toISO(d: Date) { return d.toISOString().split('T')[0]; } function periodRange(p: string): { from?: string; to?: string } { const today = new Date(); if (p === 'today') return { from: toISO(today), to: toISO(today) }; if (p === '7d') { const d = new Date(today); d.setDate(d.getDate() - 7); return { from: toISO(d), to: toISO(today) }; } if (p === '30d') { const d = new Date(today); d.setDate(d.getDate() - 30); return { from: toISO(d), to: toISO(today) }; } return {}; } // ─── Status ─────────────────────────────────────────────────────────────────── const STATUS: Record = { 1: { label: 'Ag. Aprovação', color: '#d46b08', rowBg: '#fffbe6', tagColor: 'orange' }, 2: { label: 'Aprovado', color: '#389e0d', rowBg: '#f6ffed', tagColor: 'green' }, 3: { label: 'Cancelado', color: '#cf1322', rowBg: '#fff1f0', tagColor: 'red' }, 4: { label: 'Faturado', color: '#1d39c4', rowBg: '#f0f5ff', tagColor: 'geekblue' }, }; // ─── OrderStatusBadge ───────────────────────────────────────────────────────── function OrderStatusBadge({ situa, descr }: { situa: number; descr?: string }) { const cfg = STATUS[situa]; const label = descr ?? cfg?.label ?? SITUA_LABEL[situa] ?? String(situa); return ( {label} ); } // ─── OrdersMetrics ──────────────────────────────────────────────────────────── function OrdersMetrics({ data }: { data: PedidoSummary[] }) { const total = data.reduce((a, o) => a + Number(o.total), 0); const pendentes = data.filter((o) => o.situa === 1).length; const aprovados = data.filter((o) => o.situa === 2).length; const ticket = data.length > 0 ? total / data.length : 0; const metrics = [ { label: 'Total de Pedidos', value: String(data.length), icon: , color: '#003B8E', }, { label: 'Total Vendido', value: fmt(total), icon: , color: '#389e0d' }, { label: 'Ag. Aprovação', value: String(pendentes), icon: , color: '#d46b08', }, { label: 'Aprovados', value: String(aprovados), icon: , color: '#389e0d', }, { label: 'Ticket Médio', value: fmt(ticket), icon: , color: '#1d39c4' }, ]; return ( {metrics.map((m) => ( {m.icon}
{m.label} {m.value}
))}
); } // ─── OrderActionsMenu ───────────────────────────────────────────────────────── function OrderActionsMenu({ order, onView, }: { order: PedidoSummary; onView: (id: string) => void; }) { const navigate = useNavigate(); const canDetail = order.fonte !== 'erp'; const items: MenuProps['items'] = [ canDetail ? { key: 'view', icon: , label: 'Ver detalhes', onClick: () => onView(order.id), } : { key: 'view', icon: , label: 'Ver detalhes', disabled: true }, { key: 'duplicate', icon: , label: Duplicar pedido, onClick: () => void navigate({ to: '/pedidos/novo', search: { clientId: String(order.idCliente) } }), }, { type: 'divider' }, { key: 'pdf', icon: , label: 'Gerar PDF', onClick: () => alert('PDF em breve'), }, { key: 'cancel', icon: , label: 'Cancelar pedido', danger: true, disabled: order.situa === 3, onClick: () => alert('Cancelamento em breve'), }, ]; return ( {data && ( )} } > {isLoading && } {data && ( {/* Status */}
{/* Dados principais */} Pedido {data.numPedSar} Data {fmtDate(data.dtPedido)} Cód. Cliente {data.idCliente} Total {fmt(data.total)} {data.obs && ( Observações {data.obs} )} {/* Itens */} {data.itens?.length > 0 && (
Itens do Pedido ({data.itens.length}) {data.itens.map((item) => (
{item.codProduto} {item.descProduto} {Number(item.qtd)} un × {fmt(Number(item.precoUnitario))} {fmt(Number(item.total))}
))}
Total: {fmt(data.total)}
)} {/* Histórico */} {timelineItems.length > 0 && (
Histórico
)}
)} ); } // ─── MobileOrderCard ────────────────────────────────────────────────────────── function MobileOrderCard({ order, onView, }: { order: PedidoSummary; onView: (id: string) => void; }) { const navigate = useNavigate(); const cfg = STATUS[order.situa]; return (
{order.numPedSar}
Cód. cliente {order.idCliente} · {fmtDate(order.dtPedido)} {fmt(order.total)}
); } // ─── EmptyState ─────────────────────────────────────────────────────────────── function EmptyOrders({ onNew }: { onNew: () => void }) { return ( } imageStyle={{ height: 64 }} description={ Nenhum pedido encontrado Tente alterar os filtros ou crie um novo pedido. } style={{ padding: '48px 0' }} > ); } // ─── OrdersPage ─────────────────────────────────────────────────────────────── export function OrdersPage() { const navigate = useNavigate(); const screens = useBreakpoint(); const isMobile = !screens.md; const [search, setSearch] = useState(''); const [situaFilter, setSituaFilter] = useState(); const [period, setPeriod] = useState(''); const [page, setPage] = useState(1); const [drawerOrderId, setDrawerOrderId] = useState(null); const limit = 20; const { from, to } = period ? periodRange(period) : {}; const { data, isLoading } = useOrderList({ numPedSar: search || undefined, situa: situaFilter, from, to, page, limit, }); const rows = data?.data ?? []; const total = data?.total ?? 0; function clearFilters() { setSearch(''); setSituaFilter(undefined); setPeriod(''); setPage(1); } // ── Tabela desktop ───────────────────────────────────────────────────────── const columns: TableColumnsType = [ { title: 'Nº Pedido', dataIndex: 'numPedSar', width: 140, render: (_: string, row: PedidoSummary) => { const label = row.numero ? String(row.numero) : row.numPedSar; return row.fonte === 'erp' ? ( {label} ) : ( {label} ); }, }, { title: 'Cliente', key: 'cliente', render: (_: unknown, row: PedidoSummary) => ( Cód. {row.idCliente} {row.obs && ( {row.obs.slice(0, 40)} )} ), }, { title: 'Status', dataIndex: 'situa', width: 140, render: (s: number, row: PedidoSummary) => ( ), }, { title: 'Total', dataIndex: 'total', width: 130, align: 'right', render: (v: string) => ( {fmt(v)} ), }, { title: 'Data', dataIndex: 'dtPedido', width: 110, render: (v: string) => {fmtDate(v)}, }, { title: '', key: 'actions', width: 48, render: (_: unknown, row: PedidoSummary) => ( setDrawerOrderId(id)} /> ), }, ]; return (
{/* ── Cabeçalho ───────────────────────────────────────────────── */}
Pedidos

Acompanhe seus pedidos, status de envio e histórico comercial.

{!isMobile && ( )}
{/* ── Métricas ────────────────────────────────────────────────── */} {/* ── Filtros ─────────────────────────────────────────────────── */} { setSearch(e.target.value); setPage(1); }} placeholder="Buscar por nº do pedido..." style={{ width: '100%', height: 32, padding: '0 11px', border: '1px solid #d9d9d9', borderRadius: 6, fontSize: 14, outline: 'none', color: '#1F2937', boxSizing: 'border-box', }} /> { setPeriod(v ?? ''); setPage(1); }} options={[ { value: 'today', label: 'Hoje' }, { value: '7d', label: 'Últimos 7 dias' }, { value: '30d', label: 'Últimos 30 dias' }, ]} /> {/* ── Conteúdo principal ──────────────────────────────────────── */} {isLoading ? (
) : rows.length === 0 ? ( void navigate({ to: '/pedidos/novo' })} /> ) : isMobile ? ( /* ── Mobile: cards ─────────────────────────────────────────── */
{rows.map((o) => ( setDrawerOrderId(id)} /> ))}
Mostrando {rows.length} de {total} pedidos
) : ( /* ── Desktop: tabela ────────────────────────────────────────── */ rowKey="id" columns={columns} dataSource={rows} size="middle" onRow={(row) => ({ onClick: () => { if (row.fonte !== 'erp') setDrawerOrderId(row.id); }, style: { background: STATUS[row.situa]?.rowBg ?? '#fff', cursor: row.fonte !== 'erp' ? 'pointer' : 'default', }, })} pagination={{ current: page, pageSize: limit, total, showSizeChanger: false, showTotal: (t, [s, e]) => `Mostrando ${s}–${e} de ${t} pedidos`, onChange: (p) => setPage(p), style: { padding: '12px 24px' }, }} style={{ borderRadius: 10, overflow: 'hidden' }} /> )} {/* ── Drawer de detalhe ───────────────────────────────────────── */} setDrawerOrderId(null)} /> {/* FAB mobile */} {isMobile && (
); }