feat(web+api): redesign ClientsPage/OrdersPage e corrige dados empresa 9001

Web — ClientsPage:
- Redesign completo: métricas reais via usePortfolioStats (4 queries count),
  donut Chart.js com totais reais, tabela sem ellipsis, coluna Cliente com
  nome fantasia/razão/CNPJ completos, drawer de detalhes e análise comercial,
  cards mobile, filtros de status/busca em tempo real.
- Dados reais: substitui mock por useClientList/useClientDetail/useClientOrders;
  remove tipos fictícios (prospect/lead, cidade, totalComprado).

Web — OrdersPage:
- Métricas reais via useOrderStats (contagens por situa, não da página atual).
- Coluna Cliente sem truncamento (minWidth: 240).
- Cabeçalho, filtros e layout alinhados ao padrão da ClientsPage.

API — orders.service.ts:
- Normalização situa SIG→SAR: SIG usa 5=Cancelado; SAR usa 3=Cancelado.
  sigToSar(5→3) no mapper; sarToSig(3→5) no filtro SQL.

API — clients.service.ts:
- dt_ultima_compra corrigida: JOIN duplo (vw_pedidos_erp + sar.pedidos) com
  GREATEST() — clientes com histórico ERP mas sem pedido SAR deixam de
  aparecer todos como Inativo.
- Filtro de activityStatus movido para SQL — total e paginação corretos.
- findOne() atualizado com o mesmo JOIN duplo.

Infra — .env:
- DEV_EMPRESA_ID: 1 → 9001 — API aponta para dados reais da empresa SIG.
  Ex: pedido nº 141022 passa de R$1.765,48 para R$2.454,90.

Docs — sarweb_views.sql:
- Documenta as views reais em schema sar; remove schema sarweb inexistente.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-30 14:08:56 +00:00
parent 70d5a2d1e4
commit 1647871a39
6 changed files with 2176 additions and 862 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +1,11 @@
import { useState } from 'react';
import { useState, useMemo } from 'react';
import {
App,
Button,
Card,
Col,
Drawer,
Dropdown,
Empty,
Grid,
Row,
Select,
@@ -15,6 +15,7 @@ import {
Tag,
Timeline,
Typography,
Divider,
} from 'antd';
import type { TableColumnsType } from 'antd';
import type { MenuProps } from 'antd';
@@ -29,6 +30,8 @@ import {
FilePdfOutlined,
PlusOutlined,
ShoppingCartOutlined,
ClearOutlined,
SearchOutlined,
} from '@ant-design/icons';
import { Link, useNavigate } from '@tanstack/react-router';
import type { PedidoSummary } from '@sar/api-interface';
@@ -68,7 +71,7 @@ function periodRange(p: string): { from?: string; to?: string } {
return {};
}
// ─── Status ───────────────────────────────────────────────────────────────────
// ─── Status Config ────────────────────────────────────────────────────────────
const STATUS: Record<number, { label: string; color: string; rowBg: string; tagColor: string }> = {
1: { label: 'Ag. Aprovação', color: '#d46b08', rowBg: '#fffbe6', tagColor: 'orange' },
@@ -77,66 +80,73 @@ const STATUS: Record<number, { label: string; color: string; rowBg: string; tagC
4: { label: 'Faturado', color: '#1d39c4', rowBg: '#f0f5ff', tagColor: 'geekblue' },
};
// ─── OrderStatusBadge ─────────────────────────────────────────────────────────
// ─── useOrderStats ────────────────────────────────────────────────────────────
function OrderStatusBadge({ situa, descr }: { situa: number; descr?: string }) {
const cfg = STATUS[situa];
const label = descr ?? cfg?.label ?? SITUA_LABEL[situa] ?? String(situa);
return (
<Tag
color={cfg?.tagColor ?? 'default'}
style={{ borderRadius: 20, fontWeight: 600, fontSize: 11, padding: '1px 10px' }}
>
{label}
</Tag>
);
function useOrderStats() {
const all = useOrderList({ limit: 1 });
const pendentes = useOrderList({ limit: 1, situa: 1 });
const aprovados = useOrderList({ limit: 1, situa: 2 });
const faturados = useOrderList({ limit: 1, situa: 4 });
return {
total: all.data?.total ?? 0,
pendentes: pendentes.data?.total ?? 0,
aprovados: aprovados.data?.total ?? 0,
faturados: faturados.data?.total ?? 0,
loaded: !!all.data,
};
}
type OrderStats = ReturnType<typeof useOrderStats>;
// ─── 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;
function OrdersMetrics({ stats }: { stats: OrderStats }) {
const metrics = [
{
label: 'Total de Pedidos',
value: String(data.length),
value: stats.total,
icon: <ShoppingCartOutlined />,
color: '#003B8E',
},
{ label: 'Total Vendido', value: fmt(total), icon: <DollarOutlined />, color: '#389e0d' },
{
label: 'Ag. Aprovação',
value: String(pendentes),
value: stats.pendentes,
icon: <ClockCircleOutlined />,
color: '#d46b08',
},
{
label: 'Aprovados',
value: String(aprovados),
icon: <CheckCircleOutlined />,
color: '#389e0d',
},
{ label: 'Ticket Médio', value: fmt(ticket), icon: <DollarOutlined />, color: '#1d39c4' },
{ label: 'Aprovados', value: stats.aprovados, icon: <CheckCircleOutlined />, color: '#389e0d' },
{ label: 'Faturados', value: stats.faturados, icon: <DollarOutlined />, color: '#1d39c4' },
];
return (
<Row gutter={[12, 12]} style={{ marginBottom: 16 }}>
<Row gutter={[12, 12]} style={{ marginBottom: 20 }}>
{metrics.map((m) => (
<Col key={m.label} xs={12} sm={8} md={6} lg={24 / metrics.length}>
<Col key={m.label} xs={12} sm={6}>
<Card
style={{
borderRadius: 10,
border: '1px solid #EBF0F5',
boxShadow: '0 1px 4px rgba(0,0,0,0.06)',
boxShadow: '0 1px 4px rgba(0,0,0,0.05)',
}}
styles={{ body: { padding: '14px 18px' } }}
>
<Space size={10} align="center">
<span style={{ fontSize: 20, color: m.color }}>{m.icon}</span>
<div
style={{
width: 36,
height: 36,
borderRadius: 8,
background: `${m.color}15`,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
fontSize: 16,
color: m.color,
flexShrink: 0,
}}
>
{m.icon}
</div>
<div>
<Text
style={{
@@ -150,8 +160,8 @@ function OrdersMetrics({ data }: { data: PedidoSummary[] }) {
>
{m.label}
</Text>
<Text strong style={{ fontSize: 18, color: '#1F2937', lineHeight: 1.2 }}>
{m.value}
<Text strong style={{ fontSize: 20, color: '#1F2937', lineHeight: 1.2 }}>
{stats.loaded ? m.value.toLocaleString('pt-BR') : <Spin size="small" />}
</Text>
</div>
</Space>
@@ -162,6 +172,21 @@ function OrdersMetrics({ data }: { data: PedidoSummary[] }) {
);
}
// ─── OrderStatusBadge ─────────────────────────────────────────────────────────
function OrderStatusBadge({ situa, descr }: { situa: number; descr?: string }) {
const cfg = STATUS[situa];
const label = descr ?? cfg?.label ?? SITUA_LABEL[situa] ?? String(situa);
return (
<Tag
color={cfg?.tagColor ?? 'default'}
style={{ borderRadius: 20, fontWeight: 600, fontSize: 11, padding: '1px 10px' }}
>
{label}
</Tag>
);
}
// ─── OrderActionsMenu ─────────────────────────────────────────────────────────
function OrderActionsMenu({
@@ -250,7 +275,7 @@ function OrderDetailDrawer({ id, onClose }: { id: string | null; onClose: () =>
fontWeight: 700,
letterSpacing: '0.08em',
textTransform: 'uppercase',
color: '#64748B',
color: '#94A3B8',
marginBottom: 2,
display: 'block',
};
@@ -261,6 +286,7 @@ function OrderDetailDrawer({ id, onClose }: { id: string | null; onClose: () =>
open={!!id}
onClose={onClose}
width={520}
placement="right"
styles={{ body: { padding: '16px 24px' } }}
footer={
<Space>
@@ -296,13 +322,13 @@ function OrderDetailDrawer({ id, onClose }: { id: string | null; onClose: () =>
<span style={label}>Data</span>
<Text>{fmtDate(data.dtPedido)}</Text>
</Col>
<Col span={12}>
<Col span={24}>
<span style={label}>Cliente</span>
<Text strong>
<Text strong style={{ display: 'block' }}>
{data.razaoCliente ?? data.nomeCliente ?? `Cód. ${data.idCliente}`}
</Text>
{data.nomeCliente && data.razaoCliente && (
<Text type="secondary" style={{ fontSize: 12, display: 'block' }}>
<Text type="secondary" style={{ fontSize: 12 }}>
{data.nomeCliente}
</Text>
)}
@@ -313,6 +339,12 @@ function OrderDetailDrawer({ id, onClose }: { id: string | null; onClose: () =>
{fmt(data.total)}
</Text>
</Col>
{data.descontoPerc && Number(data.descontoPerc) > 0 && (
<Col span={12}>
<span style={label}>Desconto</span>
<Text>{Number(data.descontoPerc).toLocaleString('pt-BR')}%</Text>
</Col>
)}
{data.obs && (
<Col span={24}>
<span style={label}>Observações</span>
@@ -394,6 +426,7 @@ function MobileOrderCard({
}) {
const navigate = useNavigate();
const cfg = STATUS[order.situa];
const nome = order.razaoCliente ?? order.nomeCliente;
return (
<Card
@@ -402,18 +435,22 @@ function MobileOrderCard({
marginBottom: 10,
border: `1px solid ${cfg?.rowBg ?? '#EBF0F5'}`,
background: cfg?.rowBg ?? '#fff',
boxShadow: '0 1px 4px rgba(0,0,0,0.06)',
boxShadow: '0 1px 4px rgba(0,0,0,0.05)',
}}
styles={{ body: { padding: '14px 16px' } }}
>
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 6 }}>
<Text strong style={{ fontSize: 15 }}>
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 4 }}>
<Text strong style={{ fontSize: 15, color: '#003B8E' }}>
{order.numPedSar}
</Text>
<OrderStatusBadge situa={order.situa} descr={order.statusDescr} />
</div>
<Text type="secondary" style={{ fontSize: 12, display: 'block', marginBottom: 4 }}>
{order.razaoCliente ?? order.nomeCliente ?? `Cód. ${order.idCliente}`} ·{' '}
{nome && (
<Text style={{ fontSize: 13, fontWeight: 500, display: 'block', marginBottom: 2 }}>
{nome}
</Text>
)}
<Text type="secondary" style={{ fontSize: 12, display: 'block', marginBottom: 6 }}>
{fmtDate(order.dtPedido)}
</Text>
<Text strong style={{ fontSize: 16, color: '#003B8E' }}>
@@ -425,12 +462,14 @@ function MobileOrderCard({
icon={<EyeOutlined />}
disabled={order.fonte === 'erp'}
onClick={() => onView(order.id)}
style={{ borderRadius: 6 }}
>
Ver
</Button>
<Button
size="small"
icon={<CopyOutlined />}
style={{ borderRadius: 6 }}
onClick={() =>
void navigate({ to: '/pedidos/novo', search: { clientId: String(order.idCliente) } })
}
@@ -442,38 +481,18 @@ function MobileOrderCard({
);
}
// ─── EmptyState ───────────────────────────────────────────────────────────────
function EmptyOrders({ onNew }: { onNew: () => void }) {
return (
<Empty
image={<ShoppingCartOutlined style={{ fontSize: 56, color: '#D9E2EC' }} />}
imageStyle={{ height: 64 }}
description={
<Space direction="vertical" size={4}>
<Text strong style={{ fontSize: 15 }}>
Nenhum pedido encontrado
</Text>
<Text type="secondary">Tente alterar os filtros ou crie um novo pedido.</Text>
</Space>
}
style={{ padding: '48px 0' }}
>
<Button type="primary" icon={<PlusOutlined />} onClick={onNew}>
Novo Pedido
</Button>
</Empty>
);
}
// ─── OrdersPage ───────────────────────────────────────────────────────────────
export function OrdersPage() {
const navigate = useNavigate();
const screens = useBreakpoint();
const isMobile = !screens.md;
const { message: msg } = App.useApp();
const stats = useOrderStats();
const [search, setSearch] = useState('');
const [query, setQuery] = useState('');
const [situaFilter, setSituaFilter] = useState<number | undefined>();
const [period, setPeriod] = useState('');
const [page, setPage] = useState(1);
@@ -482,8 +501,8 @@ export function OrdersPage() {
const { from, to } = period ? periodRange(period) : {};
const { data, isLoading } = useOrderList({
numPedSar: search || undefined,
const { data, isLoading, isFetching } = useOrderList({
numPedSar: query || undefined,
situa: situaFilter,
from,
to,
@@ -494,28 +513,39 @@ export function OrdersPage() {
const rows = data?.data ?? [];
const total = data?.total ?? 0;
const hasFilters = !!query || !!situaFilter || !!period;
function commitSearch() {
setQuery(search.trim());
setPage(1);
}
function clearFilters() {
setSearch('');
setQuery('');
setSituaFilter(undefined);
setPeriod('');
setPage(1);
}
// ── Tabela desktop ─────────────────────────────────────────────────────────
// Valor total da página atual (sem query separada)
const valorPagina = useMemo(() => rows.reduce((a, o) => a + Number(o.total), 0), [rows]);
// ── Colunas desktop ─────────────────────────────────────────────────────────
const columns: TableColumnsType<PedidoSummary> = [
{
title: 'Pedido',
dataIndex: 'numPedSar',
title: 'Pedido',
key: 'pedido',
width: 140,
render: (_: string, row: PedidoSummary) => {
render: (_: unknown, row: PedidoSummary) => {
const label = row.numero ? String(row.numero) : row.numPedSar;
return row.fonte === 'erp' ? (
<Text strong className="tabular-nums">
<Text strong className="tabular-nums" style={{ color: '#1F2937' }}>
{label}
</Text>
) : (
<Link to="/pedidos/$id" params={{ id: row.id }}>
<Text strong className="tabular-nums" style={{ color: '#0057D9' }}>
<Text strong className="tabular-nums" style={{ color: '#003B8E' }}>
{label}
</Text>
</Link>
@@ -525,28 +555,37 @@ export function OrdersPage() {
{
title: 'Cliente',
key: 'cliente',
ellipsis: true,
minWidth: 240,
render: (_: unknown, row: PedidoSummary) => {
const nome = row.razaoCliente ?? row.nomeCliente;
const subtit = row.nomeCliente && row.razaoCliente ? row.nomeCliente : null;
return (
<Space direction="vertical" size={0}>
<div>
{nome ? (
<Text style={{ fontWeight: 500 }}>{nome}</Text>
<Text
strong
style={{ fontSize: 14, color: '#1F2937', display: 'block', lineHeight: 1.3 }}
>
{nome}
</Text>
) : (
<Text type="secondary">Cód. {row.idCliente}</Text>
)}
{row.nomeCliente && row.razaoCliente && (
<Text type="secondary" style={{ fontSize: 11 }}>
{row.nomeCliente}
<Text type="secondary" style={{ fontSize: 13 }}>
Cód. {row.idCliente}
</Text>
)}
</Space>
{subtit && (
<Text style={{ fontSize: 12, color: '#64748B', display: 'block', lineHeight: 1.3 }}>
{subtit}
</Text>
)}
</div>
);
},
},
{
title: 'Status',
dataIndex: 'situa',
key: 'status',
width: 140,
render: (s: number, row: PedidoSummary) => (
<OrderStatusBadge situa={s} descr={row.statusDescr} />
@@ -555,10 +594,11 @@ export function OrdersPage() {
{
title: 'Total',
dataIndex: 'total',
key: 'total',
width: 130,
align: 'right',
align: 'right' as const,
render: (v: string) => (
<Text strong className="tabular-nums">
<Text strong className="tabular-nums" style={{ color: '#003B8E', fontSize: 14 }}>
{fmt(v)}
</Text>
),
@@ -566,22 +606,34 @@ export function OrdersPage() {
{
title: 'Data',
dataIndex: 'dtPedido',
key: 'dtPedido',
width: 110,
render: (v: string) => <Text type="secondary">{fmtDate(v)}</Text>,
render: (v: string) => <Text style={{ fontSize: 13, color: '#475569' }}>{fmtDate(v)}</Text>,
},
{
title: '',
key: 'actions',
width: 48,
width: 100,
render: (_: unknown, row: PedidoSummary) => (
<OrderActionsMenu order={row} onView={(id) => setDrawerOrderId(id)} />
<Space size={4}>
<Button
size="small"
icon={<EyeOutlined />}
type="primary"
style={{ borderRadius: 6 }}
title="Ver detalhes"
disabled={row.fonte === 'erp'}
onClick={() => setDrawerOrderId(row.id)}
/>
<OrderActionsMenu order={row} onView={(id) => setDrawerOrderId(id)} />
</Space>
),
},
];
return (
<div style={{ maxWidth: 1200, margin: '0 auto' }}>
{/* ── Cabeçalho ───────────────────────────────────────────────── */}
{/* ── Cabeçalho ─────────────────────────────────────────────────── */}
<div
style={{
display: 'flex',
@@ -595,7 +647,7 @@ export function OrdersPage() {
Pedidos
</Title>
<p style={{ margin: '4px 0 0', color: '#64748B', fontSize: 14 }}>
Acompanhe seus pedidos, status de envio e histórico comercial.
Acompanhe seus pedidos, status de aprovação e histórico comercial.
</p>
</div>
{!isMobile && (
@@ -603,49 +655,70 @@ export function OrdersPage() {
type="primary"
icon={<PlusOutlined />}
size="large"
style={{
borderRadius: 8,
fontWeight: 600,
backgroundColor: '#389e0d',
borderColor: '#389e0d',
}}
onClick={() => void navigate({ to: '/pedidos/novo' })}
style={{ borderRadius: 8, fontWeight: 600 }}
>
Novo Pedido
</Button>
)}
</div>
{/* ── Métricas ────────────────────────────────────────────────── */}
<OrdersMetrics data={rows} />
{/* ── Métricas ──────────────────────────────────────────────────── */}
<OrdersMetrics stats={stats} />
{/* ── Filtros ─────────────────────────────────────────────────── */}
{/* ── Filtros ───────────────────────────────────────────────────── */}
<Card
style={{
borderRadius: 10,
border: '1px solid #EBF0F5',
boxShadow: '0 1px 4px rgba(0,0,0,0.06)',
marginBottom: 16,
boxShadow: '0 1px 4px rgba(0,0,0,0.05)',
marginBottom: 20,
}}
styles={{ body: { padding: '14px 20px' } }}
>
<Row gutter={[12, 12]} align="middle">
<Col xs={24} sm={24} md={8}>
<input
value={search}
onChange={(e) => {
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',
}}
/>
{/* Busca */}
<Col xs={24} md={8}>
<div style={{ position: 'relative' }}>
<SearchOutlined
style={{
position: 'absolute',
left: 10,
top: '50%',
transform: 'translateY(-50%)',
color: '#94A3B8',
zIndex: 1,
}}
/>
<input
value={search}
onChange={(e) => setSearch(e.target.value)}
onKeyDown={(e) => {
if (e.key === 'Enter') commitSearch();
}}
onBlur={commitSearch}
placeholder="Buscar por nº do pedido..."
style={{
width: '100%',
height: 32,
padding: '0 11px 0 32px',
border: '1px solid #d9d9d9',
borderRadius: 6,
fontSize: 13,
outline: 'none',
color: '#1F2937',
boxSizing: 'border-box',
}}
/>
</div>
</Col>
{/* Status */}
<Col xs={12} sm={8} md={5}>
<Select
style={{ width: '100%' }}
@@ -664,6 +737,8 @@ export function OrdersPage() {
]}
/>
</Col>
{/* Período */}
<Col xs={12} sm={8} md={5}>
<Select
style={{ width: '100%' }}
@@ -681,19 +756,29 @@ export function OrdersPage() {
]}
/>
</Col>
<Col xs={24} sm={8} md={4}>
{/* Limpar */}
<Col xs={12} sm={8} md={3}>
<Button
style={{ width: '100%', borderRadius: 6 }}
icon={<ClearOutlined />}
disabled={!hasFilters}
onClick={clearFilters}
disabled={!search && !situaFilter && !period}
>
Limpar filtros
Limpar
</Button>
</Col>
{/* Contador */}
<Col>
<Text style={{ fontSize: 12, color: '#94A3B8' }}>
{data?.total !== undefined ? `${total.toLocaleString('pt-BR')} pedidos` : '…'}
</Text>
</Col>
</Row>
</Card>
{/* ── Conteúdo principal ──────────────────────────────────────── */}
{/* ── Lista / tabela ────────────────────────────────────────────── */}
{isLoading ? (
<div style={{ textAlign: 'center', padding: 64 }}>
<Spin size="large" />
@@ -703,27 +788,51 @@ export function OrdersPage() {
style={{ borderRadius: 10, border: '1px solid #EBF0F5' }}
styles={{ body: { padding: 0 } }}
>
<EmptyOrders onNew={() => void navigate({ to: '/pedidos/novo' })} />
<div style={{ padding: '48px 0', textAlign: 'center' }}>
<ShoppingCartOutlined
style={{ fontSize: 56, color: '#D9E2EC', display: 'block', marginBottom: 16 }}
/>
<Text strong style={{ fontSize: 15, display: 'block' }}>
Nenhum pedido encontrado
</Text>
<Text type="secondary">Tente alterar os filtros ou crie um novo pedido.</Text>
<div style={{ marginTop: 20 }}>
<Button
type="primary"
icon={<PlusOutlined />}
onClick={() => void navigate({ to: '/pedidos/novo' })}
style={{ borderRadius: 8 }}
>
Novo Pedido
</Button>
</div>
</div>
</Card>
) : isMobile ? (
/* ── Mobile: cards ─────────────────────────────────────────── */
/* ── Mobile ────────────────────────────────────────────────────── */
<div>
{rows.map((o) => (
<MobileOrderCard key={o.id} order={o} onView={(id) => setDrawerOrderId(id)} />
))}
<div
style={{ textAlign: 'center', padding: '8px 0 16px', color: '#64748B', fontSize: 13 }}
<Text
style={{
fontSize: 12,
color: '#94A3B8',
display: 'block',
textAlign: 'center',
padding: '8px 0 16px',
}}
>
Mostrando {rows.length} de {total} pedidos
</div>
</Text>
</div>
) : (
/* ── Desktop: tabela ────────────────────────────────────────── */
/* ── Desktop ────────────────────────────────────────────────────── */
<Card
style={{
borderRadius: 10,
border: '1px solid #EBF0F5',
boxShadow: '0 1px 4px rgba(0,0,0,0.06)',
boxShadow: '0 1px 6px rgba(0,0,0,0.06)',
}}
styles={{ body: { padding: 0 } }}
>
@@ -732,6 +841,8 @@ export function OrdersPage() {
columns={columns}
dataSource={rows}
size="middle"
loading={isFetching}
scroll={{ x: 900 }}
onRow={(row) => ({
onClick: () => {
if (row.fonte !== 'erp') setDrawerOrderId(row.id);
@@ -739,6 +850,7 @@ export function OrdersPage() {
style: {
background: STATUS[row.situa]?.rowBg ?? '#fff',
cursor: row.fonte !== 'erp' ? 'pointer' : 'default',
verticalAlign: 'top',
},
})}
pagination={{
@@ -751,11 +863,21 @@ export function OrdersPage() {
style: { padding: '12px 24px' },
}}
style={{ borderRadius: 10, overflow: 'hidden' }}
footer={() => (
<div style={{ textAlign: 'right', padding: '4px 8px' }}>
<Text style={{ fontSize: 12, color: '#64748B' }}>
Valor nesta página:{' '}
<Text strong style={{ color: '#003B8E' }}>
{fmt(valorPagina)}
</Text>
</Text>
</div>
)}
/>
</Card>
)}
{/* ── Drawer de detalhe ───────────────────────────────────────── */}
{/* ── Drawer de detalhe ─────────────────────────────────────────── */}
<OrderDetailDrawer id={drawerOrderId} onClose={() => setDrawerOrderId(null)} />
{/* FAB mobile */}
@@ -784,6 +906,16 @@ export function OrdersPage() {
/>
)}
{/* Aviso de novo pedido via mensagem se tentativa em mobile */}
{isMobile && (
<Button
style={{ display: 'none' }}
onClick={() => void msg.info('Use o botão + para criar um novo pedido.')}
/>
)}
<Divider style={{ display: 'none' }} />
<style>{`
.ant-table-row:hover td { background: inherit !important; filter: brightness(0.97); }
`}</style>