@fayz-ai/plugin-orders 0.12.28 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/OrderDetailRoute-LTPDQXQU.js +193 -0
- package/dist/OrderDetailRoute-LTPDQXQU.js.map +1 -0
- package/dist/OrdersPage-5326V62H.js +291 -0
- package/dist/OrdersPage-5326V62H.js.map +1 -0
- package/dist/chunk-YVC7R552.js +6 -0
- package/dist/chunk-YVC7R552.js.map +1 -0
- package/dist/context.d.ts +0 -46
- package/dist/context.d.ts.map +1 -1
- package/dist/data/core-supabase.d.ts.map +1 -1
- package/dist/index.d.ts +4 -34
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1108 -934
- package/dist/index.js.map +1 -1
- package/dist/lib/detail-slot.d.ts +13 -0
- package/dist/lib/detail-slot.d.ts.map +1 -0
- package/dist/lib/list-query.d.ts +21 -0
- package/dist/lib/list-query.d.ts.map +1 -0
- package/dist/migrations/index.d.ts +6 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/server/index.d.ts +17 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +48 -0
- package/dist/server/index.js.map +1 -0
- package/dist/types.d.ts +10 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/views/OrderDetailRoute.d.ts +12 -0
- package/dist/views/OrderDetailRoute.d.ts.map +1 -0
- package/dist/views/OrdersPage.d.ts +1 -7
- package/dist/views/OrdersPage.d.ts.map +1 -1
- package/dist/views/OrdersScreen.d.ts.map +1 -1
- package/package.json +12 -9
- package/dist/OrdersPage-QV2YWARF.js +0 -483
- package/dist/OrdersPage-QV2YWARF.js.map +0 -1
- package/dist/chunk-TYS3LCKX.js +0 -57
- package/dist/chunk-TYS3LCKX.js.map +0 -1
- package/dist/lib/floor-plan-id.d.ts +0 -13
- package/dist/lib/floor-plan-id.d.ts.map +0 -1
- package/dist/views/CommercialOrdersScreen.d.ts +0 -3
- package/dist/views/CommercialOrdersScreen.d.ts.map +0 -1
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { ORDER_DETAIL_COMPONENT_ID } from './chunk-YVC7R552.js';
|
|
2
|
+
import * as React2 from 'react';
|
|
3
|
+
import React2__default from 'react';
|
|
4
|
+
import { Pencil, Ban, Check } from 'lucide-react';
|
|
5
|
+
import { adminNavigateTo, OrderDetailPage, usePermissionOptional, useOrderKindTransitions, orderIsEditable, PageActions } from '@fayz-ai/admin';
|
|
6
|
+
import { Button, ConfirmDialog, toast } from '@fayz-ai/ui';
|
|
7
|
+
import { getComponent, usePluginRuntimeOptional, getSupabaseClientOptional, describeError, getActiveTenantId } from '@fayz-ai/core';
|
|
8
|
+
import { setStatus } from '@fayz-ai/core/orders';
|
|
9
|
+
import { ReceivePaymentModal } from '@fayz-ai/plugin-financial';
|
|
10
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
11
|
+
|
|
12
|
+
function toModalInstallment(bill) {
|
|
13
|
+
return {
|
|
14
|
+
id: bill.id,
|
|
15
|
+
amount: Number(bill.amount ?? 0),
|
|
16
|
+
paidAmount: Number(bill.paid_amount ?? 0),
|
|
17
|
+
installmentNumber: bill.installment_number ?? 1,
|
|
18
|
+
direction: bill.direction ?? "credit",
|
|
19
|
+
dueDate: bill.due_date,
|
|
20
|
+
invoiceId: bill.financial_invoice_id ?? bill.invoice_id
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function firstOpenBill(receivable) {
|
|
24
|
+
return receivable?.bills.find(
|
|
25
|
+
(b) => Number(b.paid_amount ?? 0) < Number(b.amount)
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
function OrderReceivableActions({ orderId, orderTotal, receivable, reload }) {
|
|
29
|
+
const [busy, setBusy] = React2.useState(false);
|
|
30
|
+
const [paying, setPaying] = React2.useState(null);
|
|
31
|
+
const can = usePermissionOptional();
|
|
32
|
+
const runtime = usePluginRuntimeOptional();
|
|
33
|
+
const hasFinancialRoute = (runtime?.activePlugins ?? []).some(
|
|
34
|
+
(p) => p.routes?.some((r) => r.path === "/financial")
|
|
35
|
+
);
|
|
36
|
+
const canInvoice = can("financial", "create");
|
|
37
|
+
const balance = receivable ? Number(receivable.balance.balance ?? 0) : 0;
|
|
38
|
+
const cancelled = receivable?.balance.status === "cancelled";
|
|
39
|
+
const openBill = firstOpenBill(receivable);
|
|
40
|
+
const canReceive = receivable ? balance > 0 && !cancelled && Boolean(openBill) : canInvoice && Number(orderTotal) > 0;
|
|
41
|
+
async function registrarRecebimento() {
|
|
42
|
+
if (receivable) {
|
|
43
|
+
const bill = firstOpenBill(receivable);
|
|
44
|
+
if (bill) setPaying(toModalInstallment(bill));
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const db = getSupabaseClientOptional();
|
|
48
|
+
if (!db) return;
|
|
49
|
+
setBusy(true);
|
|
50
|
+
try {
|
|
51
|
+
const { error } = await db.rpc("fn_invoice_from_order", { p_order_id: orderId });
|
|
52
|
+
if (error) throw new Error(error.message ?? "Falha ao faturar o pedido");
|
|
53
|
+
const { data } = await db.from("v_financial_bills").select("*").eq("invoice_id", orderId).order("installment_number", { ascending: true });
|
|
54
|
+
const bill = (data ?? []).find(
|
|
55
|
+
(b) => Number(b.paid_amount ?? 0) < Number(b.amount ?? 0)
|
|
56
|
+
);
|
|
57
|
+
await reload(true);
|
|
58
|
+
if (bill) setPaying(toModalInstallment(bill));
|
|
59
|
+
else toast.error("Pedido faturado, mas nenhuma parcela em aberto foi encontrada");
|
|
60
|
+
} catch (err) {
|
|
61
|
+
toast.error(describeError(err, "Falha ao faturar o pedido"));
|
|
62
|
+
} finally {
|
|
63
|
+
setBusy(false);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
67
|
+
canReceive && /* @__PURE__ */ jsx(Button, { onClick: () => void registrarRecebimento(), disabled: busy, "data-testid": "order-register-receipt", children: busy ? "Abrindo\u2026" : "Registrar recebimento" }),
|
|
68
|
+
hasFinancialRoute && /* @__PURE__ */ jsx(
|
|
69
|
+
"button",
|
|
70
|
+
{
|
|
71
|
+
type: "button",
|
|
72
|
+
onClick: () => adminNavigateTo("/financial"),
|
|
73
|
+
className: "rounded-md border px-3 py-1.5 text-sm font-medium transition hover:bg-muted",
|
|
74
|
+
children: "Abrir no Financeiro"
|
|
75
|
+
}
|
|
76
|
+
),
|
|
77
|
+
paying != null && /* @__PURE__ */ jsx(
|
|
78
|
+
ReceivePaymentModal,
|
|
79
|
+
{
|
|
80
|
+
installment: paying,
|
|
81
|
+
onClose: () => setPaying(null),
|
|
82
|
+
onPaid: () => {
|
|
83
|
+
setPaying(null);
|
|
84
|
+
void reload(true);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
)
|
|
88
|
+
] });
|
|
89
|
+
}
|
|
90
|
+
var VERB = {
|
|
91
|
+
confirmed: "Confirmar",
|
|
92
|
+
completed: "Concluir",
|
|
93
|
+
cancelled: "Cancelar pedido"
|
|
94
|
+
};
|
|
95
|
+
function StatusActions({ order, reload, options }) {
|
|
96
|
+
const next = useOrderKindTransitions(order.kind, order.status);
|
|
97
|
+
const [confirming, setConfirming] = React2__default.useState(false);
|
|
98
|
+
const [busy, setBusy] = React2__default.useState(false);
|
|
99
|
+
const [error, setError] = React2__default.useState(null);
|
|
100
|
+
const move = async (status) => {
|
|
101
|
+
const db = getSupabaseClientOptional();
|
|
102
|
+
if (!db) return;
|
|
103
|
+
setBusy(true);
|
|
104
|
+
setError(null);
|
|
105
|
+
try {
|
|
106
|
+
await setStatus({ db, tenantId: getActiveTenantId() ?? "", source: "orders:detail" }, order.id, status);
|
|
107
|
+
reload();
|
|
108
|
+
} catch (err) {
|
|
109
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
110
|
+
} finally {
|
|
111
|
+
setBusy(false);
|
|
112
|
+
setConfirming(false);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
const edit = options.editRoute;
|
|
116
|
+
const editable = edit && (options.canEditOrder ?? orderIsEditable)(order);
|
|
117
|
+
const actions = [
|
|
118
|
+
...next.filter((s) => s !== "cancelled" && VERB[s]).map((status, index) => ({
|
|
119
|
+
id: `status-${status}`,
|
|
120
|
+
testId: `order-status-${status}`,
|
|
121
|
+
label: VERB[status],
|
|
122
|
+
icon: Check,
|
|
123
|
+
intent: index === 0 ? "primary" : "secondary",
|
|
124
|
+
disabled: busy,
|
|
125
|
+
onSelect: () => {
|
|
126
|
+
void move(status);
|
|
127
|
+
}
|
|
128
|
+
})),
|
|
129
|
+
...editable ? [{
|
|
130
|
+
id: "edit",
|
|
131
|
+
testId: "order-edit",
|
|
132
|
+
label: "Editar pedido",
|
|
133
|
+
icon: Pencil,
|
|
134
|
+
intent: "secondary",
|
|
135
|
+
onSelect: () => adminNavigateTo(edit(order.id))
|
|
136
|
+
}] : [],
|
|
137
|
+
...next.includes("cancelled") ? [{
|
|
138
|
+
id: "cancel",
|
|
139
|
+
testId: "order-cancel",
|
|
140
|
+
label: VERB.cancelled,
|
|
141
|
+
icon: Ban,
|
|
142
|
+
intent: "danger",
|
|
143
|
+
disabled: busy,
|
|
144
|
+
onSelect: () => setConfirming(true)
|
|
145
|
+
}] : []
|
|
146
|
+
];
|
|
147
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
148
|
+
error && /* @__PURE__ */ jsx("span", { role: "alert", className: "text-xs text-destructive", children: error }),
|
|
149
|
+
actions.length > 0 && /* @__PURE__ */ jsx(PageActions, { actions }),
|
|
150
|
+
/* @__PURE__ */ jsx(
|
|
151
|
+
ConfirmDialog,
|
|
152
|
+
{
|
|
153
|
+
open: confirming,
|
|
154
|
+
title: `Cancelar o pedido ${order.referenceNumber}?`,
|
|
155
|
+
description: "O pedido sai da opera\xE7\xE3o e n\xE3o volta a ficar aberto.",
|
|
156
|
+
confirmLabel: "Cancelar pedido",
|
|
157
|
+
cancelLabel: "Voltar",
|
|
158
|
+
variant: "destructive",
|
|
159
|
+
loading: busy,
|
|
160
|
+
onConfirm: () => {
|
|
161
|
+
void move("cancelled");
|
|
162
|
+
},
|
|
163
|
+
onCancel: () => setConfirming(false)
|
|
164
|
+
}
|
|
165
|
+
)
|
|
166
|
+
] });
|
|
167
|
+
}
|
|
168
|
+
function OrderDetailRoute({ id, options }) {
|
|
169
|
+
if (!id) return null;
|
|
170
|
+
const generic = /* @__PURE__ */ jsx(
|
|
171
|
+
OrderDetailPage,
|
|
172
|
+
{
|
|
173
|
+
orderId: id,
|
|
174
|
+
backTo: "/orders",
|
|
175
|
+
actions: (order, { reload }) => /* @__PURE__ */ jsx(StatusActions, { order, reload, options }),
|
|
176
|
+
receivableActions: (order, ctx) => /* @__PURE__ */ jsx(
|
|
177
|
+
OrderReceivableActions,
|
|
178
|
+
{
|
|
179
|
+
orderId: order.id,
|
|
180
|
+
orderTotal: order.total ?? 0,
|
|
181
|
+
receivable: ctx.receivable,
|
|
182
|
+
reload: ctx.reload
|
|
183
|
+
}
|
|
184
|
+
)
|
|
185
|
+
}
|
|
186
|
+
);
|
|
187
|
+
const Owned = getComponent(ORDER_DETAIL_COMPONENT_ID);
|
|
188
|
+
return Owned ? /* @__PURE__ */ jsx(Owned, { orderId: id, onBack: () => adminNavigateTo("/orders"), fallback: generic }) : generic;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export { OrderDetailRoute };
|
|
192
|
+
//# sourceMappingURL=OrderDetailRoute-LTPDQXQU.js.map
|
|
193
|
+
//# sourceMappingURL=OrderDetailRoute-LTPDQXQU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/views/OrderReceivableActions.tsx","../src/views/OrderDetailRoute.tsx"],"names":["React","getSupabaseClientOptional","adminNavigateTo","jsxs","Fragment","jsx"],"mappings":"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","file":"OrderDetailRoute-LTPDQXQU.js","sourcesContent":["import * as React from 'react'\nimport { adminNavigateTo, usePermissionOptional, type OrderReceivable } from '@fayz-ai/admin'\nimport { getSupabaseClientOptional, usePluginRuntimeOptional, describeError } from '@fayz-ai/core'\nimport { ReceivePaymentModal } from '@fayz-ai/plugin-financial'\nimport { Button, toast } from '@fayz-ai/ui'\n\n// ---------------------------------------------------------------------------\n// \"Registrar recebimento\" na tela de um pedido.\n//\n// POR QUE ISTO EXISTE. O bloco \"Contas a receber\" ja era compartilhado e ja era\n// lido em todo produto que tem pedidos — mas ninguem preenchia o seam\n// `receivableActions`. Na pratica: a tela sabia dizer que o pedido nao tinha\n// conta a receber, e nao oferecia nenhuma forma de receber por ele.\n//\n// UM VERBO, NAO DOIS. A loja (plugin-shop) tem so \"Registrar recebimento\"\n// porque la o recebivel nasce no CHECKOUT. Aqui o pedido pode nunca ter sido\n// faturado — e a resposta NAO e um segundo botao \"Faturar\" com toast proprio.\n// Faturar e o primeiro passo do MESMO ato, e quem pergunta metodo, conta e data\n// e o modal do Financeiro, que ja existe e ja sabe fazer isso.\n//\n// Entao o clique e sempre o mesmo: se falta a fatura, levanta-se a fatura em\n// silencio e abre-se o modal na parcela que ela criou. O operador ve uma tela\n// so — a do Financeiro —, e nao um fluxo paralelo inventado aqui.\n//\n// A ESCRITA E A MESMA DOS OUTROS CAMINHOS. `fn_invoice_from_order` e a ponte que\n// o checkout da loja usa, alinhada com a da comanda na migration 004: o pedido\n// conserva o proprio `reference_number`, a parcela nasce com `unit_id`, e\n// `p_status` so e aplicado quando a especie o declara. O recebimento e\n// `financial_receive_payment`, dentro do modal. Nada aqui inventa uma segunda\n// forma de faturar nem uma segunda forma de receber.\n// ---------------------------------------------------------------------------\n\n/** A parcela como `ReceivePaymentModal` a quer — `v_financial_bills` expoe `installment_id AS id`. */\nfunction toModalInstallment(bill: Record<string, unknown>) {\n return {\n id: bill.id,\n amount: Number(bill.amount ?? 0),\n paidAmount: Number(bill.paid_amount ?? 0),\n installmentNumber: bill.installment_number ?? 1,\n direction: bill.direction ?? 'credit',\n dueDate: bill.due_date,\n invoiceId: bill.financial_invoice_id ?? bill.invoice_id,\n } as never\n}\n\n/** A primeira parcela que ainda tem saldo. */\nfunction firstOpenBill(receivable: OrderReceivable | null) {\n return receivable?.bills.find(\n (b) => Number((b as { paid_amount?: number }).paid_amount ?? 0) < Number(b.amount),\n )\n}\n\nexport interface OrderReceivableActionsProps {\n orderId: string\n /** O total do pedido — nao ha o que receber de um pedido que nao vale nada. */\n orderTotal: number\n receivable: OrderReceivable | null\n /** `force` porque faturar e receber precisam enxergar a propria escrita. */\n reload: (force?: boolean) => Promise<void>\n}\n\nexport function OrderReceivableActions({ orderId, orderTotal, receivable, reload }: OrderReceivableActionsProps) {\n const [busy, setBusy] = React.useState(false)\n const [paying, setPaying] = React.useState<unknown>(null)\n const can = usePermissionOptional()\n\n // \"Abrir no Financeiro\" precisa de uma ROTA existir, nao do id do plugin: um\n // app pode montar so as CONFIGURACOES do financeiro (createFinancialSettings-\n // Plugin declara o mesmo id e nao tem `/financial`), e o link levaria a uma\n // porta pintada na parede. Mesma checagem que a loja faz.\n const runtime = usePluginRuntimeOptional()\n const hasFinancialRoute = (runtime?.activePlugins ?? []).some(\n (p) => (p as { routes?: { path?: string }[] }).routes?.some((r) => r.path === '/financial'),\n )\n\n // O wrapper publico `fn_invoice_from_order` exige `financial.create` de QUEM\n // CHAMA — quem dispensa e o `_internal`, e ele nao e chamavel do navegador.\n // Sem este gate o botao existiria para um garcom e devolveria 42501 no clique.\n const canInvoice = can('financial', 'create')\n\n const balance = receivable ? Number(receivable.balance.balance ?? 0) : 0\n const cancelled = receivable?.balance.status === 'cancelled'\n const openBill = firstOpenBill(receivable)\n\n // Sem recebivel, o botao vale se a pessoa pode faturar E se ha o que faturar;\n // com recebivel, vale enquanto sobrar saldo.\n //\n // O guarda do total nao e teorico: um pedido novo, sem item, aceitou ser\n // faturado por R$ 0,00 e devolveu uma parcela que ja nascia quitada — fatura\n // de zero real no livro, e um erro para o operador logo depois. Faturar exige\n // ter valor, e essa e a checagem mais barata que existe.\n const canReceive = receivable\n ? balance > 0 && !cancelled && Boolean(openBill)\n : canInvoice && Number(orderTotal) > 0\n\n /**\n * Um clique, um modal. A fatura, quando falta, e levantada aqui e o modal\n * abre na parcela dela — o operador nao ve dois passos porque nao sao dois\n * atos.\n */\n async function registrarRecebimento() {\n if (receivable) {\n const bill = firstOpenBill(receivable)\n if (bill) setPaying(toModalInstallment(bill as unknown as Record<string, unknown>))\n return\n }\n\n const db = getSupabaseClientOptional() as unknown as {\n rpc: (fn: string, args: Record<string, unknown>) => Promise<{ error?: { message?: string } | null }>\n from: (t: string) => any\n } | null\n if (!db) return\n\n setBusy(true)\n try {\n const { error } = await db.rpc('fn_invoice_from_order', { p_order_id: orderId })\n if (error) throw new Error(error.message ?? 'Falha ao faturar o pedido')\n\n // A parcela recem-criada vem da MESMA view que o bloco le, e nao do\n // retorno da RPC: o modal precisa de `installment_id`, que e o que\n // `v_financial_bills` expoe, e ler daqui mantem os dois lados na mesma\n // fonte. `reload(true)` sozinho nao serve — ele atualiza o bloco depois,\n // e o modal precisa da parcela agora.\n const { data } = await db\n .from('v_financial_bills')\n .select('*')\n .eq('invoice_id', orderId)\n .order('installment_number', { ascending: true })\n const bill = (data ?? []).find(\n (b: { paid_amount?: number; amount?: number }) => Number(b.paid_amount ?? 0) < Number(b.amount ?? 0),\n )\n await reload(true)\n if (bill) setPaying(toModalInstallment(bill))\n else toast.error('Pedido faturado, mas nenhuma parcela em aberto foi encontrada')\n } catch (err: unknown) {\n toast.error(describeError(err, 'Falha ao faturar o pedido'))\n } finally {\n setBusy(false)\n }\n }\n\n return (\n <>\n {canReceive && (\n <Button onClick={() => void registrarRecebimento()} disabled={busy} data-testid=\"order-register-receipt\">\n {busy ? 'Abrindo…' : 'Registrar recebimento'}\n </Button>\n )}\n\n {hasFinancialRoute && (\n <button\n type=\"button\"\n onClick={() => adminNavigateTo('/financial')}\n className=\"rounded-md border px-3 py-1.5 text-sm font-medium transition hover:bg-muted\"\n >\n Abrir no Financeiro\n </button>\n )}\n\n {/* SEM gate de rota, e a distincao importa: o modal traz o proprio provider\n e store, entao o que ele precisa sao as TABELAS do financeiro, nao o\n plugin montado. Gatear aqui transformaria o botao num clique morto. */}\n {paying != null && (\n <ReceivePaymentModal\n installment={paying as never}\n onClose={() => setPaying(null)}\n onPaid={() => {\n setPaying(null)\n void reload(true)\n }}\n />\n )}\n </>\n )\n}\n","import React from 'react'\nimport { Ban, Check, Pencil } from 'lucide-react'\nimport {\n OrderDetailPage, PageActions, adminNavigateTo, orderIsEditable, useOrderKindTransitions,\n type OrderDetailRailOrder, type OrderReceivable,\n} from '@fayz-ai/admin'\nimport { ConfirmDialog } from '@fayz-ai/ui'\nimport { getActiveTenantId, getComponent, getSupabaseClientOptional } from '@fayz-ai/core'\nimport { setStatus } from '@fayz-ai/core/orders'\nimport { OrderReceivableActions } from './OrderReceivableActions'\nimport { ORDER_DETAIL_COMPONENT_ID, type OrderDetailSlotProps } from '../lib/detail-slot'\n\nexport interface OrderDetailRouteOptions {\n editRoute?: (orderId: string) => string\n canEditOrder?: (order: { status?: string }) => boolean\n}\n\nconst VERB: Record<string, string> = {\n confirmed: 'Confirmar',\n completed: 'Concluir',\n cancelled: 'Cancelar pedido',\n}\n\nfunction StatusActions({ order, reload, options }: {\n order: OrderDetailRailOrder\n reload: () => void\n options: OrderDetailRouteOptions\n}) {\n // The cluster's own machine: a hop it would refuse is never offered.\n const next = useOrderKindTransitions(order.kind, order.status)\n const [confirming, setConfirming] = React.useState(false)\n const [busy, setBusy] = React.useState(false)\n const [error, setError] = React.useState<string | null>(null)\n\n const move = async (status: string) => {\n const db = getSupabaseClientOptional()\n if (!db) return\n setBusy(true)\n setError(null)\n try {\n await setStatus({ db: db as never, tenantId: getActiveTenantId() ?? '', source: 'orders:detail' }, order.id, status)\n reload()\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err))\n } finally {\n setBusy(false)\n setConfirming(false)\n }\n }\n\n const edit = options.editRoute\n const editable = edit && (options.canEditOrder ?? orderIsEditable)(order)\n\n const actions = [\n ...next.filter((s) => s !== 'cancelled' && VERB[s]).map((status, index) => ({\n id: `status-${status}`,\n testId: `order-status-${status}`,\n label: VERB[status]!,\n icon: Check,\n intent: index === 0 ? 'primary' as const : 'secondary' as const,\n disabled: busy,\n onSelect: () => { void move(status) },\n })),\n ...(editable ? [{\n id: 'edit',\n testId: 'order-edit',\n label: 'Editar pedido',\n icon: Pencil,\n intent: 'secondary' as const,\n onSelect: () => adminNavigateTo(edit(order.id)),\n }] : []),\n ...(next.includes('cancelled') ? [{\n id: 'cancel',\n testId: 'order-cancel',\n label: VERB.cancelled!,\n icon: Ban,\n intent: 'danger' as const,\n disabled: busy,\n onSelect: () => setConfirming(true),\n }] : []),\n ]\n\n return (\n <>\n {error && <span role=\"alert\" className=\"text-xs text-destructive\">{error}</span>}\n {actions.length > 0 && <PageActions actions={actions} />}\n <ConfirmDialog\n open={confirming}\n title={`Cancelar o pedido ${order.referenceNumber}?`}\n description=\"O pedido sai da operação e não volta a ficar aberto.\"\n confirmLabel=\"Cancelar pedido\"\n cancelLabel=\"Voltar\"\n variant=\"destructive\"\n loading={busy}\n onConfirm={() => { void move('cancelled') }}\n onCancel={() => setConfirming(false)}\n />\n </>\n )\n}\n\nexport function OrderDetailRoute({ id, options }: { id?: string; options: OrderDetailRouteOptions }) {\n if (!id) return null\n\n const generic = (\n <OrderDetailPage\n orderId={id}\n backTo=\"/orders\"\n actions={(order, { reload }) => <StatusActions order={order} reload={reload} options={options} />}\n receivableActions={(\n order: { id: string; total?: number },\n ctx: { receivable: OrderReceivable | null; reload: (force?: boolean) => Promise<void> },\n ) => (\n <OrderReceivableActions\n orderId={order.id}\n orderTotal={order.total ?? 0}\n receivable={ctx.receivable}\n reload={ctx.reload}\n />\n )}\n />\n )\n\n const Owned = getComponent(ORDER_DETAIL_COMPONENT_ID) as React.ComponentType<OrderDetailSlotProps> | undefined\n return Owned\n ? <Owned orderId={id} onBack={() => adminNavigateTo('/orders')} fallback={generic} />\n : generic\n}\n"]}
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
import { createPluginContext, usePersistedState, formatCurrency, adminNavigateTo, orderChannelColumn, PaymentStatusBadge, OrderListView, PageActions, ORDER_CHANNEL_LABELS, ORDER_STAGES, ORDER_STAGE_COLORS, ORDER_STAGE_LABELS, orderStage, ORDER_STATUS_LABELS } from '@fayz-ai/admin';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { Plus } from 'lucide-react';
|
|
4
|
+
import { DateRangeChip, ListFilterBar } from '@fayz-ai/ui';
|
|
5
|
+
import { useTranslation } from '@fayz-ai/core';
|
|
6
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
7
|
+
|
|
8
|
+
// src/context.tsx
|
|
9
|
+
var ctx = createPluginContext("OrdersPage");
|
|
10
|
+
var OrdersContextProvider = ctx.ContextProvider;
|
|
11
|
+
var useOrdersConfig = ctx.useConfig;
|
|
12
|
+
var useOrdersProvider = ctx.useProvider;
|
|
13
|
+
ctx.useStore;
|
|
14
|
+
|
|
15
|
+
// src/lib/list-query.ts
|
|
16
|
+
var PERIOD_PRESETS = [
|
|
17
|
+
{ value: "today", label: "Hoje" },
|
|
18
|
+
{ value: "7d", label: "\xDAltimos 7 dias" },
|
|
19
|
+
{ value: "30d", label: "\xDAltimos 30 dias" },
|
|
20
|
+
{ value: "month", label: "Este m\xEAs" }
|
|
21
|
+
];
|
|
22
|
+
function ymd(date) {
|
|
23
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
24
|
+
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
|
|
25
|
+
}
|
|
26
|
+
function periodRange(preset, now = /* @__PURE__ */ new Date()) {
|
|
27
|
+
const to = ymd(now);
|
|
28
|
+
const back = (days) => {
|
|
29
|
+
const d = new Date(now);
|
|
30
|
+
d.setDate(d.getDate() - days);
|
|
31
|
+
return ymd(d);
|
|
32
|
+
};
|
|
33
|
+
if (preset === "today") return { from: to, to };
|
|
34
|
+
if (preset === "7d") return { from: back(6), to };
|
|
35
|
+
if (preset === "30d") return { from: back(29), to };
|
|
36
|
+
if (preset === "month") return { from: ymd(new Date(now.getFullYear(), now.getMonth(), 1)), to };
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
function toOrderQuery(filters, search, page, pageSize, now = /* @__PURE__ */ new Date()) {
|
|
40
|
+
const range = filters.preset === "custom" ? { from: filters.from, to: filters.to } : periodRange(filters.preset, now);
|
|
41
|
+
const from = range?.from ? (/* @__PURE__ */ new Date(`${range.from}T00:00:00`)).toISOString() : void 0;
|
|
42
|
+
const to = range?.to ? (/* @__PURE__ */ new Date(`${range.to}T23:59:59.999`)).toISOString() : void 0;
|
|
43
|
+
return {
|
|
44
|
+
...from || to ? { dateRange: { from: from ?? "1970-01-01T00:00:00.000Z", to: to ?? "9999-12-31T23:59:59.999Z" } } : {},
|
|
45
|
+
...filters.status ? { status: filters.status } : {},
|
|
46
|
+
...filters.channel ? { channel: filters.channel } : {},
|
|
47
|
+
...filters.fulfillment ? { fulfillmentStatus: filters.fulfillment } : {},
|
|
48
|
+
...search.trim() ? { search: search.trim() } : {},
|
|
49
|
+
// `orders` also holds what the account BUYS; this screen is what it sells.
|
|
50
|
+
excludeKinds: ["purchase"],
|
|
51
|
+
withItems: false,
|
|
52
|
+
page,
|
|
53
|
+
pageSize
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
var PAGE_SIZE = 50;
|
|
57
|
+
var DEFAULT_FILTERS = { preset: "30d", from: "", to: "" };
|
|
58
|
+
function meta(order) {
|
|
59
|
+
return order.metadata ?? {};
|
|
60
|
+
}
|
|
61
|
+
function stageOf(order) {
|
|
62
|
+
const m = meta(order);
|
|
63
|
+
return orderStage({
|
|
64
|
+
status: order.status,
|
|
65
|
+
channel: m.channel,
|
|
66
|
+
paymentStatus: m.paymentStatus,
|
|
67
|
+
fulfillmentStatus: m.fulfillmentStatus,
|
|
68
|
+
shipmentStatuses: m.shipmentStatuses
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
function StageBadge({ stage }) {
|
|
72
|
+
return /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1.5 text-sm", children: [
|
|
73
|
+
/* @__PURE__ */ jsx("span", { className: `h-2 w-2 rounded-full ${ORDER_STAGE_COLORS[stage]}` }),
|
|
74
|
+
ORDER_STAGE_LABELS[stage]
|
|
75
|
+
] });
|
|
76
|
+
}
|
|
77
|
+
var options = (labels) => Object.entries(labels).map(([value, label]) => ({ value, label }));
|
|
78
|
+
function OrdersScreen() {
|
|
79
|
+
const t = useTranslation();
|
|
80
|
+
const config = useOrdersConfig();
|
|
81
|
+
const provider = useOrdersProvider();
|
|
82
|
+
const [filters, setFilters] = usePersistedState("orders.filters", DEFAULT_FILTERS);
|
|
83
|
+
const [search, setSearch] = usePersistedState("orders.search", "");
|
|
84
|
+
const [page, setPage] = usePersistedState("orders.page", 1);
|
|
85
|
+
const [rows, setRows] = React.useState([]);
|
|
86
|
+
const [total, setTotal] = React.useState(0);
|
|
87
|
+
const [loading, setLoading] = React.useState(true);
|
|
88
|
+
const [error, setError] = React.useState(null);
|
|
89
|
+
const [term, setTerm] = React.useState(search);
|
|
90
|
+
React.useEffect(() => {
|
|
91
|
+
const id = setTimeout(() => setTerm(search), 300);
|
|
92
|
+
return () => clearTimeout(id);
|
|
93
|
+
}, [search]);
|
|
94
|
+
const patch = React.useCallback((next) => {
|
|
95
|
+
setFilters((current) => ({ ...current, ...next }));
|
|
96
|
+
setPage(1);
|
|
97
|
+
}, [setFilters, setPage]);
|
|
98
|
+
React.useEffect(() => {
|
|
99
|
+
let cancelled = false;
|
|
100
|
+
setLoading(true);
|
|
101
|
+
setError(null);
|
|
102
|
+
provider.getOrders(toOrderQuery(filters, term, page, PAGE_SIZE)).then((result) => {
|
|
103
|
+
if (cancelled) return;
|
|
104
|
+
setRows(result.data);
|
|
105
|
+
setTotal(result.total);
|
|
106
|
+
}).catch((err) => {
|
|
107
|
+
if (cancelled) return;
|
|
108
|
+
setRows([]);
|
|
109
|
+
setTotal(0);
|
|
110
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
111
|
+
}).finally(() => {
|
|
112
|
+
if (!cancelled) setLoading(false);
|
|
113
|
+
});
|
|
114
|
+
return () => {
|
|
115
|
+
cancelled = true;
|
|
116
|
+
};
|
|
117
|
+
}, [provider, filters, term, page]);
|
|
118
|
+
const money = React.useCallback(
|
|
119
|
+
// An order is printed in the currency it was sold in, not the app's.
|
|
120
|
+
(value, code) => formatCurrency(
|
|
121
|
+
value,
|
|
122
|
+
code && code !== config.currency.code ? { ...config.currency, code } : config.currency
|
|
123
|
+
),
|
|
124
|
+
[config.currency]
|
|
125
|
+
);
|
|
126
|
+
const open = React.useCallback((order) => {
|
|
127
|
+
adminNavigateTo(config.orderRoute?.(order.id) ?? `/orders/${order.id}`);
|
|
128
|
+
}, [config]);
|
|
129
|
+
const columns = React.useMemo(() => [
|
|
130
|
+
{
|
|
131
|
+
key: "reference",
|
|
132
|
+
header: t("orders.list.column.order"),
|
|
133
|
+
mobile: "title",
|
|
134
|
+
render: (o) => /* @__PURE__ */ jsx("span", { className: "font-medium", children: o.referenceNumber })
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
key: "date",
|
|
138
|
+
header: "Data",
|
|
139
|
+
render: (o) => new Date(o.createdAt).toLocaleDateString("pt-BR")
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
key: "customer",
|
|
143
|
+
header: t("orders.list.column.customer"),
|
|
144
|
+
render: (o) => o.partyName ?? /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "\u2014" })
|
|
145
|
+
},
|
|
146
|
+
orderChannelColumn((o) => meta(o).channel),
|
|
147
|
+
{
|
|
148
|
+
key: "payment",
|
|
149
|
+
header: "Recebimento",
|
|
150
|
+
render: (o) => {
|
|
151
|
+
const m = meta(o);
|
|
152
|
+
const status = m.paymentStatus ?? "none";
|
|
153
|
+
if (status === "none") return /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "\u2014" });
|
|
154
|
+
return /* @__PURE__ */ jsx(
|
|
155
|
+
PaymentStatusBadge,
|
|
156
|
+
{
|
|
157
|
+
status,
|
|
158
|
+
totalAmount: Number(m.invoicedAmount) || 0,
|
|
159
|
+
paidAmount: Number(m.paidAmount) || 0,
|
|
160
|
+
formatCurrency: (v) => money(v, o.currency)
|
|
161
|
+
}
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
{ key: "total", header: t("orders.list.column.total"), align: "right", render: (o) => money(o.total, o.currency) },
|
|
166
|
+
{
|
|
167
|
+
key: "stage",
|
|
168
|
+
header: "Situa\xE7\xE3o",
|
|
169
|
+
mobile: "badge",
|
|
170
|
+
render: (o) => /* @__PURE__ */ jsx(StageBadge, { stage: stageOf(o) })
|
|
171
|
+
}
|
|
172
|
+
], [t, money]);
|
|
173
|
+
const filterDefs = [
|
|
174
|
+
{
|
|
175
|
+
id: "status",
|
|
176
|
+
label: "Estado",
|
|
177
|
+
allLabel: "Todos os estados",
|
|
178
|
+
options: options(ORDER_STATUS_LABELS),
|
|
179
|
+
value: filters.status,
|
|
180
|
+
onChange: (status) => patch({ status })
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
id: "channel",
|
|
184
|
+
label: "Canal",
|
|
185
|
+
allLabel: "Todos os canais",
|
|
186
|
+
options: options(ORDER_CHANNEL_LABELS),
|
|
187
|
+
value: filters.channel,
|
|
188
|
+
onChange: (channel) => patch({ channel })
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
id: "fulfillment",
|
|
192
|
+
label: "Entrega",
|
|
193
|
+
allLabel: "Qualquer entrega",
|
|
194
|
+
options: [
|
|
195
|
+
{ value: "unfulfilled", label: "N\xE3o entregue" },
|
|
196
|
+
{ value: "partially_fulfilled", label: "Entrega parcial" },
|
|
197
|
+
{ value: "fulfilled", label: "Entregue" }
|
|
198
|
+
],
|
|
199
|
+
value: filters.fulfillment,
|
|
200
|
+
onChange: (fulfillment) => patch({ fulfillment })
|
|
201
|
+
}
|
|
202
|
+
];
|
|
203
|
+
const filterBar = /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-1.5", children: [
|
|
204
|
+
/* @__PURE__ */ jsx(
|
|
205
|
+
DateRangeChip,
|
|
206
|
+
{
|
|
207
|
+
label: "Per\xEDodo",
|
|
208
|
+
allLabel: "Todo o per\xEDodo",
|
|
209
|
+
labels: { from: "De", to: "At\xE9", clear: "Limpar" },
|
|
210
|
+
presets: PERIOD_PRESETS,
|
|
211
|
+
preset: filters.preset,
|
|
212
|
+
from: filters.preset === "custom" ? filters.from : periodRange(filters.preset)?.from ?? "",
|
|
213
|
+
to: filters.preset === "custom" ? filters.to : periodRange(filters.preset)?.to ?? "",
|
|
214
|
+
onPresetChange: (preset) => patch({ preset }),
|
|
215
|
+
onChange: ({ from, to }) => patch({ from, to })
|
|
216
|
+
}
|
|
217
|
+
),
|
|
218
|
+
/* @__PURE__ */ jsx(
|
|
219
|
+
ListFilterBar,
|
|
220
|
+
{
|
|
221
|
+
filters: filterDefs,
|
|
222
|
+
onClear: () => patch({ status: void 0, channel: void 0, fulfillment: void 0 })
|
|
223
|
+
}
|
|
224
|
+
)
|
|
225
|
+
] });
|
|
226
|
+
const createLabel = (() => {
|
|
227
|
+
const translated = t("orders.kanban.newOrder");
|
|
228
|
+
return !translated || translated === "orders.kanban.newOrder" ? "Criar pedido" : translated;
|
|
229
|
+
})();
|
|
230
|
+
return /* @__PURE__ */ jsx(
|
|
231
|
+
OrderListView,
|
|
232
|
+
{
|
|
233
|
+
title: config.labels.pageTitle,
|
|
234
|
+
viewKey: "orders",
|
|
235
|
+
views: ["list", "board"],
|
|
236
|
+
defaultView: "list",
|
|
237
|
+
board: {
|
|
238
|
+
columns: ORDER_STAGES.map((id) => ({ id, label: ORDER_STAGE_LABELS[id], color: ORDER_STAGE_COLORS[id] })),
|
|
239
|
+
columnOf: stageOf,
|
|
240
|
+
emptyColumn: "Nada aqui",
|
|
241
|
+
card: (o) => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
242
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center justify-between gap-2", children: [
|
|
243
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-bold", children: o.referenceNumber }),
|
|
244
|
+
/* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground", children: new Date(o.createdAt).toLocaleDateString("pt-BR") })
|
|
245
|
+
] }),
|
|
246
|
+
o.partyName && /* @__PURE__ */ jsx("p", { className: "truncate text-sm font-medium", children: o.partyName }),
|
|
247
|
+
/* @__PURE__ */ jsx("p", { className: "truncate text-xs text-muted-foreground", children: ORDER_CHANNEL_LABELS[String(meta(o).channel ?? "")] ?? "" }),
|
|
248
|
+
/* @__PURE__ */ jsx("div", { className: "mt-3 border-t pt-2 text-sm font-bold", children: money(o.total, o.currency) })
|
|
249
|
+
] })
|
|
250
|
+
},
|
|
251
|
+
columns,
|
|
252
|
+
rows,
|
|
253
|
+
loading,
|
|
254
|
+
empty: error ?? "Nenhum pedido neste recorte.",
|
|
255
|
+
search,
|
|
256
|
+
onSearchChange: (value) => {
|
|
257
|
+
setSearch(value);
|
|
258
|
+
setPage(1);
|
|
259
|
+
},
|
|
260
|
+
searchPlaceholder: "Buscar pedido\u2026",
|
|
261
|
+
filters: filterBar,
|
|
262
|
+
page,
|
|
263
|
+
total,
|
|
264
|
+
pageSize: PAGE_SIZE,
|
|
265
|
+
onPageChange: setPage,
|
|
266
|
+
mobileLayout: "cards",
|
|
267
|
+
onRowClick: open,
|
|
268
|
+
actions: config.createRoute ? /* @__PURE__ */ jsx(
|
|
269
|
+
PageActions,
|
|
270
|
+
{
|
|
271
|
+
actions: [{
|
|
272
|
+
id: "new-order",
|
|
273
|
+
label: createLabel,
|
|
274
|
+
icon: Plus,
|
|
275
|
+
intent: "primary",
|
|
276
|
+
creates: true,
|
|
277
|
+
testId: "orders-create",
|
|
278
|
+
onSelect: () => adminNavigateTo(config.createRoute)
|
|
279
|
+
}]
|
|
280
|
+
}
|
|
281
|
+
) : void 0
|
|
282
|
+
}
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
function OrdersPage({ config, provider, store }) {
|
|
286
|
+
return /* @__PURE__ */ jsx(OrdersContextProvider, { config, provider, store, children: /* @__PURE__ */ jsx(OrdersScreen, {}) });
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
export { OrdersPage };
|
|
290
|
+
//# sourceMappingURL=OrdersPage-5326V62H.js.map
|
|
291
|
+
//# sourceMappingURL=OrdersPage-5326V62H.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/context.tsx","../src/lib/list-query.ts","../src/views/OrdersScreen.tsx","../src/views/OrdersPage.tsx"],"names":["jsx"],"mappings":"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","file":"OrdersPage-5326V62H.js","sourcesContent":["import { createPluginContext, formatCurrency, type CurrencyConfig, type EntityLookup } from '@fayz-ai/admin'\nimport type { OrdersDataProvider } from './data/types'\nimport type { OrdersUIState } from './store'\nimport type { RestaurantOrder } from './types'\n\n// ---------------------------------------------------------------------------\n// Resolved config — fully merged, no optionals\n// ---------------------------------------------------------------------------\n\nexport interface OrdersModules {\n delivery: boolean\n takeout: boolean\n}\n\nexport type OrdersCurrency = CurrencyConfig\n\nexport interface OrderSourceOption {\n value: string\n label: string\n icon?: string\n}\n\nexport interface OrdersPluginLabels {\n pageTitle: string\n pageSubtitle: string\n orderSingular: string\n orderPlural: string\n}\n\nexport interface ResolvedOrdersConfig {\n modules: OrdersModules\n labels: OrdersPluginLabels\n currency: OrdersCurrency\n orderSources: OrderSourceOption[]\n menuItemLookup?: EntityLookup\n staffLookup?: EntityLookup\n onOrderCompleted?: (order: RestaurantOrder) => Promise<void>\n onOrderCancelled?: (order: RestaurantOrder) => Promise<void>\n /** Route the list's create action opens. Unset = the list offers none. */\n createRoute?: string\n orderRoute?: (orderId: string) => string\n editRoute?: (orderId: string) => string\n /** Whether this order still takes changes. Unset = it always does. */\n canEditOrder?: (order: { status?: string }) => boolean\n}\n\nconst ctx = createPluginContext<ResolvedOrdersConfig, OrdersDataProvider, OrdersUIState>('OrdersPage')\n\nexport const OrdersContextProvider = ctx.ContextProvider\nexport const useOrdersConfig = ctx.useConfig\nexport const useOrdersProvider = ctx.useProvider\nexport const useOrdersStore = ctx.useStore\n\nexport { formatCurrency }\n","import type { OrderQuery } from '../types'\n\nexport interface OrdersListFilters {\n /** One of PERIOD_PRESETS, `custom` (uses from/to) or `all`. */\n preset: string\n from: string\n to: string\n status?: string\n channel?: string\n fulfillment?: string\n}\n\nexport const PERIOD_PRESETS = [\n { value: 'today', label: 'Hoje' },\n { value: '7d', label: 'Últimos 7 dias' },\n { value: '30d', label: 'Últimos 30 dias' },\n { value: 'month', label: 'Este mês' },\n]\n\nfunction ymd(date: Date): string {\n const pad = (n: number) => String(n).padStart(2, '0')\n return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`\n}\n\n/** A preset as local calendar days. `null` for `all`, `custom` and anything unknown. */\nexport function periodRange(preset: string, now = new Date()): { from: string; to: string } | null {\n const to = ymd(now)\n const back = (days: number) => {\n const d = new Date(now)\n d.setDate(d.getDate() - days)\n return ymd(d)\n }\n if (preset === 'today') return { from: to, to }\n if (preset === '7d') return { from: back(6), to }\n if (preset === '30d') return { from: back(29), to }\n if (preset === 'month') return { from: ymd(new Date(now.getFullYear(), now.getMonth(), 1)), to }\n return null\n}\n\nexport function toOrderQuery(\n filters: OrdersListFilters, search: string, page: number, pageSize: number, now = new Date(),\n): OrderQuery {\n const range = filters.preset === 'custom'\n ? { from: filters.from, to: filters.to }\n : periodRange(filters.preset, now)\n // Local day bounds: `created_at <= 2026-10-13` would drop that whole day.\n const from = range?.from ? new Date(`${range.from}T00:00:00`).toISOString() : undefined\n const to = range?.to ? new Date(`${range.to}T23:59:59.999`).toISOString() : undefined\n return {\n ...(from || to ? { dateRange: { from: from ?? '1970-01-01T00:00:00.000Z', to: to ?? '9999-12-31T23:59:59.999Z' } } : {}),\n ...(filters.status ? { status: filters.status } : {}),\n ...(filters.channel ? { channel: filters.channel } : {}),\n ...(filters.fulfillment ? { fulfillmentStatus: filters.fulfillment } : {}),\n ...(search.trim() ? { search: search.trim() } : {}),\n // `orders` also holds what the account BUYS; this screen is what it sells.\n excludeKinds: ['purchase'],\n withItems: false,\n page,\n pageSize,\n }\n}\n","import React from 'react'\nimport { Plus } from 'lucide-react'\nimport {\n OrderListView, PageActions, PaymentStatusBadge, adminNavigateTo, usePersistedState,\n orderChannelColumn, orderStage,\n ORDER_CHANNEL_LABELS, ORDER_STAGES, ORDER_STAGE_COLORS, ORDER_STAGE_LABELS, ORDER_STATUS_LABELS,\n type OrderListColumn, type OrderStage,\n} from '@fayz-ai/admin'\nimport { DateRangeChip, ListFilterBar, type ListFilterDef } from '@fayz-ai/ui'\nimport { useTranslation } from '@fayz-ai/core'\nimport { useOrdersConfig, useOrdersProvider, formatCurrency } from '../context'\nimport { periodRange, PERIOD_PRESETS, toOrderQuery, type OrdersListFilters } from '../lib/list-query'\nimport type { RestaurantOrder } from '../types'\n\nconst PAGE_SIZE = 50\n\nconst DEFAULT_FILTERS: OrdersListFilters = { preset: '30d', from: '', to: '' }\n\ntype PaymentState = 'none' | 'pending' | 'partial' | 'paid' | 'overdue' | 'cancelled'\n\nfunction meta(order: RestaurantOrder): Record<string, unknown> {\n return (order.metadata ?? {}) as Record<string, unknown>\n}\n\nfunction stageOf(order: RestaurantOrder): OrderStage {\n const m = meta(order)\n return orderStage({\n status: order.status,\n channel: m.channel as string | null,\n paymentStatus: m.paymentStatus as string | null,\n fulfillmentStatus: m.fulfillmentStatus as string | null,\n shipmentStatuses: m.shipmentStatuses as string[] | undefined,\n })\n}\n\nfunction StageBadge({ stage }: { stage: OrderStage }) {\n return (\n <span className=\"inline-flex items-center gap-1.5 text-sm\">\n <span className={`h-2 w-2 rounded-full ${ORDER_STAGE_COLORS[stage]}`} />\n {ORDER_STAGE_LABELS[stage]}\n </span>\n )\n}\n\nconst options = (labels: Record<string, string>) =>\n Object.entries(labels).map(([value, label]) => ({ value, label }))\n\nexport function OrdersScreen() {\n const t = useTranslation()\n const config = useOrdersConfig()\n const provider = useOrdersProvider()\n\n const [filters, setFilters] = usePersistedState<OrdersListFilters>('orders.filters', DEFAULT_FILTERS)\n const [search, setSearch] = usePersistedState('orders.search', '')\n const [page, setPage] = usePersistedState('orders.page', 1)\n\n const [rows, setRows] = React.useState<RestaurantOrder[]>([])\n const [total, setTotal] = React.useState(0)\n const [loading, setLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n\n // Typing must not fire a query per key.\n const [term, setTerm] = React.useState(search)\n React.useEffect(() => {\n const id = setTimeout(() => setTerm(search), 300)\n return () => clearTimeout(id)\n }, [search])\n\n const patch = React.useCallback((next: Partial<OrdersListFilters>) => {\n setFilters((current) => ({ ...current, ...next }))\n setPage(1)\n }, [setFilters, setPage])\n\n React.useEffect(() => {\n let cancelled = false\n setLoading(true)\n setError(null)\n provider.getOrders(toOrderQuery(filters, term, page, PAGE_SIZE))\n .then((result) => {\n if (cancelled) return\n setRows(result.data)\n setTotal(result.total)\n })\n .catch((err: unknown) => {\n if (cancelled) return\n setRows([])\n setTotal(0)\n setError(err instanceof Error ? err.message : String(err))\n })\n .finally(() => { if (!cancelled) setLoading(false) })\n return () => { cancelled = true }\n }, [provider, filters, term, page])\n\n const money = React.useCallback(\n // An order is printed in the currency it was sold in, not the app's.\n (value: number, code?: string) => formatCurrency(\n value,\n code && code !== config.currency.code ? { ...config.currency, code } : config.currency,\n ),\n [config.currency],\n )\n\n const open = React.useCallback((order: RestaurantOrder) => {\n adminNavigateTo(config.orderRoute?.(order.id) ?? `/orders/${order.id}`)\n }, [config])\n\n const columns: OrderListColumn<RestaurantOrder>[] = React.useMemo(() => [\n {\n key: 'reference',\n header: t('orders.list.column.order'),\n mobile: 'title',\n render: (o) => <span className=\"font-medium\">{o.referenceNumber}</span>,\n },\n {\n key: 'date',\n header: 'Data',\n render: (o) => new Date(o.createdAt).toLocaleDateString('pt-BR'),\n },\n {\n key: 'customer',\n header: t('orders.list.column.customer'),\n render: (o) => o.partyName ?? <span className=\"text-muted-foreground\">—</span>,\n },\n orderChannelColumn<RestaurantOrder>((o) => meta(o).channel as string | undefined),\n {\n key: 'payment',\n header: 'Recebimento',\n render: (o) => {\n const m = meta(o)\n const status = (m.paymentStatus as PaymentState | undefined) ?? 'none'\n if (status === 'none') return <span className=\"text-muted-foreground\">—</span>\n return (\n <PaymentStatusBadge\n status={status}\n totalAmount={Number(m.invoicedAmount) || 0}\n paidAmount={Number(m.paidAmount) || 0}\n formatCurrency={(v: number) => money(v, o.currency)}\n />\n )\n },\n },\n { key: 'total', header: t('orders.list.column.total'), align: 'right', render: (o) => money(o.total, o.currency) },\n {\n key: 'stage',\n header: 'Situação',\n mobile: 'badge',\n render: (o) => <StageBadge stage={stageOf(o)} />,\n },\n ], [t, money])\n\n const filterDefs: ListFilterDef[] = [\n {\n id: 'status',\n label: 'Estado',\n allLabel: 'Todos os estados',\n options: options(ORDER_STATUS_LABELS),\n value: filters.status,\n onChange: (status) => patch({ status }),\n },\n {\n id: 'channel',\n label: 'Canal',\n allLabel: 'Todos os canais',\n options: options(ORDER_CHANNEL_LABELS),\n value: filters.channel,\n onChange: (channel) => patch({ channel }),\n },\n {\n id: 'fulfillment',\n label: 'Entrega',\n allLabel: 'Qualquer entrega',\n options: [\n { value: 'unfulfilled', label: 'Não entregue' },\n { value: 'partially_fulfilled', label: 'Entrega parcial' },\n { value: 'fulfilled', label: 'Entregue' },\n ],\n value: filters.fulfillment,\n onChange: (fulfillment) => patch({ fulfillment }),\n },\n ]\n\n const filterBar = (\n <div className=\"flex min-w-0 items-center gap-1.5\">\n <DateRangeChip\n label=\"Período\"\n allLabel=\"Todo o período\"\n labels={{ from: 'De', to: 'Até', clear: 'Limpar' }}\n presets={PERIOD_PRESETS}\n preset={filters.preset}\n from={filters.preset === 'custom' ? filters.from : (periodRange(filters.preset)?.from ?? '')}\n to={filters.preset === 'custom' ? filters.to : (periodRange(filters.preset)?.to ?? '')}\n onPresetChange={(preset) => patch({ preset })}\n onChange={({ from, to }) => patch({ from, to })}\n />\n <ListFilterBar\n filters={filterDefs}\n onClear={() => patch({ status: undefined, channel: undefined, fulfillment: undefined })}\n />\n </div>\n )\n\n const createLabel = (() => {\n const translated = t('orders.kanban.newOrder')\n return !translated || translated === 'orders.kanban.newOrder' ? 'Criar pedido' : translated\n })()\n\n return (\n <OrderListView<RestaurantOrder>\n title={config.labels.pageTitle}\n viewKey=\"orders\"\n views={['list', 'board']}\n defaultView=\"list\"\n board={{\n columns: ORDER_STAGES.map((id) => ({ id, label: ORDER_STAGE_LABELS[id], color: ORDER_STAGE_COLORS[id] })),\n columnOf: stageOf,\n emptyColumn: 'Nada aqui',\n card: (o) => (\n <>\n <div className=\"mb-2 flex items-center justify-between gap-2\">\n <span className=\"text-sm font-bold\">{o.referenceNumber}</span>\n <span className=\"text-[10px] text-muted-foreground\">\n {new Date(o.createdAt).toLocaleDateString('pt-BR')}\n </span>\n </div>\n {o.partyName && <p className=\"truncate text-sm font-medium\">{o.partyName}</p>}\n <p className=\"truncate text-xs text-muted-foreground\">\n {ORDER_CHANNEL_LABELS[String(meta(o).channel ?? '')] ?? ''}\n </p>\n <div className=\"mt-3 border-t pt-2 text-sm font-bold\">{money(o.total, o.currency)}</div>\n </>\n ),\n }}\n columns={columns}\n rows={rows}\n loading={loading}\n empty={error ?? 'Nenhum pedido neste recorte.'}\n search={search}\n onSearchChange={(value) => { setSearch(value); setPage(1) }}\n searchPlaceholder=\"Buscar pedido…\"\n filters={filterBar}\n page={page}\n total={total}\n pageSize={PAGE_SIZE}\n onPageChange={setPage}\n mobileLayout=\"cards\"\n onRowClick={open}\n actions={config.createRoute ? (\n <PageActions\n actions={[{\n id: 'new-order',\n label: createLabel,\n icon: Plus,\n intent: 'primary' as const,\n creates: true,\n testId: 'orders-create',\n onSelect: () => adminNavigateTo(config.createRoute as string),\n }]}\n />\n ) : undefined}\n />\n )\n}\n","import React from 'react'\nimport type { StoreApi } from 'zustand/vanilla'\nimport { OrdersContextProvider, type ResolvedOrdersConfig } from '../context'\nimport { OrdersScreen } from './OrdersScreen'\nimport type { OrdersDataProvider } from '../data/types'\nimport type { OrdersUIState } from '../store'\nimport type { PluginRegistryDef } from '@fayz-ai/core'\n\nexport function OrdersPage({ config, provider, store }: {\n config: ResolvedOrdersConfig\n provider: OrdersDataProvider\n store: StoreApi<OrdersUIState>\n registries?: PluginRegistryDef[]\n}) {\n return (\n <OrdersContextProvider config={config} provider={provider} store={store}>\n <OrdersScreen />\n </OrdersContextProvider>\n )\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/detail-slot.ts"],"names":[],"mappings":";AAOO,IAAM,yBAAA,GAA4B","file":"chunk-YVC7R552.js","sourcesContent":["import type React from 'react'\n\n/**\n * A product that owns part of the orders (a shop, with shipments and a\n * checkout) registers its own detail page under this id. It must render\n * `fallback` for any order it does not own.\n */\nexport const ORDER_DETAIL_COMPONENT_ID = 'orders.detail'\n\nexport interface OrderDetailSlotProps {\n orderId: string\n onBack: () => void\n fallback: React.ReactNode\n}\n"]}
|
package/dist/context.d.ts
CHANGED
|
@@ -35,52 +35,6 @@ export interface ResolvedOrdersConfig {
|
|
|
35
35
|
canEditOrder?: (order: {
|
|
36
36
|
status?: string;
|
|
37
37
|
}) => boolean;
|
|
38
|
-
/**
|
|
39
|
-
* Whether the floor-plan tab is offered when one is registered.
|
|
40
|
-
*
|
|
41
|
-
* A restaurant that runs its salão on an operator surface (ChefControl's
|
|
42
|
-
* Balcão) already answers "onde a comanda está sentada" there, and the tab
|
|
43
|
-
* becomes a second, colder copy of the same room inside the back office.
|
|
44
|
-
*/
|
|
45
|
-
floorView: boolean;
|
|
46
|
-
/**
|
|
47
|
-
* Whether the QUADRO tab — the during-service board — is offered.
|
|
48
|
-
*
|
|
49
|
-
* It was the one view no app could turn off, because every app that mounted
|
|
50
|
-
* this plugin was a restaurant. A commercial order is a document: it has a
|
|
51
|
-
* customer, a total and a state, and no kitchen advancing it column by
|
|
52
|
-
* column.
|
|
53
|
-
*/
|
|
54
|
-
boardView: boolean;
|
|
55
|
-
/**
|
|
56
|
-
* This screen, opened straight onto one board and with no tabs.
|
|
57
|
-
*
|
|
58
|
-
* For an app that gives a board its own rail entry — "Operação · Delivery" is
|
|
59
|
-
* a place, not a tab you have to know to click. The tabs go because the
|
|
60
|
-
* destination IS the board: leaving them turns one rail row into three.
|
|
61
|
-
*/
|
|
62
|
-
pinnedView?: 'quadro' | 'salao' | 'delivery';
|
|
63
|
-
/**
|
|
64
|
-
* The delivery board has a rail entry of its own (see `deliveryRoute`).
|
|
65
|
-
*
|
|
66
|
-
* When it does, the tab on /orders is the same board reachable a second way,
|
|
67
|
-
* one click deeper — and the rail row stops being the way in. Same reasoning
|
|
68
|
-
* as `floorView`: a board that became a place stops being a tab.
|
|
69
|
-
*/
|
|
70
|
-
deliveryRoute?: string;
|
|
71
|
-
/**
|
|
72
|
-
* What the detail panel is FOR.
|
|
73
|
-
*
|
|
74
|
-
* `operate` (default) is the panel that runs the order: add items, advance
|
|
75
|
-
* the status, cancel. `inspect` only shows it.
|
|
76
|
-
*
|
|
77
|
-
* The difference is which surface owns the service. An app with an operator
|
|
78
|
-
* screen (ChefControl's Balcão) already has one place where a comanda gains
|
|
79
|
-
* an item and gets settled; a second, colder copy of those verbs inside the
|
|
80
|
-
* back office is how the same comanda ends up written from two hands with
|
|
81
|
-
* two different sets of rules.
|
|
82
|
-
*/
|
|
83
|
-
detailRail: 'operate' | 'inspect';
|
|
84
38
|
}
|
|
85
39
|
export declare const OrdersContextProvider: import("react").FC<{
|
|
86
40
|
config: ResolvedOrdersConfig;
|