@fayz-ai/plugin-shop 0.8.3 → 0.8.4

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.
@@ -34,49 +34,9 @@ function shopCustomerLookup(provider) {
34
34
  }
35
35
  };
36
36
  }
37
- var RECEIVABLE_LABEL = {
38
- open: "Em aberto",
39
- partial: "Parcialmente recebido",
40
- paid: "Recebido",
41
- overdue: "Vencido",
42
- cancelled: "Cancelado"
43
- };
44
- var RECEIVABLE_TONE = {
45
- open: "bg-blue-100 text-blue-800",
46
- partial: "bg-yellow-100 text-yellow-800",
47
- paid: "bg-emerald-100 text-emerald-800",
48
- overdue: "bg-red-100 text-red-700",
49
- cancelled: "bg-gray-100 text-gray-700"
50
- };
51
- var SHIPMENT_LABEL = {
52
- pending: "Aguardando coleta",
53
- in_transit: "Em tr\xE2nsito",
54
- delivered: "Entregue",
55
- failed: "Falhou",
56
- returned: "Devolvido",
57
- cancelled: "Cancelado"
58
- };
59
37
  var money = (v, currency2 = "BRL") => new Intl.NumberFormat("pt-BR", { style: "currency", currency: currency2 }).format(Number(v) || 0);
60
- var dateTime = (iso) => new Intl.DateTimeFormat("pt-BR", {
61
- day: "2-digit",
62
- month: "2-digit",
63
- year: "numeric",
64
- hour: "2-digit",
65
- minute: "2-digit"
66
- }).format(new Date(iso));
67
- var TONE = {
68
- paid: "bg-emerald-100 text-emerald-800",
69
- pending: "bg-yellow-100 text-yellow-800",
70
- refunded: "bg-orange-100 text-orange-700",
71
- partially_refunded: "bg-orange-100 text-orange-700",
72
- voided: "bg-gray-100 text-gray-700",
73
- fulfilled: "bg-emerald-100 text-emerald-800",
74
- unfulfilled: "bg-gray-100 text-gray-700",
75
- partially_fulfilled: "bg-blue-100 text-blue-800",
76
- open: "bg-blue-100 text-blue-800",
77
- cancelled: "bg-red-100 text-red-700",
78
- archived: "bg-gray-100 text-gray-700"
79
- };
38
+ var dateTime = (iso) => new Intl.DateTimeFormat("pt-BR", { day: "2-digit", month: "2-digit", year: "numeric", hour: "2-digit", minute: "2-digit" }).format(new Date(iso));
39
+ var dateOnly = (iso) => new Date(iso).toLocaleDateString("pt-BR");
80
40
  var PAYMENT_LABEL = {
81
41
  pix: "Pix",
82
42
  credit_card: "Cart\xE3o de cr\xE9dito",
@@ -98,85 +58,89 @@ var LABEL = {
98
58
  cancelled: "Cancelado",
99
59
  archived: "Arquivado"
100
60
  };
101
- function Badge({ value }) {
102
- return /* @__PURE__ */ jsxRuntime.jsx("span", { className: `inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${TONE[value] ?? TONE.open}`, children: LABEL[value] ?? value });
103
- }
104
- function Block({ title, hint, children }) {
105
- return /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { children: /* @__PURE__ */ jsxRuntime.jsxs(ui.CardContent, { className: "pt-4", children: [
106
- /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-sm font-semibold", children: title }),
107
- hint && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-0.5 text-xs text-muted-foreground", children: hint }),
108
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3", children })
109
- ] }) });
61
+ var RECEIVABLE_LABEL = {
62
+ open: "Em aberto",
63
+ partial: "Parcialmente recebido",
64
+ paid: "Recebido",
65
+ overdue: "Vencido",
66
+ cancelled: "Cancelado"
67
+ };
68
+ var SHIPMENT_LABEL = {
69
+ pending: "Aguardando coleta",
70
+ in_transit: "Em tr\xE2nsito",
71
+ delivered: "Entregue",
72
+ failed: "Falhou",
73
+ returned: "Devolvido",
74
+ cancelled: "Cancelado"
75
+ };
76
+ function toneOf(value) {
77
+ switch (value) {
78
+ case "paid":
79
+ case "fulfilled":
80
+ case "delivered":
81
+ return "success";
82
+ case "pending":
83
+ case "partial":
84
+ case "partially_fulfilled":
85
+ case "open":
86
+ case "in_transit":
87
+ return "warning";
88
+ case "refunded":
89
+ case "partially_refunded":
90
+ case "voided":
91
+ case "cancelled":
92
+ case "overdue":
93
+ case "failed":
94
+ case "returned":
95
+ return "destructive";
96
+ default:
97
+ return "muted";
98
+ }
110
99
  }
111
- function Row({ label, value, strong }) {
112
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex items-baseline justify-between gap-4 py-1 ${strong ? "font-semibold" : ""}`, children: [
113
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: strong ? "" : "text-muted-foreground", children: label }),
114
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums", children: value })
115
- ] });
100
+ function InlineBadge({ value }) {
101
+ const tone = toneOf(value);
102
+ const cls = {
103
+ success: "bg-emerald-100 text-emerald-800",
104
+ warning: "bg-amber-100 text-amber-800",
105
+ destructive: "bg-red-100 text-red-700",
106
+ info: "bg-sky-100 text-sky-800",
107
+ muted: "bg-muted text-muted-foreground"
108
+ };
109
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: `inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${cls[tone]}`, children: LABEL[value] ?? value });
116
110
  }
117
111
  function deliveryFromNotes(notes) {
118
112
  if (!notes) return null;
119
113
  const match = notes.match(/entrega:\s*(.+)/i);
120
114
  return (match?.[1] ?? "").trim() || null;
121
115
  }
122
- function BlockSkeleton({ rows }) {
123
- return /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { children: /* @__PURE__ */ jsxRuntime.jsxs(ui.CardContent, { className: "pt-4", children: [
124
- /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-4 w-28" }),
125
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-4 space-y-2.5", children: Array.from({ length: rows }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: `h-3 ${i % 3 === 2 ? "w-1/2" : i % 3 === 1 ? "w-2/3" : "w-full"}` }, i)) })
126
- ] }) });
127
- }
128
- function OrderDetailSkeleton() {
129
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", "aria-busy": "true", "aria-live": "polite", children: [
130
- /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-4 w-20" }),
131
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [
132
- /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-8 w-48" }),
133
- /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-5 w-20 rounded-full" }),
134
- /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-5 w-24 rounded-full" }),
135
- /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-4 w-32" })
136
- ] }),
137
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-4 lg:grid-cols-3", children: [
138
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4 lg:col-span-2", children: [
139
- /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { children: /* @__PURE__ */ jsxRuntime.jsxs(ui.CardContent, { className: "pt-4", children: [
140
- /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-4 w-16" }),
141
- /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "mt-1.5 h-3 w-24" }),
142
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3 divide-y", children: Array.from({ length: 3 }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 py-2", children: [
143
- /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-10 w-10 shrink-0 rounded" }),
144
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1 space-y-1.5", children: [
145
- /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-3.5 w-2/5" }),
146
- /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-2.5 w-20" })
147
- ] }),
148
- /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-3 w-24" }),
149
- /* @__PURE__ */ jsxRuntime.jsx(ui.Skeleton, { className: "h-3 w-16" })
150
- ] }, i)) })
151
- ] }) }),
152
- /* @__PURE__ */ jsxRuntime.jsx(BlockSkeleton, { rows: 6 })
153
- ] }),
154
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
155
- /* @__PURE__ */ jsxRuntime.jsx(BlockSkeleton, { rows: 2 }),
156
- /* @__PURE__ */ jsxRuntime.jsx(BlockSkeleton, { rows: 4 }),
157
- /* @__PURE__ */ jsxRuntime.jsx(BlockSkeleton, { rows: 3 })
158
- ] })
159
- ] })
160
- ] });
161
- }
162
- function OrderDetailView({
163
- orderId,
164
- provider,
165
- onBack
166
- }) {
167
- const [order, setOrder] = react.useState(null);
168
- const [shipments, setShipments] = react.useState([]);
169
- const [loading, setLoading] = react.useState(true);
116
+ var shopOrderCache = /* @__PURE__ */ new Map();
117
+ var shopShipmentsCache = /* @__PURE__ */ new Map();
118
+ var shopReceivableCache = /* @__PURE__ */ new Map();
119
+ function OrderDetailView({ orderId, provider, onBack }) {
120
+ const [order, setOrder] = react.useState(() => shopOrderCache.get(orderId) ?? null);
121
+ const [shipments, setShipments] = react.useState(() => shopShipmentsCache.get(orderId) ?? []);
122
+ const [loading, setLoading] = react.useState(() => !shopOrderCache.has(orderId));
170
123
  const [error, setError] = react.useState(null);
171
124
  const [confirming, setConfirming] = react.useState(false);
172
125
  const [confirmError, setConfirmError] = react.useState(null);
173
- const [receivable, setReceivable] = react.useState(null);
126
+ const [receivable, setReceivable] = react.useState(() => shopReceivableCache.get(orderId) ?? null);
174
127
  react.useEffect(() => {
175
128
  let cancelled = false;
129
+ const cached = shopOrderCache.get(orderId);
130
+ if (cached) {
131
+ setOrder(cached);
132
+ setLoading(false);
133
+ return () => {
134
+ cancelled = true;
135
+ };
136
+ }
176
137
  setLoading(true);
177
138
  setError(null);
178
139
  provider().getOrder(orderId).then((o) => {
179
- if (!cancelled) setOrder(o);
140
+ if (!cancelled) {
141
+ if (o) shopOrderCache.set(orderId, o);
142
+ setOrder(o);
143
+ }
180
144
  }).catch((err) => {
181
145
  if (!cancelled) setError(err instanceof Error ? err.message : String(err));
182
146
  }).finally(() => {
@@ -190,8 +154,14 @@ function OrderDetailView({
190
154
  let cancelled = false;
191
155
  const db = core.getSupabaseClientOptional();
192
156
  if (!db) return;
193
- db.from("fulfillments").select("*").eq("order_id", orderId).order("created_at", { ascending: false }).then(({ data }) => {
194
- if (!cancelled) setShipments(data ?? []);
157
+ if (shopShipmentsCache.has(orderId)) return () => {
158
+ cancelled = true;
159
+ };
160
+ db.from("fulfillments").select("*").eq("order_id", orderId).order("created_at", { ascending: false }).then(({ data: data2 }) => {
161
+ if (!cancelled) {
162
+ shopShipmentsCache.set(orderId, data2 ?? []);
163
+ setShipments(data2 ?? []);
164
+ }
195
165
  });
196
166
  return () => {
197
167
  cancelled = true;
@@ -201,19 +171,27 @@ function OrderDetailView({
201
171
  let cancelled = false;
202
172
  const db = core.getSupabaseClientOptional();
203
173
  if (!db) return;
174
+ if (shopReceivableCache.has(orderId)) {
175
+ setReceivable(shopReceivableCache.get(orderId) ?? null);
176
+ return () => {
177
+ cancelled = true;
178
+ };
179
+ }
204
180
  void (async () => {
205
181
  const [balance, bills] = await Promise.all([
206
182
  db.from("v_invoice_balances").select("*").eq("invoice_id", orderId).maybeSingle(),
207
183
  db.from("plg_financial_movements").select("*").eq("invoice_id", orderId).eq("movement_kind", "bill").order("installment_number", { ascending: true })
208
184
  ]);
209
185
  if (cancelled || !balance?.data) return;
210
- setReceivable({ balance: balance.data, bills: bills?.data ?? [] });
186
+ const rec = { balance: balance.data, bills: bills?.data ?? [] };
187
+ shopReceivableCache.set(orderId, rec);
188
+ setReceivable(rec);
211
189
  })();
212
190
  return () => {
213
191
  cancelled = true;
214
192
  };
215
193
  }, [orderId, confirming]);
216
- if (loading) return /* @__PURE__ */ jsxRuntime.jsx(OrderDetailSkeleton, {});
194
+ if (loading) return /* @__PURE__ */ jsxRuntime.jsx(saas.OrderDetailSkeleton, {});
217
195
  if (error) {
218
196
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-800", children: [
219
197
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium", children: "N\xE3o foi poss\xEDvel carregar o pedido." }),
@@ -221,188 +199,157 @@ function OrderDetailView({
221
199
  ] });
222
200
  }
223
201
  if (!order) return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-12 text-center text-sm text-muted-foreground", children: "Pedido n\xE3o encontrado." });
202
+ const cur = order.currency;
224
203
  const delivery = deliveryFromNotes(order.notes);
225
204
  const addr = order.shippingAddress;
226
205
  async function registerReceipt() {
227
206
  if (!order) return;
207
+ shopReceivableCache.delete(order.id);
228
208
  setConfirming(true);
229
209
  setConfirmError(null);
230
210
  try {
231
- const updated = await provider().confirmPayment?.(order.id);
232
- if (updated) setOrder(updated);
233
- else setOrder(await provider().getOrder(order.id));
211
+ const fresh = await provider().confirmPayment?.(order.id) ?? await provider().getOrder(order.id);
212
+ if (fresh) {
213
+ shopOrderCache.set(order.id, fresh);
214
+ setOrder(fresh);
215
+ }
234
216
  } catch (err) {
235
217
  setConfirmError(err instanceof Error ? err.message : String(err));
236
218
  } finally {
237
219
  setConfirming(false);
238
220
  }
239
221
  }
240
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
241
- /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: onBack, className: "text-sm text-muted-foreground hover:text-foreground", children: "\u2190 Pedidos" }),
242
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [
243
- /* @__PURE__ */ jsxRuntime.jsxs("h1", { className: "text-2xl font-semibold", children: [
244
- "Pedido #",
245
- order.orderNumber
246
- ] }),
247
- /* @__PURE__ */ jsxRuntime.jsx(Badge, { value: order.financialStatus }),
248
- /* @__PURE__ */ jsxRuntime.jsx(Badge, { value: order.fulfillmentStatus }),
249
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground", children: dateTime(order.createdAt) })
250
- ] }),
251
- confirmError && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "rounded-md border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-800", children: [
252
- "N\xE3o foi poss\xEDvel confirmar o pagamento: ",
253
- confirmError
222
+ const installments = receivable && receivable.bills.length > 1 ? receivable.bills.map((b) => ({
223
+ number: b.installment_number ?? 0,
224
+ amount: `${money(Number(b.paid_amount ?? 0), cur)} / ${money(Number(b.amount), cur)}`,
225
+ status: RECEIVABLE_LABEL[b.status] ?? b.status,
226
+ statusTone: toneOf(b.status),
227
+ dueDate: `vence ${dateOnly(b.due_date)}`
228
+ })) : [];
229
+ const data = {
230
+ title: `Pedido #${order.orderNumber}`,
231
+ subtitle: dateTime(order.createdAt),
232
+ badges: [
233
+ { label: LABEL[order.financialStatus] ?? order.financialStatus, tone: toneOf(order.financialStatus) },
234
+ { label: LABEL[order.fulfillmentStatus] ?? order.fulfillmentStatus, tone: toneOf(order.fulfillmentStatus) }
235
+ ],
236
+ customer: { name: order.customerName, email: order.customerEmail },
237
+ customerNode: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1 text-sm", children: [
238
+ order.customerId ? /* @__PURE__ */ jsxRuntime.jsx(
239
+ saas.PersonLink,
240
+ {
241
+ personId: order.customerId,
242
+ name: order.customerName ?? order.customerEmail ?? "Cliente",
243
+ lookup: shopCustomerLookup(provider),
244
+ profileHref: `#/customers/${order.customerId}`,
245
+ className: "font-medium"
246
+ }
247
+ ) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium", children: order.customerName ?? "\u2014" }),
248
+ order.customerEmail && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground", children: order.customerEmail }),
249
+ !order.customerId && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "Compra sem cadastro \u2014 n\xE3o h\xE1 ficha de cliente para abrir." })
254
250
  ] }),
255
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-4 lg:grid-cols-3", children: [
256
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4 lg:col-span-2", children: [
257
- /* @__PURE__ */ jsxRuntime.jsx(Block, { title: "Itens", hint: `${order.items.length} item(ns)`, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y", children: order.items.map((item) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 py-2", children: [
258
- item.imageUrl ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: item.imageUrl, alt: "", className: "h-10 w-10 shrink-0 rounded object-cover" }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-10 w-10 shrink-0 rounded bg-muted" }),
259
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
260
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate text-sm font-medium", children: item.name }),
261
- item.sku && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: item.sku })
262
- ] }),
263
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm text-muted-foreground", children: [
264
- item.quantity,
265
- " \xD7 ",
266
- money(item.unitPrice, order.currency)
267
- ] }),
268
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-24 text-right text-sm font-medium tabular-nums", children: money(item.total, order.currency) })
269
- ] }, item.id)) }) }),
270
- /* @__PURE__ */ jsxRuntime.jsx(Block, { title: "Pagamento", hint: "O que o financeiro precisa conciliar", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-sm", children: [
271
- /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Subtotal", value: money(order.subtotal, order.currency) }),
272
- order.discountTotal > 0 && /* @__PURE__ */ jsxRuntime.jsx(
273
- Row,
274
- {
275
- label: `Desconto${order.discountCode ? ` (${order.discountCode})` : ""}`,
276
- value: `\u2212 ${money(order.discountTotal, order.currency)}`
277
- }
278
- ),
279
- /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Entrega", value: money(order.shippingTotal, order.currency) }),
280
- /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Impostos", value: money(order.taxTotal, order.currency) }),
281
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 border-t pt-2", children: /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Total", value: money(order.total, order.currency), strong: true }) }),
282
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 border-t pt-2", children: [
283
- /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Forma de pagamento", value: PAYMENT_LABEL[order.paymentMethodKind ?? ""] ?? "\u2014" }),
284
- order.paidAt && /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Pago em", value: dateTime(order.paidAt) })
285
- ] }),
286
- !order.paymentMethodKind && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-xs text-muted-foreground", children: "Este pedido \xE9 anterior ao registro de forma de pagamento." })
287
- ] }) }),
251
+ items: order.items.map((it) => ({
252
+ id: it.id,
253
+ name: it.name,
254
+ description: it.sku,
255
+ imageUrl: it.imageUrl,
256
+ quantity: it.quantity,
257
+ unitPrice: money(it.unitPrice, cur),
258
+ total: money(it.total, cur)
259
+ })),
260
+ totals: [
261
+ { label: "Subtotal", value: money(order.subtotal, cur) },
262
+ ...order.discountTotal > 0 ? [{ label: `Desconto${order.discountCode ? ` (${order.discountCode})` : ""}`, value: `\u2212 ${money(order.discountTotal, cur)}`, muted: true }] : [],
263
+ { label: "Entrega", value: money(order.shippingTotal, cur) },
264
+ { label: "Impostos", value: money(order.taxTotal, cur) },
265
+ { label: "Total", value: money(order.total, cur), strong: true }
266
+ ],
267
+ paymentMethod: order.paymentMethodKind ? PAYMENT_LABEL[order.paymentMethodKind] ?? order.paymentMethodKind : void 0,
268
+ paidAt: order.paidAt ? dateTime(order.paidAt) : void 0,
269
+ receivable: receivable ? {
270
+ referenceNumber: receivable.balance.reference_number ?? void 0,
271
+ statusBadge: { label: RECEIVABLE_LABEL[receivable.balance.status] ?? receivable.balance.status, tone: toneOf(receivable.balance.status) },
272
+ rows: [
273
+ { label: "Faturado", value: money(receivable.balance.amount, cur) },
274
+ { label: "Recebido", value: money(receivable.balance.paid, cur) },
275
+ { label: "Saldo", value: money(receivable.balance.balance, cur), strong: true }
276
+ ],
277
+ installments,
278
+ actions: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
279
+ receivable.balance.balance > 0 && receivable.balance.status !== "cancelled" && /* @__PURE__ */ jsxRuntime.jsx(
280
+ "button",
281
+ {
282
+ type: "button",
283
+ onClick: registerReceipt,
284
+ disabled: confirming,
285
+ "data-testid": "order-register-receipt",
286
+ className: "rounded-md bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground transition hover:opacity-90 disabled:opacity-60",
287
+ children: confirming ? "Registrando\u2026" : "Registrar recebimento"
288
+ }
289
+ ),
288
290
  /* @__PURE__ */ jsxRuntime.jsx(
289
- Block,
291
+ "button",
290
292
  {
291
- title: "Contas a receber",
292
- hint: "Criado automaticamente quando o pedido foi feito \u2014 o mesmo registro que o Financeiro l\xEA",
293
- children: !receivable ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground", children: "Sem conta a receber para este pedido." }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-sm", children: [
294
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-3 flex flex-wrap items-center gap-2", children: [
295
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono font-semibold", children: receivable.balance.reference_number ?? "\u2014" }),
296
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: `inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium ${RECEIVABLE_TONE[receivable.balance.status] ?? RECEIVABLE_TONE.open}`, children: RECEIVABLE_LABEL[receivable.balance.status] ?? receivable.balance.status })
297
- ] }),
298
- /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Faturado", value: money(receivable.balance.amount, order.currency) }),
299
- /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Recebido", value: money(receivable.balance.paid, order.currency) }),
300
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 border-t pt-2", children: /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Saldo", value: money(receivable.balance.balance, order.currency), strong: true }) }),
301
- receivable.bills.length > 1 && /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "mt-3 space-y-1 border-t pt-2 text-xs", children: receivable.bills.map((bill) => /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-baseline justify-between gap-3", children: [
302
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-muted-foreground", children: [
303
- "Parcela ",
304
- bill.installment_number,
305
- " \xB7 vence ",
306
- new Date(bill.due_date).toLocaleDateString("pt-BR")
307
- ] }),
308
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "tabular-nums", children: [
309
- money(Number(bill.paid_amount ?? 0), order.currency),
310
- " / ",
311
- money(Number(bill.amount), order.currency)
312
- ] })
313
- ] }, bill.id)) }),
314
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4 flex flex-wrap gap-2", children: [
315
- receivable.balance.balance > 0 && receivable.balance.status !== "cancelled" && /* @__PURE__ */ jsxRuntime.jsx(
316
- "button",
317
- {
318
- type: "button",
319
- onClick: registerReceipt,
320
- disabled: confirming,
321
- "data-testid": "order-register-receipt",
322
- className: "rounded-md bg-primary px-3 py-1.5 text-sm font-medium text-primary-foreground transition hover:opacity-90 disabled:opacity-60",
323
- children: confirming ? "Registrando\u2026" : "Registrar recebimento"
324
- }
325
- ),
326
- /* @__PURE__ */ jsxRuntime.jsx(
327
- "button",
328
- {
329
- type: "button",
330
- onClick: () => saas.adminNavigateTo("/financial"),
331
- className: "rounded-md border px-3 py-1.5 text-sm font-medium transition hover:bg-muted",
332
- children: "Abrir no Financeiro"
333
- }
334
- )
335
- ] }),
336
- confirmError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 rounded-md border border-red-200 bg-red-50 px-3 py-2 text-xs text-red-800", children: confirmError })
337
- ] })
293
+ type: "button",
294
+ onClick: () => saas.adminNavigateTo("/financial"),
295
+ className: "rounded-md border px-3 py-1.5 text-sm font-medium transition hover:bg-muted",
296
+ children: "Abrir no Financeiro"
338
297
  }
339
- )
298
+ ),
299
+ confirmError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 w-full rounded-md border border-red-200 bg-red-50 px-3 py-2 text-xs text-red-800", children: confirmError })
340
300
  ] }),
341
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
342
- /* @__PURE__ */ jsxRuntime.jsx(Block, { title: "Cliente", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1 text-sm", children: [
343
- order.customerId ? /* @__PURE__ */ jsxRuntime.jsx(
344
- saas.PersonLink,
345
- {
346
- personId: order.customerId,
347
- name: order.customerName ?? order.customerEmail ?? "Cliente",
348
- lookup: shopCustomerLookup(provider),
349
- profileHref: `#/shop/customers/${order.customerId}`,
350
- className: "font-medium"
351
- }
352
- ) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium", children: order.customerName ?? "\u2014" }),
353
- order.customerEmail && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground", children: order.customerEmail }),
354
- !order.customerId && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "Compra sem cadastro \u2014 n\xE3o h\xE1 ficha de cliente para abrir." })
355
- ] }) }),
356
- /* @__PURE__ */ jsxRuntime.jsx(Block, { title: "Entrega", hint: "O que a log\xEDstica precisa", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2 text-sm", children: [
357
- addr ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-0.5", children: [
358
- /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
359
- [addr.street, addr.number].filter(Boolean).join(", "),
360
- addr.complement ? ` \u2014 ${addr.complement}` : ""
361
- ] }),
362
- addr.district && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground", children: addr.district }),
363
- /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-muted-foreground", children: [
364
- [addr.city, addr.state].filter((v) => v && v !== "\u2014").join("/"),
365
- addr.postal_code ? ` \xB7 ${addr.postal_code}` : ""
366
- ] }),
367
- (addr.recipient || addr.phone) && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: [addr.recipient, addr.phone].filter(Boolean).join(" \xB7 ") })
368
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
369
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: delivery ? "" : "text-muted-foreground", children: delivery ?? "Nenhum endere\xE7o registrado neste pedido." }),
370
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "Pedido anterior ao endere\xE7o estruturado \u2014 s\xF3 existe o texto livre das observa\xE7\xF5es, sem CEP, n\xFAmero ou bairro separ\xE1veis." })
301
+ emptyLabel: "Sem conta a receber para este pedido."
302
+ } : { rows: [], installments: [], emptyLabel: "Sem conta a receber para este pedido." },
303
+ extraSections: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
304
+ /* @__PURE__ */ jsxRuntime.jsx(saas.OrderDetailBlock, { title: "Entrega", hint: "O que a log\xEDstica precisa", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2 text-sm", children: [
305
+ addr ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-0.5", children: [
306
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
307
+ [addr.street, addr.number].filter(Boolean).join(", "),
308
+ addr.complement ? ` \u2014 ${addr.complement}` : ""
309
+ ] }),
310
+ addr.district && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground", children: addr.district }),
311
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-muted-foreground", children: [
312
+ [addr.city, addr.state].filter((v) => v && v !== "\u2014").join("/"),
313
+ addr.postal_code ? ` \xB7 ${addr.postal_code}` : ""
371
314
  ] }),
372
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-t pt-2", children: [
373
- /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Status", value: /* @__PURE__ */ jsxRuntime.jsx(Badge, { value: order.fulfillmentStatus }) }),
374
- shipments.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: "Nenhum envio registrado. Ao despachar, informe transportadora e c\xF3digo de rastreio \u2014 o status do pedido \xE9 calculado a partir dos envios." }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 space-y-2", children: shipments.map((s) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-md border px-2 py-1.5", children: [
375
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2", children: [
376
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium", children: [s.carrier, s.service].filter(Boolean).join(" \xB7 ") || "Envio" }),
377
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground", children: SHIPMENT_LABEL[s.status] ?? s.status })
315
+ (addr.recipient || addr.phone) && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: [addr.recipient, addr.phone].filter(Boolean).join(" \xB7 ") })
316
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: delivery ? "" : "text-muted-foreground", children: delivery ?? "Nenhum endere\xE7o registrado neste pedido." }),
317
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-t pt-2", children: [
318
+ /* @__PURE__ */ jsxRuntime.jsx(saas.OrderDetailRow, { label: "Status", value: /* @__PURE__ */ jsxRuntime.jsx(InlineBadge, { value: order.fulfillmentStatus }) }),
319
+ shipments.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: "Nenhum envio registrado." }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 space-y-2", children: shipments.map((s) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-md border px-2 py-1.5", children: [
320
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2", children: [
321
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium", children: [s.carrier, s.service].filter(Boolean).join(" \xB7 ") || "Envio" }),
322
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground", children: SHIPMENT_LABEL[s.status] ?? s.status })
323
+ ] }),
324
+ s.tracking_code && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-0.5 font-mono text-xs", children: s.tracking_url ? /* @__PURE__ */ jsxRuntime.jsx("a", { href: s.tracking_url, target: "_blank", rel: "noreferrer", className: "text-primary hover:underline", children: s.tracking_code }) : s.tracking_code }),
325
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1 space-y-0.5 text-[11px] text-muted-foreground", children: [
326
+ s.shipped_at && /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
327
+ "Despachado em ",
328
+ dateTime(s.shipped_at)
329
+ ] }),
330
+ s.estimated_delivery_at && /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
331
+ "Previs\xE3o: ",
332
+ dateTime(s.estimated_delivery_at)
378
333
  ] }),
379
- s.tracking_code && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-0.5 font-mono text-xs", children: s.tracking_url ? /* @__PURE__ */ jsxRuntime.jsx("a", { href: s.tracking_url, target: "_blank", rel: "noreferrer", className: "text-primary hover:underline", children: s.tracking_code }) : s.tracking_code }),
380
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1 space-y-0.5 text-[11px] text-muted-foreground", children: [
381
- s.shipped_at && /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
382
- "Despachado em ",
383
- dateTime(s.shipped_at)
384
- ] }),
385
- s.estimated_delivery_at && /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
386
- "Previs\xE3o: ",
387
- dateTime(s.estimated_delivery_at)
388
- ] }),
389
- s.delivered_at && /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
390
- "Entregue em ",
391
- dateTime(s.delivered_at)
392
- ] })
334
+ s.delivered_at && /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
335
+ "Entregue em ",
336
+ dateTime(s.delivered_at)
393
337
  ] })
394
- ] }, s.id)) })
395
- ] })
396
- ] }) }),
397
- /* @__PURE__ */ jsxRuntime.jsx(Block, { title: "Hist\xF3rico", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1 text-sm", children: [
398
- /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Criado", value: dateTime(order.createdAt) }),
399
- /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Atualizado", value: dateTime(order.updatedAt) }),
400
- /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Situa\xE7\xE3o", value: /* @__PURE__ */ jsxRuntime.jsx(Badge, { value: order.status }) })
401
- ] }) }),
402
- order.notes && /* @__PURE__ */ jsxRuntime.jsx(Block, { title: "Observa\xE7\xF5es", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "whitespace-pre-wrap text-sm text-muted-foreground", children: order.notes }) })
403
- ] })
404
- ] })
405
- ] });
338
+ ] })
339
+ ] }, s.id)) })
340
+ ] })
341
+ ] }) }),
342
+ /* @__PURE__ */ jsxRuntime.jsx(saas.OrderDetailBlock, { title: "Hist\xF3rico", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1 text-sm", children: [
343
+ /* @__PURE__ */ jsxRuntime.jsx(saas.OrderDetailRow, { label: "Criado", value: dateTime(order.createdAt) }),
344
+ /* @__PURE__ */ jsxRuntime.jsx(saas.OrderDetailRow, { label: "Atualizado", value: dateTime(order.updatedAt) }),
345
+ /* @__PURE__ */ jsxRuntime.jsx(saas.OrderDetailRow, { label: "Situa\xE7\xE3o", value: /* @__PURE__ */ jsxRuntime.jsx(InlineBadge, { value: order.status }) })
346
+ ] }) }),
347
+ order.notes && /* @__PURE__ */ jsxRuntime.jsx(saas.OrderDetailBlock, { title: "Observa\xE7\xF5es", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "whitespace-pre-wrap text-sm text-muted-foreground", children: order.notes }) })
348
+ ] }),
349
+ onBack,
350
+ backLabel: "Pedidos"
351
+ };
352
+ return /* @__PURE__ */ jsxRuntime.jsx(saas.OrderDetailView, { ...data });
406
353
  }
407
354
  function currency(value, code = "BRL", locale = "pt-BR") {
408
355
  return new Intl.NumberFormat(locale, { style: "currency", currency: code }).format(value);
@@ -557,7 +504,7 @@ function OrdersTab({ provider }) {
557
504
  personId: id,
558
505
  name: label,
559
506
  lookup: shopCustomerLookup(() => resolveShopProvider(provider)),
560
- profileHref: `#/shop/customers/${id}`
507
+ profileHref: `#/customers/${id}`
561
508
  }
562
509
  );
563
510
  }
@@ -741,5 +688,5 @@ var ShopPage = ({ provider, section }) => {
741
688
  ShopPage.displayName = "ShopPage";
742
689
 
743
690
  exports.ShopPage = ShopPage;
744
- //# sourceMappingURL=ShopPage-ALBPZAEW.cjs.map
745
- //# sourceMappingURL=ShopPage-ALBPZAEW.cjs.map
691
+ //# sourceMappingURL=ShopPage-NK6FSPJ5.cjs.map
692
+ //# sourceMappingURL=ShopPage-NK6FSPJ5.cjs.map