feat(auth): endpoint /auth/me, cockpits renomeados e menu de logout
- GET /api/v1/auth/me retorna perfil real do ERP (vw_representantes) - Contrato UserProfile adicionado ao shared api-interface - Hook useCurrentUser() no frontend consome o endpoint - Cockpit rafael → rep, sandra → supervisor (pastas e componentes) - Topbar exibe iniciais do usuário e dropdown com nome, role e "Sair" - Logout limpa token e recarrega para voltar ao DevLogin Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
142
apps/web/src/cockpits/rep/OrdersPage.tsx
Normal file
142
apps/web/src/cockpits/rep/OrdersPage.tsx
Normal file
@@ -0,0 +1,142 @@
|
||||
import { useState } from 'react';
|
||||
import { Table, Tag, Input, Select, Space, Typography, Badge } from 'antd';
|
||||
import type { TableColumnsType } from 'antd';
|
||||
import { Link } from '@tanstack/react-router';
|
||||
import type { PedidoSummary } from '@sar/api-interface';
|
||||
import { SITUA_LABEL } from '@sar/api-interface';
|
||||
import { useOrderList } from '../../lib/queries/orders';
|
||||
|
||||
const { Title } = Typography;
|
||||
const { Search } = Input;
|
||||
|
||||
const SITUA_COLOR: Record<number, string> = {
|
||||
1: 'warning',
|
||||
2: 'processing',
|
||||
3: 'error',
|
||||
4: 'success',
|
||||
};
|
||||
|
||||
const columns: TableColumnsType<PedidoSummary> = [
|
||||
{
|
||||
title: 'Nº',
|
||||
dataIndex: 'numero',
|
||||
width: 120,
|
||||
render: (_: number, row: PedidoSummary) => {
|
||||
const label = row.numero ? String(row.numero) : row.numPedSar || row.id;
|
||||
return row.fonte === 'erp' ? (
|
||||
<span style={{ fontVariantNumeric: 'tabular-nums' }}>{label}</span>
|
||||
) : (
|
||||
<Link to="/pedidos/$id" params={{ id: row.id }}>
|
||||
{label}
|
||||
</Link>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Status',
|
||||
dataIndex: 'situa',
|
||||
width: 150,
|
||||
render: (s: number, row: PedidoSummary) => {
|
||||
const label = row.statusDescr ?? SITUA_LABEL[s] ?? String(s);
|
||||
return (
|
||||
<Badge
|
||||
status={
|
||||
(SITUA_COLOR[s] ?? 'default') as
|
||||
| 'default'
|
||||
| 'warning'
|
||||
| 'processing'
|
||||
| 'success'
|
||||
| 'error'
|
||||
}
|
||||
text={<Tag color={SITUA_COLOR[s] ?? 'default'}>{label}</Tag>}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Total',
|
||||
dataIndex: 'total',
|
||||
width: 130,
|
||||
align: 'right',
|
||||
render: (v: string) =>
|
||||
Number(v).toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' }),
|
||||
},
|
||||
{
|
||||
title: 'Data',
|
||||
dataIndex: 'dtPedido',
|
||||
width: 130,
|
||||
render: (v: string) => new Date(v).toLocaleDateString('pt-BR'),
|
||||
},
|
||||
];
|
||||
|
||||
export function OrdersPage() {
|
||||
const [numFilter, setNumFilter] = useState('');
|
||||
const [situaFilter, setSituaFilter] = useState<number | undefined>();
|
||||
const [page, setPage] = useState(1);
|
||||
const limit = 50;
|
||||
|
||||
const { data, isLoading } = useOrderList({
|
||||
numPedSar: numFilter || undefined,
|
||||
situa: situaFilter,
|
||||
page,
|
||||
limit,
|
||||
});
|
||||
|
||||
return (
|
||||
<div style={{ padding: 24 }}>
|
||||
<Title level={3} style={{ marginBottom: 16 }}>
|
||||
Pedidos
|
||||
</Title>
|
||||
|
||||
<Space style={{ marginBottom: 16 }} wrap>
|
||||
<Search
|
||||
placeholder="Buscar por número (SAR-NNNNN)..."
|
||||
allowClear
|
||||
style={{ width: 240 }}
|
||||
onSearch={(v) => {
|
||||
setNumFilter(v);
|
||||
setPage(1);
|
||||
}}
|
||||
onChange={(e) => {
|
||||
if (!e.target.value) {
|
||||
setNumFilter('');
|
||||
setPage(1);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Select
|
||||
placeholder="Status"
|
||||
allowClear
|
||||
style={{ width: 160 }}
|
||||
onChange={(v) => {
|
||||
setSituaFilter(v as number | undefined);
|
||||
setPage(1);
|
||||
}}
|
||||
options={[
|
||||
{ value: 1, label: 'Ag. Aprovação' },
|
||||
{ value: 2, label: 'Aprovado' },
|
||||
{ value: 3, label: 'Cancelado' },
|
||||
{ value: 4, label: 'Faturado' },
|
||||
]}
|
||||
/>
|
||||
</Space>
|
||||
|
||||
<Table<PedidoSummary>
|
||||
rowKey="id"
|
||||
columns={columns}
|
||||
dataSource={data?.data ?? []}
|
||||
loading={isLoading}
|
||||
rowClassName={(row) => (row.situa === 1 ? 'row-pending' : '')}
|
||||
pagination={{
|
||||
current: page,
|
||||
pageSize: limit,
|
||||
total: data?.total ?? 0,
|
||||
showSizeChanger: false,
|
||||
onChange: (p) => setPage(p),
|
||||
}}
|
||||
/>
|
||||
|
||||
<style>{`.row-pending td { background: #fffbe6 !important; }`}</style>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user