@fayz-ai/plugin-shop 0.11.2 → 0.12.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/{ShopPage-YB5ZWECJ.js → ShopPage-VVLOH3RF.js} +67 -28
- package/dist/ShopPage-VVLOH3RF.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +684 -141
- package/dist/index.js.map +1 -1
- package/dist/integrations/abacatepay/connectorDef.d.ts.map +1 -1
- package/dist/integrations/abacatepay/data.d.ts +40 -0
- package/dist/integrations/abacatepay/data.d.ts.map +1 -0
- package/dist/integrations/abacatepay/limits.d.ts +26 -0
- package/dist/integrations/abacatepay/limits.d.ts.map +1 -0
- package/dist/integrations/abacatepay/sync.d.ts +88 -0
- package/dist/integrations/abacatepay/sync.d.ts.map +1 -0
- package/dist/integrations/neochef/connectorDef.d.ts +12 -0
- package/dist/integrations/neochef/connectorDef.d.ts.map +1 -0
- package/dist/integrations/neochef/data.d.ts +54 -0
- package/dist/integrations/neochef/data.d.ts.map +1 -0
- package/dist/integrations/neochef/index.d.ts +8 -0
- package/dist/integrations/neochef/index.d.ts.map +1 -0
- package/dist/integrations/neochef/limits.d.ts +26 -0
- package/dist/integrations/neochef/limits.d.ts.map +1 -0
- package/dist/integrations/neochef/mapping.d.ts +31 -0
- package/dist/integrations/neochef/mapping.d.ts.map +1 -0
- package/dist/integrations/neochef/mark.d.ts +21 -0
- package/dist/integrations/neochef/mark.d.ts.map +1 -0
- package/dist/integrations/neochef/types.d.ts +71 -0
- package/dist/integrations/neochef/types.d.ts.map +1 -0
- package/dist/integrations/vindi/connectorDef.d.ts +25 -6
- package/dist/integrations/vindi/connectorDef.d.ts.map +1 -1
- package/dist/views/ContentPage.d.ts.map +1 -1
- package/dist/views/NewOrderCharge.d.ts +14 -2
- package/dist/views/NewOrderCharge.d.ts.map +1 -1
- package/dist/views/NewOrderPage.d.ts.map +1 -1
- package/dist/views/new-order-rules.d.ts +10 -1
- package/dist/views/new-order-rules.d.ts.map +1 -1
- package/package.json +5 -5
- package/dist/ShopPage-YB5ZWECJ.js.map +0 -1
|
@@ -2,7 +2,7 @@ import { errorMessage, shopCustomerLookup, listProductsDetailed, invalidateProdu
|
|
|
2
2
|
import React2, { useState, useEffect, useMemo, useCallback, useRef } from 'react';
|
|
3
3
|
import { Thumbnail, Button, DataTable, toast, ConfirmDialog, formatPhone, SearchSelect, Modal, ModalPortal, ModalOverlay, ModalContent, ModalHeader, ModalTitle, ModalBody, ModalFooter, Skeleton, PhoneField } from '@fayz-ai/ui';
|
|
4
4
|
import { Minus, Plus, Trash2, CreditCard, XCircle, ShoppingBag, Package, Wallet, X, Pencil, MapPin, Search, Check, Copy, MessageCircle, CheckCircle2, Printer, RefreshCw, ExternalLink, Truck, AlertTriangle, Loader2 } from 'lucide-react';
|
|
5
|
-
import { getShopProvider, formatDocument, resolveShippingLabelProvider, documentDigits, isValidDocument } from '@fayz-ai/shop';
|
|
5
|
+
import { CHARGEABLE_PROVIDERS, supportsPaymentLink, getShopProvider, formatDocument, resolveShippingLabelProvider, documentDigits, isValidDocument } from '@fayz-ai/shop';
|
|
6
6
|
import { useAdminPath, adminNavigateTo, OrderFormBlock, OrderFormView, OrderDetailSkeleton, OrderDetailBlock, OrderDetailRow, PersonLink, OrderDetailView as OrderDetailView$1, OrderListView, RecordPickerModal, useConnectors, CrudRecordModal } from '@fayz-ai/admin';
|
|
7
7
|
import { usePluginRuntimeOptional, getSupabaseClientOptional } from '@fayz-ai/core';
|
|
8
8
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
@@ -187,6 +187,15 @@ function validateNewOrder(draft, ending) {
|
|
|
187
187
|
return `Para gerar a cobran\xE7a o adquirente exige ${missing.join(", ")} no cadastro do cliente.`;
|
|
188
188
|
}
|
|
189
189
|
}
|
|
190
|
+
if (ending === "link") {
|
|
191
|
+
const missing = [
|
|
192
|
+
!draft.customerEmail.trim() && "e-mail",
|
|
193
|
+
!draft.customerPhone.trim() && "telefone"
|
|
194
|
+
].filter(Boolean);
|
|
195
|
+
if (missing.length) {
|
|
196
|
+
return `Para mandar o link o cadastro do cliente precisa de ${missing.join(" e ")}.`;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
190
199
|
return null;
|
|
191
200
|
}
|
|
192
201
|
function isDuplicateEmail(error) {
|
|
@@ -1014,7 +1023,7 @@ function OrderDetailView({ orderId, provider, onBack }) {
|
|
|
1014
1023
|
useEffect(() => {
|
|
1015
1024
|
void loadReceivable();
|
|
1016
1025
|
}, [loadReceivable]);
|
|
1017
|
-
if (loading) return /* @__PURE__ */ jsx(OrderDetailSkeleton, {});
|
|
1026
|
+
if (loading) return /* @__PURE__ */ jsx(OrderDetailSkeleton, { parentLabel: "Pedidos", onBack });
|
|
1018
1027
|
if (error) {
|
|
1019
1028
|
return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-800", children: [
|
|
1020
1029
|
/* @__PURE__ */ jsx("p", { className: "font-medium", children: "N\xE3o foi poss\xEDvel carregar o pedido." }),
|
|
@@ -1318,6 +1327,8 @@ function NewOrderCharge({
|
|
|
1318
1327
|
sessionId,
|
|
1319
1328
|
emv,
|
|
1320
1329
|
qrcodeBase64,
|
|
1330
|
+
paymentUrl,
|
|
1331
|
+
acquirer,
|
|
1321
1332
|
total,
|
|
1322
1333
|
currency: currency2,
|
|
1323
1334
|
customerName,
|
|
@@ -1334,7 +1345,7 @@ function NewOrderCharge({
|
|
|
1334
1345
|
if (settled.current) return;
|
|
1335
1346
|
setChecking(true);
|
|
1336
1347
|
try {
|
|
1337
|
-
const result = await provider().settleCheckoutSession?.(sessionId);
|
|
1348
|
+
const result = await provider().settleCheckoutSession?.(sessionId, acquirer);
|
|
1338
1349
|
if (!result) return;
|
|
1339
1350
|
if (result.state === "paid") {
|
|
1340
1351
|
settled.current = true;
|
|
@@ -1350,7 +1361,7 @@ function NewOrderCharge({
|
|
|
1350
1361
|
} finally {
|
|
1351
1362
|
setChecking(false);
|
|
1352
1363
|
}
|
|
1353
|
-
}, [provider, sessionId, onPaid]);
|
|
1364
|
+
}, [provider, sessionId, acquirer, onPaid]);
|
|
1354
1365
|
useEffect(() => {
|
|
1355
1366
|
if (!open) return;
|
|
1356
1367
|
const timer = setInterval(() => {
|
|
@@ -1358,28 +1369,32 @@ function NewOrderCharge({
|
|
|
1358
1369
|
}, POLL_MS);
|
|
1359
1370
|
return () => clearInterval(timer);
|
|
1360
1371
|
}, [open, check]);
|
|
1372
|
+
const isLink = Boolean(paymentUrl && !emv);
|
|
1373
|
+
const payable = paymentUrl ?? emv ?? "";
|
|
1361
1374
|
async function copy() {
|
|
1375
|
+
if (!payable) return;
|
|
1362
1376
|
try {
|
|
1363
|
-
await navigator.clipboard.writeText(
|
|
1377
|
+
await navigator.clipboard.writeText(payable);
|
|
1364
1378
|
setCopied(true);
|
|
1365
1379
|
setTimeout(() => setCopied(false), 2400);
|
|
1366
1380
|
} catch {
|
|
1367
1381
|
}
|
|
1368
1382
|
}
|
|
1369
|
-
const
|
|
1370
|
-
|
|
1383
|
+
const greeting = customerName ? ` ${customerName.split(" ")[0]}` : "";
|
|
1384
|
+
const message = isLink ? `Ol\xE1${greeting}! Aqui est\xE1 o link para pagar seu pedido de ${money4}:
|
|
1385
|
+
|
|
1386
|
+
${payable}
|
|
1371
1387
|
|
|
1372
|
-
${
|
|
1373
|
-
|
|
1388
|
+
Voc\xEA escolhe a forma de pagamento na p\xE1gina.` : `Ol\xE1${greeting}! Segue o Pix de ${money4} para o seu pedido:
|
|
1389
|
+
|
|
1390
|
+
${payable}`;
|
|
1391
|
+
const whatsapp = customerPhone && payable ? `https://wa.me/${customerPhone.length > 11 ? customerPhone : `55${customerPhone}`}?text=${encodeURIComponent(message)}` : null;
|
|
1374
1392
|
return /* @__PURE__ */ jsx(Modal, { open, onOpenChange: (next) => {
|
|
1375
1393
|
if (!next) onClose();
|
|
1376
1394
|
}, children: /* @__PURE__ */ jsx(ModalPortal, { children: /* @__PURE__ */ jsx(ModalOverlay, { children: /* @__PURE__ */ jsxs(ModalContent, { size: "lg", "data-testid": "new-order-charge-modal", children: [
|
|
1377
1395
|
/* @__PURE__ */ jsxs(ModalHeader, { className: "mb-4", children: [
|
|
1378
|
-
/* @__PURE__ */
|
|
1379
|
-
|
|
1380
|
-
money4
|
|
1381
|
-
] }),
|
|
1382
|
-
state === "waiting" && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "Vale por 15 minutos. O pedido \xE9 criado quando o pagamento cair." })
|
|
1396
|
+
/* @__PURE__ */ jsx(ModalTitle, { children: isLink ? `Link de ${money4}` : `Pix de ${money4}` }),
|
|
1397
|
+
state === "waiting" && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: isLink ? "Mande para o cliente. O pedido \xE9 criado quando o pagamento cair \u2014 pode fechar esta janela." : "Vale por 15 minutos. O pedido \xE9 criado quando o pagamento cair." })
|
|
1383
1398
|
] }),
|
|
1384
1399
|
/* @__PURE__ */ jsxs(ModalBody, { children: [
|
|
1385
1400
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-4 sm:flex-row sm:items-start", children: [
|
|
@@ -1394,20 +1409,21 @@ ${emv}`
|
|
|
1394
1409
|
),
|
|
1395
1410
|
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 space-y-3", children: [
|
|
1396
1411
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
1397
|
-
/* @__PURE__ */ jsx("p", { className: "text-xs font-medium text-muted-foreground", children: "Pix copia e cola" }),
|
|
1412
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs font-medium text-muted-foreground", children: isLink ? "Link de pagamento" : "Pix copia e cola" }),
|
|
1398
1413
|
/* @__PURE__ */ jsx(
|
|
1399
1414
|
"p",
|
|
1400
1415
|
{
|
|
1401
|
-
"data-testid": "new-order-emv",
|
|
1416
|
+
"data-testid": isLink ? "new-order-payment-link" : "new-order-emv",
|
|
1402
1417
|
className: "mt-1 max-h-20 overflow-auto break-all rounded-md border bg-muted/30 p-2 font-mono text-[11px]",
|
|
1403
|
-
children:
|
|
1418
|
+
children: payable
|
|
1404
1419
|
}
|
|
1405
|
-
)
|
|
1420
|
+
),
|
|
1421
|
+
isLink && /* @__PURE__ */ jsx("p", { className: "mt-1 text-[11px] text-muted-foreground", children: "O cliente escolhe Pix, boleto ou cart\xE3o na p\xE1gina do adquirente." })
|
|
1406
1422
|
] }),
|
|
1407
1423
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
|
|
1408
1424
|
/* @__PURE__ */ jsxs(Button, { size: "sm", onClick: copy, "data-testid": "new-order-copy", children: [
|
|
1409
1425
|
copied ? /* @__PURE__ */ jsx(Check, { className: "mr-1.5 h-3.5 w-3.5" }) : /* @__PURE__ */ jsx(Copy, { className: "mr-1.5 h-3.5 w-3.5" }),
|
|
1410
|
-
copied ? "Copiado" : "Copiar c\xF3digo"
|
|
1426
|
+
copied ? "Copiado" : isLink ? "Copiar link" : "Copiar c\xF3digo"
|
|
1411
1427
|
] }),
|
|
1412
1428
|
whatsapp && /* @__PURE__ */ jsxs(
|
|
1413
1429
|
"a",
|
|
@@ -1435,7 +1451,7 @@ ${emv}`
|
|
|
1435
1451
|
/* @__PURE__ */ jsx(Check, { className: "h-4 w-4" }),
|
|
1436
1452
|
" Pagamento confirmado \u2014 abrindo o pedido\u2026"
|
|
1437
1453
|
] }),
|
|
1438
|
-
(state === "expired" || state === "failed") && /* @__PURE__ */ jsx("p", { className: "text-red-700", "data-testid": "new-order-dead", children: state === "expired" ? "O c\xF3digo expirou sem pagamento. O pedido continua aqui \u2014 d\xE1 para cobrar de outro jeito
|
|
1454
|
+
(state === "expired" || state === "failed") && /* @__PURE__ */ jsx("p", { className: "text-red-700", "data-testid": "new-order-dead", children: state === "expired" ? `${isLink ? "O link expirou" : "O c\xF3digo expirou"} sem pagamento. O pedido continua aqui \u2014 d\xE1 para cobrar de outro jeito.` : "O pagamento n\xE3o foi conclu\xEDdo. O pedido continua aqui \u2014 d\xE1 para cobrar de outro jeito." })
|
|
1439
1455
|
] })
|
|
1440
1456
|
] }),
|
|
1441
1457
|
/* @__PURE__ */ jsxs(ModalFooter, { className: "mt-4 gap-2", children: [
|
|
@@ -1470,7 +1486,6 @@ var PAYMENT_METHODS = [
|
|
|
1470
1486
|
{ id: "boleto", label: "Boleto" },
|
|
1471
1487
|
{ id: "other", label: "Outro" }
|
|
1472
1488
|
];
|
|
1473
|
-
var CHARGEABLE_PROVIDERS = ["abacatepay"];
|
|
1474
1489
|
var money3 = (value, currency2 = "BRL") => new Intl.NumberFormat("pt-BR", { style: "currency", currency: currency2 }).format(Number(value) || 0);
|
|
1475
1490
|
var onlyDigits = (value) => value.replace(/\D/gu, "");
|
|
1476
1491
|
var maskPostal = (value) => {
|
|
@@ -1514,6 +1529,7 @@ function NewOrderPage({ provider, onDone, onCancel }) {
|
|
|
1514
1529
|
}, [provider]);
|
|
1515
1530
|
const acquirer = settings?.paymentProvider ?? null;
|
|
1516
1531
|
const canCharge = Boolean(acquirer && CHARGEABLE_PROVIDERS.includes(acquirer));
|
|
1532
|
+
const canLink = canCharge && supportsPaymentLink(acquirer);
|
|
1517
1533
|
const currency2 = settings?.currency ?? "BRL";
|
|
1518
1534
|
const subtotal = useMemo(
|
|
1519
1535
|
() => lines.reduce((sum, line) => sum + line.unitPrice * line.quantity, 0),
|
|
@@ -1624,7 +1640,7 @@ function NewOrderPage({ provider, onDone, onCancel }) {
|
|
|
1624
1640
|
setSaving(true);
|
|
1625
1641
|
setError(null);
|
|
1626
1642
|
try {
|
|
1627
|
-
if (ending === "charge") {
|
|
1643
|
+
if (ending === "charge" || ending === "link") {
|
|
1628
1644
|
const opened = await provider().openCheckoutSession?.({
|
|
1629
1645
|
items: lines.map((line) => ({
|
|
1630
1646
|
productId: line.productId,
|
|
@@ -1634,13 +1650,24 @@ function NewOrderPage({ provider, onDone, onCancel }) {
|
|
|
1634
1650
|
})),
|
|
1635
1651
|
customer: { name: customer.name.trim(), email: customer.email.trim().toLowerCase() },
|
|
1636
1652
|
shippingAddress,
|
|
1637
|
-
discountCode: discountCode.trim() || null
|
|
1653
|
+
discountCode: discountCode.trim() || null,
|
|
1654
|
+
// The one difference between the two endings, all the way down: same
|
|
1655
|
+
// repricing, same frozen session, same settlement by webhook. What
|
|
1656
|
+
// changes is whether the acquirer answers with a code to read out or
|
|
1657
|
+
// an address to send.
|
|
1658
|
+
asLink: ending === "link"
|
|
1638
1659
|
});
|
|
1639
|
-
if (
|
|
1660
|
+
if (ending === "link" && !opened?.paymentUrl) {
|
|
1661
|
+
throw new Error("O adquirente n\xE3o devolveu o link de pagamento. Tente de novo.");
|
|
1662
|
+
}
|
|
1663
|
+
if (ending === "charge" && !opened?.charge?.emv) {
|
|
1664
|
+
throw new Error("A cobran\xE7a foi aberta sem c\xF3digo Pix. Tente de novo.");
|
|
1665
|
+
}
|
|
1640
1666
|
setSession({
|
|
1641
1667
|
sessionId: opened.sessionId,
|
|
1642
|
-
emv: opened.charge
|
|
1643
|
-
qrcode: opened.charge
|
|
1668
|
+
emv: opened.charge?.emv ?? null,
|
|
1669
|
+
qrcode: opened.charge?.qrcodeBase64 ?? null,
|
|
1670
|
+
paymentUrl: opened.paymentUrl ?? null,
|
|
1644
1671
|
total: opened.total
|
|
1645
1672
|
});
|
|
1646
1673
|
setChargeOpen(true);
|
|
@@ -1882,6 +1909,16 @@ function NewOrderPage({ provider, onDone, onCancel }) {
|
|
|
1882
1909
|
children: saving ? "Abrindo\u2026" : session ? "Ver cobran\xE7a" : "Gerar cobran\xE7a Pix"
|
|
1883
1910
|
}
|
|
1884
1911
|
),
|
|
1912
|
+
canLink && !session && /* @__PURE__ */ jsx(
|
|
1913
|
+
Button,
|
|
1914
|
+
{
|
|
1915
|
+
variant: "outline",
|
|
1916
|
+
onClick: () => void finish("link"),
|
|
1917
|
+
disabled: saving,
|
|
1918
|
+
"data-testid": "new-order-link",
|
|
1919
|
+
children: saving ? "Gerando\u2026" : "Gerar link de pagamento"
|
|
1920
|
+
}
|
|
1921
|
+
),
|
|
1885
1922
|
/* @__PURE__ */ jsx(
|
|
1886
1923
|
Button,
|
|
1887
1924
|
{
|
|
@@ -1914,6 +1951,8 @@ function NewOrderPage({ provider, onDone, onCancel }) {
|
|
|
1914
1951
|
sessionId: session.sessionId,
|
|
1915
1952
|
emv: session.emv,
|
|
1916
1953
|
qrcodeBase64: session.qrcode,
|
|
1954
|
+
paymentUrl: session.paymentUrl,
|
|
1955
|
+
acquirer,
|
|
1917
1956
|
total: session.total,
|
|
1918
1957
|
currency: currency2,
|
|
1919
1958
|
customerPhone: onlyDigits(customer.phone),
|
|
@@ -2922,5 +2961,5 @@ var ShopPage = ({ provider, section }) => {
|
|
|
2922
2961
|
ShopPage.displayName = "ShopPage";
|
|
2923
2962
|
|
|
2924
2963
|
export { ShopPage };
|
|
2925
|
-
//# sourceMappingURL=ShopPage-
|
|
2926
|
-
//# sourceMappingURL=ShopPage-
|
|
2964
|
+
//# sourceMappingURL=ShopPage-VVLOH3RF.js.map
|
|
2965
|
+
//# sourceMappingURL=ShopPage-VVLOH3RF.js.map
|