@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
package/dist/index.js
CHANGED
|
@@ -2,8 +2,8 @@ import { shopCustomerLookup, resolve, invalidateProductLists, listProductsDetail
|
|
|
2
2
|
import React8, { useState, useEffect, useRef } from 'react';
|
|
3
3
|
import { createConnectionStore, connectionSettings, connectionStatus, settingsStatus, connectionRuns, tl, getSupabaseClientOptional, registerMessageDefaults, connectorRuntimeToken, CONNECTOR_RUNTIME_TOKEN_HEADER, resolveDataProvider } from '@fayz-ai/core';
|
|
4
4
|
import { getShopTenantId, setShopTenantResolver, buildShopMessageDefaults, registerShippingLabelProvider, getShopProvider, buildShopDomainEvents, axesFromOptions, planVariantMatrix, validateVariantAxes, hasOnlyDefaultVariant, MAX_VARIANT_AXES, leavesNothingSellable, productImageToMediaFile, formatVariantCombination, applyVariantMatrix } from '@fayz-ai/shop';
|
|
5
|
-
import { fayzConnectorOAuth, useOrganizationStore, registerEntityPath, registerPersonLookup, createCrudPage, adminNavigateTo, ClientOrdersTab, createClientOrdersProvider, CrudFormPage, SettingsGroup, SelectRow, ToggleRow, useConnectors, useConnectorsPanelAvailable, openConnectorsPanel, MultiSelectRow, AddConnectorButton, AddConnectorPanel, ConnectorDetail, RegistryCrudView, TextRow, ConnectorRow, ConnectorMark, StateChip } from '@fayz-ai/admin';
|
|
6
|
-
import { Package, Eye, FileEdit, PackageX, UsersRound, Users, UserX, Filter, ShoppingBag, Repeat, CircleDollarSign, Tag, TicketCheck, Layers, CreditCard, ImageOff, Link2, MapPin, Music, Camera, MessageCircle, Globe, Plus, Loader2, ChevronLeft, ChevronRight,
|
|
5
|
+
import { fayzConnectorOAuth, useOrganizationStore, registerEntityPath, registerPersonLookup, createCrudPage, adminNavigateTo, ClientOrdersTab, createClientOrdersProvider, AskAIButton, CrudFormPage, SettingsGroup, SelectRow, ToggleRow, useConnectors, useConnectorsPanelAvailable, openConnectorsPanel, MultiSelectRow, AddConnectorButton, AddConnectorPanel, ConnectorDetail, RegistryCrudView, TextRow, ConnectorRow, ConnectorMark, StateChip } from '@fayz-ai/admin';
|
|
6
|
+
import { Package, Eye, FileEdit, PackageX, UsersRound, Users, UserX, Filter, ShoppingBag, Repeat, CircleDollarSign, Tag, TicketCheck, Layers, CreditCard, ImageOff, Link2, MapPin, Music, Camera, MessageCircle, Globe, Plus, Loader2, ChevronLeft, ChevronRight, Download, RefreshCw, Trash2, Upload, ExternalLink, Check, X, AlertTriangle, Box, ChevronDown, Film, FileText, Warehouse, ArrowRight, Car, Truck, Info } from 'lucide-react';
|
|
7
7
|
import { PageHeaderActions, PageTabs, Card, Button, Thumbnail, PageHeader, toast, ConfirmDialog, Input, Hint, Modal, ModalContent, ModalHeader, ModalTitle, ModalBody, Skeleton } from '@fayz-ai/ui';
|
|
8
8
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
9
9
|
import { advanceWindow, createRateLimiter, sliceWindow, paginate, reconcileMirror, serializeCursor } from '@fayz-ai/core/connector-runtime';
|
|
@@ -309,7 +309,7 @@ function AxisEditor({ axis, index, count, disabled, onChange, onMove, onRemove }
|
|
|
309
309
|
onChange({ ...axis, values: merged });
|
|
310
310
|
setDraft("");
|
|
311
311
|
}
|
|
312
|
-
return /* @__PURE__ */ jsxs("li", { className: "rounded-
|
|
312
|
+
return /* @__PURE__ */ jsxs("li", { className: "rounded-card border bg-card p-3", children: [
|
|
313
313
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
314
314
|
/* @__PURE__ */ jsx(
|
|
315
315
|
"input",
|
|
@@ -2676,7 +2676,7 @@ function PaymentsSettings({ provider }) {
|
|
|
2676
2676
|
] }),
|
|
2677
2677
|
/* @__PURE__ */ jsx(AddConnectorButton, { onClick: () => setAdding(true) })
|
|
2678
2678
|
] }),
|
|
2679
|
-
/* @__PURE__ */ jsx("div", { className: "rounded-
|
|
2679
|
+
/* @__PURE__ */ jsx("div", { className: "rounded-card border bg-card shadow-sm", children: payment.length === 0 ? /* @__PURE__ */ jsx("p", { className: "p-4 text-sm text-muted-foreground", children: "Nenhum provedor de pagamento dispon\xEDvel para este app ainda." }) : /* @__PURE__ */ jsxs("ul", { className: "divide-y", role: "radiogroup", "aria-label": "Quem cobra", children: [
|
|
2680
2680
|
payment.map((connector) => /* @__PURE__ */ jsx(
|
|
2681
2681
|
PaymentProviderRow,
|
|
2682
2682
|
{
|
|
@@ -2894,7 +2894,7 @@ function HandlingSettings({ settings, provider }) {
|
|
|
2894
2894
|
] }),
|
|
2895
2895
|
/* @__PURE__ */ jsx("p", { className: "mt-0.5 text-[10px] text-muted-foreground", children: "Um perfil \xE9 um grupo de produtos com zonas pr\xF3prias \u2014 refrigerados, fr\xE1geis, volumosos, sob encomenda. Um perfil com s\xF3 as suas zonas e o gateway desligado \xE9 como se diz \xABisto n\xE3o vai de transportadora\xBB. Produto sem perfil usa o geral, que \xE9 o de todos hoje." })
|
|
2896
2896
|
] }),
|
|
2897
|
-
/* @__PURE__ */ jsx("div", { className: "rounded-
|
|
2897
|
+
/* @__PURE__ */ jsx("div", { className: "rounded-card border bg-card px-5 shadow-sm", children: /* @__PURE__ */ jsxs(
|
|
2898
2898
|
"button",
|
|
2899
2899
|
{
|
|
2900
2900
|
type: "button",
|
|
@@ -3180,7 +3180,7 @@ function ShippingSettings({ provider }) {
|
|
|
3180
3180
|
/* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold", children: "De onde voc\xEA despacha" }),
|
|
3181
3181
|
/* @__PURE__ */ jsx("p", { className: "mt-0.5 text-[10px] text-muted-foreground", children: "Os locais que guardam estoque e despacham pedidos. O CEP do local padr\xE3o \xE9 a origem que a transportadora usa para cotar o frete \u2014 \xE9 aqui que ele se cadastra, uma vez. Cada local pode ter o seu pr\xF3prio despachante ou seguir a decis\xE3o da loja." })
|
|
3182
3182
|
] }),
|
|
3183
|
-
/* @__PURE__ */ jsx("div", { className: "rounded-
|
|
3183
|
+
/* @__PURE__ */ jsx("div", { className: "rounded-card border bg-card px-5 shadow-sm", children: /* @__PURE__ */ jsxs(
|
|
3184
3184
|
"button",
|
|
3185
3185
|
{
|
|
3186
3186
|
type: "button",
|
|
@@ -3208,7 +3208,7 @@ function ShippingSettings({ provider }) {
|
|
|
3208
3208
|
/* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold", children: "Zonas de entrega" }),
|
|
3209
3209
|
/* @__PURE__ */ jsx("p", { className: "mt-0.5 text-[10px] text-muted-foreground", children: "Faixas de CEP com pre\xE7o, prazo e frete gr\xE1tis pr\xF3prios. Um CEP fora de todas as zonas cai no pre\xE7o base acima; se a loja n\xE3o tiver pre\xE7o base nem zona que o cubra, o checkout diz que n\xE3o entrega ali. Uma faixa tamb\xE9m pode ser uma recusa \u2014 \xABn\xE3o entrego aqui\xBB \u2014 e ela vence qualquer zona e qualquer gateway." })
|
|
3210
3210
|
] }),
|
|
3211
|
-
/* @__PURE__ */ jsx("div", { className: "rounded-
|
|
3211
|
+
/* @__PURE__ */ jsx("div", { className: "rounded-card border bg-card px-5 shadow-sm", children: /* @__PURE__ */ jsxs(
|
|
3212
3212
|
"button",
|
|
3213
3213
|
{
|
|
3214
3214
|
type: "button",
|
|
@@ -3262,7 +3262,7 @@ function ShippingSettings({ provider }) {
|
|
|
3262
3262
|
/* @__PURE__ */ jsx("p", { className: "mt-0.5 text-[10px] text-muted-foreground", children: "Conectado, ele cota o frete para o CEP do comprador em vez de a loja adivinhar. O pre\xE7o cotado \xE9 gravado no servidor e \xE9 ele que o pedido cobra \u2014 o navegador escolhe entre op\xE7\xF5es, nunca informa um valor. Quais transportadoras aparecem vem da conta do gateway, n\xE3o desta lista." }),
|
|
3263
3263
|
!carriersConnected && /* @__PURE__ */ jsx("p", { className: "mt-1 text-[10px] text-muted-foreground", children: "Nenhum conectado \u2014 a loja entrega por conta pr\xF3pria, pelo pre\xE7o base e pelas zonas acima. Conectar \xE9 opcional e pode ficar para depois." })
|
|
3264
3264
|
] }),
|
|
3265
|
-
/* @__PURE__ */ jsx("div", { className: "rounded-
|
|
3265
|
+
/* @__PURE__ */ jsx("div", { className: "rounded-card border bg-card shadow-sm", children: /* @__PURE__ */ jsx("ul", { className: "divide-y", children: carriers.map((connector) => /* @__PURE__ */ jsx(ConnectorRow, { connector, onOpen: openJourney }, connector.id)) }) })
|
|
3266
3266
|
] }),
|
|
3267
3267
|
/* @__PURE__ */ jsx(HandlingSettings, { settings: storeSettings, provider }),
|
|
3268
3268
|
/* @__PURE__ */ jsx("div", { className: "flex min-h-5 items-center gap-1.5 px-1 text-xs text-muted-foreground", children: error ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1.5 text-destructive", children: [
|
|
@@ -3630,6 +3630,39 @@ var appmaxConnectorDef = {
|
|
|
3630
3630
|
disconnect: () => store2.disconnect(),
|
|
3631
3631
|
ExtraPanel: AppmaxExtraPanel
|
|
3632
3632
|
};
|
|
3633
|
+
var ABACATEPAY_FUNCTION = "abacatepay-sync";
|
|
3634
|
+
function client() {
|
|
3635
|
+
const supabase = getSupabaseClientOptional();
|
|
3636
|
+
if (!supabase) throw new Error("Sem conex\xE3o com o banco para falar com a AbacatePay.");
|
|
3637
|
+
return supabase;
|
|
3638
|
+
}
|
|
3639
|
+
async function invoke(body) {
|
|
3640
|
+
const tenantId = getShopTenantId();
|
|
3641
|
+
if (!tenantId) throw new Error("Sem loja selecionada para sincronizar com a AbacatePay.");
|
|
3642
|
+
const runtimeToken = await connectorRuntimeToken({ tenantId });
|
|
3643
|
+
const { data, error } = await client().functions.invoke(ABACATEPAY_FUNCTION, {
|
|
3644
|
+
body: { ...body, tenantId },
|
|
3645
|
+
headers: { [CONNECTOR_RUNTIME_TOKEN_HEADER]: runtimeToken }
|
|
3646
|
+
});
|
|
3647
|
+
if (!error) return data;
|
|
3648
|
+
const status = Number(error?.context?.status ?? 0);
|
|
3649
|
+
let message2 = "";
|
|
3650
|
+
try {
|
|
3651
|
+
const payload = await error?.context?.json?.();
|
|
3652
|
+
message2 = String(payload?.message ?? payload?.error ?? "").trim();
|
|
3653
|
+
} catch {
|
|
3654
|
+
}
|
|
3655
|
+
if (!message2 && status === 404) {
|
|
3656
|
+
message2 = "Esta loja n\xE3o tem uma conta AbacatePay conectada.";
|
|
3657
|
+
}
|
|
3658
|
+
throw new Error(message2 || error.message);
|
|
3659
|
+
}
|
|
3660
|
+
function pushCatalogue() {
|
|
3661
|
+
return invoke({ action: "push_products" });
|
|
3662
|
+
}
|
|
3663
|
+
function reconcileCatalogue() {
|
|
3664
|
+
return invoke({ action: "reconcile" });
|
|
3665
|
+
}
|
|
3633
3666
|
var ABACATEPAY_CONNECTOR_ID = "abacatepay";
|
|
3634
3667
|
var ABACATEPAY_LATENCY_BUDGET_MS = 6e3;
|
|
3635
3668
|
var ABACATEPAY_FIELDS = [
|
|
@@ -3649,8 +3682,13 @@ var ABACATEPAY_SETTINGS = [
|
|
|
3649
3682
|
type: "multi-select",
|
|
3650
3683
|
options: [
|
|
3651
3684
|
{ value: "PIX", label: "Pix" },
|
|
3652
|
-
{ value: "BOLETO", label: "Boleto" }
|
|
3653
|
-
|
|
3685
|
+
{ value: "BOLETO", label: "Boleto" }
|
|
3686
|
+
// Credit card does NOT belong here. AbacatePay discontinued it for new
|
|
3687
|
+
// clients and new integrations, so offering the checkbox would let a
|
|
3688
|
+
// merchant switch on a method the acquirer refuses — and the first to find
|
|
3689
|
+
// out would be a buyer. `CARD` stays in METHOD_LABELS because an older
|
|
3690
|
+
// connection may have the option stored and its row still has to describe
|
|
3691
|
+
// itself.
|
|
3654
3692
|
],
|
|
3655
3693
|
requiredToOperate: true
|
|
3656
3694
|
}
|
|
@@ -3665,6 +3703,97 @@ function methodsDetail2(value) {
|
|
|
3665
3703
|
const labels = list.map((v) => METHOD_LABELS2[String(v).trim()] ?? String(v).trim()).filter(Boolean);
|
|
3666
3704
|
return labels.length > 0 ? labels.join(", ") : void 0;
|
|
3667
3705
|
}
|
|
3706
|
+
function CatalogueSync() {
|
|
3707
|
+
const [busy, setBusy] = useState(null);
|
|
3708
|
+
const [result, setResult] = useState(null);
|
|
3709
|
+
const [error, setError] = useState(null);
|
|
3710
|
+
const run = async (kind) => {
|
|
3711
|
+
setBusy(kind);
|
|
3712
|
+
setError(null);
|
|
3713
|
+
try {
|
|
3714
|
+
setResult(await (kind === "push" ? pushCatalogue() : reconcileCatalogue()));
|
|
3715
|
+
} catch (caught) {
|
|
3716
|
+
setError(caught instanceof Error ? caught.message : "N\xE3o conseguimos sincronizar agora.");
|
|
3717
|
+
} finally {
|
|
3718
|
+
setBusy(null);
|
|
3719
|
+
}
|
|
3720
|
+
};
|
|
3721
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
3722
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
3723
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-foreground", children: "Cat\xE1logo" }),
|
|
3724
|
+
/* @__PURE__ */ jsx("p", { className: "mt-0.5 text-xs text-muted-foreground", children: "O link de pagamento \xE9 aberto na p\xE1gina da AbacatePay, e ela cobra por produtos que precisam existir l\xE1. Envie os seus antes de mandar um link para um cliente." })
|
|
3725
|
+
] }),
|
|
3726
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
|
|
3727
|
+
/* @__PURE__ */ jsx(
|
|
3728
|
+
"button",
|
|
3729
|
+
{
|
|
3730
|
+
type: "button",
|
|
3731
|
+
onClick: () => {
|
|
3732
|
+
void run("push");
|
|
3733
|
+
},
|
|
3734
|
+
disabled: busy !== null,
|
|
3735
|
+
className: "inline-flex min-h-9 items-center rounded-md bg-primary px-3 text-xs font-medium text-primary-foreground transition hover:opacity-90 disabled:opacity-60",
|
|
3736
|
+
children: busy === "push" ? "Enviando\u2026" : "Enviar produtos"
|
|
3737
|
+
}
|
|
3738
|
+
),
|
|
3739
|
+
/* @__PURE__ */ jsx(
|
|
3740
|
+
"button",
|
|
3741
|
+
{
|
|
3742
|
+
type: "button",
|
|
3743
|
+
onClick: () => {
|
|
3744
|
+
void run("reconcile");
|
|
3745
|
+
},
|
|
3746
|
+
disabled: busy !== null,
|
|
3747
|
+
className: "inline-flex min-h-9 items-center rounded-md border px-3 text-xs font-medium transition hover:bg-muted/50 disabled:opacity-60",
|
|
3748
|
+
children: busy === "reconcile" ? "Conferindo\u2026" : "Conferir pre\xE7os"
|
|
3749
|
+
}
|
|
3750
|
+
)
|
|
3751
|
+
] }),
|
|
3752
|
+
error && /* @__PURE__ */ jsx("p", { className: "text-xs text-destructive", children: error }),
|
|
3753
|
+
result && /* @__PURE__ */ jsxs("div", { className: "space-y-1.5 rounded-md border bg-muted/30 p-3 text-xs", children: [
|
|
3754
|
+
/* @__PURE__ */ jsxs("p", { className: "text-foreground", children: [
|
|
3755
|
+
result.pushed > 0 ? `${result.pushed} produto${result.pushed > 1 ? "s" : ""} enviado${result.pushed > 1 ? "s" : ""}.` : "Nenhum produto novo para enviar.",
|
|
3756
|
+
" ",
|
|
3757
|
+
/* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
|
|
3758
|
+
result.unchanged,
|
|
3759
|
+
" j\xE1 ",
|
|
3760
|
+
result.unchanged === 1 ? "estava" : "estavam",
|
|
3761
|
+
" l\xE1, de ",
|
|
3762
|
+
result.total,
|
|
3763
|
+
"."
|
|
3764
|
+
] })
|
|
3765
|
+
] }),
|
|
3766
|
+
result.hasMore && /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: "Ainda h\xE1 produtos na fila \u2014 clique novamente para continuar." }),
|
|
3767
|
+
result.withoutImage?.length > 0 && /* @__PURE__ */ jsxs("p", { className: "text-muted-foreground", children: [
|
|
3768
|
+
result.withoutImage.length,
|
|
3769
|
+
" produto",
|
|
3770
|
+
result.withoutImage.length > 1 ? "s foram enviados" : " foi enviado",
|
|
3771
|
+
" sem foto \u2014 a AbacatePay recusou a imagem. O produto vende normalmente; s\xF3 aparece sem imagem na p\xE1gina dela."
|
|
3772
|
+
] }),
|
|
3773
|
+
result.skipped?.length > 0 && /* @__PURE__ */ jsxs("p", { className: "text-muted-foreground", children: [
|
|
3774
|
+
result.skipped.length,
|
|
3775
|
+
" ignorado",
|
|
3776
|
+
result.skipped.length > 1 ? "s" : "",
|
|
3777
|
+
" por estar sem nome ou com pre\xE7o zerado."
|
|
3778
|
+
] }),
|
|
3779
|
+
result.failed?.length > 0 && /* @__PURE__ */ jsxs("div", { className: "text-destructive", children: [
|
|
3780
|
+
/* @__PURE__ */ jsxs("p", { children: [
|
|
3781
|
+
result.failed.length,
|
|
3782
|
+
" recusado",
|
|
3783
|
+
result.failed.length > 1 ? "s" : "",
|
|
3784
|
+
" pela AbacatePay:"
|
|
3785
|
+
] }),
|
|
3786
|
+
/* @__PURE__ */ jsx("ul", { className: "mt-0.5 list-disc pl-4", children: result.failed.slice(0, 3).map((f) => /* @__PURE__ */ jsx("li", { children: f.error }, f.productId)) })
|
|
3787
|
+
] }),
|
|
3788
|
+
result.drifted && result.drifted.length > 0 && /* @__PURE__ */ jsxs("p", { className: "text-amber-600 dark:text-amber-500", children: [
|
|
3789
|
+
result.drifted.length,
|
|
3790
|
+
" produto",
|
|
3791
|
+
result.drifted.length > 1 ? "s mudaram" : " mudou",
|
|
3792
|
+
" de pre\xE7o aqui depois de enviado. A AbacatePay n\xE3o permite alterar um produto j\xE1 criado, ent\xE3o o link ainda cobra o pre\xE7o antigo \u2014 refa\xE7a o produto l\xE1 se o novo valor precisa valer."
|
|
3793
|
+
] })
|
|
3794
|
+
] })
|
|
3795
|
+
] });
|
|
3796
|
+
}
|
|
3668
3797
|
function AbacatePayExtraPanel() {
|
|
3669
3798
|
const [connected, setConnected] = useState(false);
|
|
3670
3799
|
const [loaded, setLoaded] = useState(false);
|
|
@@ -3681,17 +3810,20 @@ function AbacatePayExtraPanel() {
|
|
|
3681
3810
|
};
|
|
3682
3811
|
}, []);
|
|
3683
3812
|
if (!loaded || !connected) return null;
|
|
3684
|
-
return /* @__PURE__ */ jsxs("div", { className: "space-y-
|
|
3685
|
-
/* @__PURE__ */ jsx(
|
|
3686
|
-
/* @__PURE__ */
|
|
3687
|
-
|
|
3813
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-4 border-t pt-4", children: [
|
|
3814
|
+
/* @__PURE__ */ jsx(CatalogueSync, {}),
|
|
3815
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2 text-xs text-muted-foreground", children: [
|
|
3816
|
+
/* @__PURE__ */ jsx("p", { children: "Pix e boleto acontecem dentro da sua loja: o cliente v\xEA o QR Code ou a linha digit\xE1vel sem sair da p\xE1gina. Cart\xE3o de cr\xE9dito a AbacatePay encerrou para contas novas \u2014 para vender no cart\xE3o, conecte outro provedor em Pagamentos." }),
|
|
3817
|
+
/* @__PURE__ */ jsx("p", { children: "Quem decide se a cobran\xE7a \xE9 de verdade \xE9 a chave. Uma chave de teste simula o pagamento e n\xE3o movimenta dinheiro; a de produ\xE7\xE3o cobra o cliente. \xC9 a mesma tela para as duas, ent\xE3o confira no painel da AbacatePay qual chave voc\xEA colou aqui." }),
|
|
3818
|
+
/* @__PURE__ */ jsx("p", { children: 'O valor cobrado \xE9 sempre recalculado aqui no servidor a partir do pedido. Pre\xE7o alterado no navegador n\xE3o \xE9 aceito, e clicar duas vezes em "pagar" gera uma cobran\xE7a s\xF3.' })
|
|
3819
|
+
] })
|
|
3688
3820
|
] });
|
|
3689
3821
|
}
|
|
3690
3822
|
var abacatePayConnectorDef = {
|
|
3691
3823
|
id: ABACATEPAY_CONNECTOR_ID,
|
|
3692
3824
|
hostPluginId: "shop",
|
|
3693
3825
|
name: "AbacatePay",
|
|
3694
|
-
description: "Pix
|
|
3826
|
+
description: "Pix e boleto com uma chave s\xF3, sem contrato de adquirente e sem tirar o cliente da loja.",
|
|
3695
3827
|
icon: "CreditCard",
|
|
3696
3828
|
category: "payments",
|
|
3697
3829
|
// One pasted key, no consent screen: AbacatePay has no OAuth and no app to
|
|
@@ -3740,7 +3872,7 @@ var abacatePayConnectorDef = {
|
|
|
3740
3872
|
invokedAt: [
|
|
3741
3873
|
{
|
|
3742
3874
|
key: "shop.checkout.session_open",
|
|
3743
|
-
label: "O cliente finaliza a compra e a cobran\xE7a \xE9 aberta na AbacatePay (Pix
|
|
3875
|
+
label: "O cliente finaliza a compra e a cobran\xE7a \xE9 aberta na AbacatePay (Pix ou boleto)",
|
|
3744
3876
|
touches: ["order", "payment"]
|
|
3745
3877
|
},
|
|
3746
3878
|
{
|
|
@@ -3928,26 +4060,80 @@ var VINDI_ENVIRONMENT_SETTING = {
|
|
|
3928
4060
|
],
|
|
3929
4061
|
requiredToOperate: true
|
|
3930
4062
|
};
|
|
4063
|
+
var VINDI_CARD_METHOD = "3";
|
|
3931
4064
|
var VINDI_SETTINGS = [
|
|
3932
4065
|
VINDI_ENVIRONMENT_SETTING,
|
|
3933
4066
|
{
|
|
3934
4067
|
key: "methods",
|
|
3935
4068
|
label: "Formas de pagamento",
|
|
3936
|
-
description: "O que o cliente pode escolher
|
|
4069
|
+
description: "O que o cliente pode escolher. O cart\xE3o \xE9 pago na p\xE1gina segura da Vindi.",
|
|
3937
4070
|
type: "multi-select",
|
|
3938
4071
|
options: [
|
|
3939
4072
|
{ value: "27", label: "Pix" },
|
|
3940
4073
|
{ value: "28", label: "Bolepix (boleto com QR)" },
|
|
3941
|
-
{ value: "6", label: "Boleto" }
|
|
4074
|
+
{ value: "6", label: "Boleto" },
|
|
4075
|
+
{ value: VINDI_CARD_METHOD, label: "Cart\xE3o de cr\xE9dito (p\xE1gina da Vindi)" }
|
|
3942
4076
|
],
|
|
3943
4077
|
requiredToOperate: true
|
|
4078
|
+
},
|
|
4079
|
+
/**
|
|
4080
|
+
* The seller's postcode, which Vindi's cart endpoint refuses to open without.
|
|
4081
|
+
*
|
|
4082
|
+
* NOT `requiredToOperate` in the static list — a store selling Pix has never
|
|
4083
|
+
* needed it, and turning it into a requirement would put every working
|
|
4084
|
+
* connection into "falta configurar" the day this version ships. It becomes
|
|
4085
|
+
* required the moment card is enabled: see `requiredSettingsFor`.
|
|
4086
|
+
*/
|
|
4087
|
+
{
|
|
4088
|
+
key: "sellerPostalCode",
|
|
4089
|
+
label: "CEP da loja",
|
|
4090
|
+
description: "De onde a loja vende. A Vindi exige esse dado para abrir a p\xE1gina de cart\xE3o.",
|
|
4091
|
+
type: "text",
|
|
4092
|
+
placeholder: "01310-100",
|
|
4093
|
+
pattern: "\\d{5}-?\\d{3}",
|
|
4094
|
+
patternHint: "Oito d\xEDgitos, com ou sem h\xEDfen."
|
|
4095
|
+
},
|
|
4096
|
+
/**
|
|
4097
|
+
* How many instalments Vindi's page may offer.
|
|
4098
|
+
*
|
|
4099
|
+
* A `select` rather than free text because it is a number with a ceiling the
|
|
4100
|
+
* merchant does not know: Vindi refuses a split above what the account was
|
|
4101
|
+
* accredited for, and a typed "24" would be a checkout that fails at the last
|
|
4102
|
+
* click. The default is 1 — a store that never thought about instalments
|
|
4103
|
+
* should not discover it is financing purchases.
|
|
4104
|
+
*/
|
|
4105
|
+
{
|
|
4106
|
+
key: "maxSplit",
|
|
4107
|
+
label: "Parcelas no cart\xE3o",
|
|
4108
|
+
description: "Em quantas vezes o cliente pode dividir. Depende do que a Vindi liberou para a conta.",
|
|
4109
|
+
type: "select",
|
|
4110
|
+
options: [
|
|
4111
|
+
{ value: "1", label: "\xC0 vista" },
|
|
4112
|
+
{ value: "2", label: "At\xE9 2x" },
|
|
4113
|
+
{ value: "3", label: "At\xE9 3x" },
|
|
4114
|
+
{ value: "6", label: "At\xE9 6x" },
|
|
4115
|
+
{ value: "10", label: "At\xE9 10x" },
|
|
4116
|
+
{ value: "12", label: "At\xE9 12x" }
|
|
4117
|
+
],
|
|
4118
|
+
defaultValue: "1"
|
|
3944
4119
|
}
|
|
3945
4120
|
];
|
|
4121
|
+
function requiredSettingsFor(settings) {
|
|
4122
|
+
const raw = settings?.methods;
|
|
4123
|
+
const list = Array.isArray(raw) ? raw : String(raw ?? "").split(",");
|
|
4124
|
+
const hasCard = list.map((v) => String(v).trim()).includes(VINDI_CARD_METHOD);
|
|
4125
|
+
return VINDI_SETTINGS.map((setting) => setting.key === "sellerPostalCode" && hasCard ? { ...setting, requiredToOperate: true } : setting);
|
|
4126
|
+
}
|
|
3946
4127
|
var store5 = createConnectionStore(VINDI_CONNECTOR_ID, {
|
|
3947
4128
|
fields: VINDI_FIELDS,
|
|
3948
4129
|
settings: VINDI_SETTINGS
|
|
3949
4130
|
});
|
|
3950
|
-
var METHOD_LABELS4 = {
|
|
4131
|
+
var METHOD_LABELS4 = {
|
|
4132
|
+
"27": "Pix",
|
|
4133
|
+
"28": "Bolepix",
|
|
4134
|
+
"6": "Boleto",
|
|
4135
|
+
[VINDI_CARD_METHOD]: "Cart\xE3o"
|
|
4136
|
+
};
|
|
3951
4137
|
var ENVIRONMENT_LABELS = { sandbox: "Sandbox", production: "Produ\xE7\xE3o" };
|
|
3952
4138
|
function connectionDetail(settings) {
|
|
3953
4139
|
const environment = ENVIRONMENT_LABELS[String(settings?.environment ?? "")];
|
|
@@ -3974,7 +4160,12 @@ function VindiExtraPanel() {
|
|
|
3974
4160
|
}, []);
|
|
3975
4161
|
if (!loaded) return null;
|
|
3976
4162
|
return /* @__PURE__ */ jsx("div", { className: "space-y-2 border-t pt-4 text-xs text-muted-foreground", children: connected ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3977
|
-
/* @__PURE__ */ jsx("p", { children: "Pix e boleto acontecem dentro da sua loja: o cliente v\xEA o QR Code ou a linha digit\xE1vel sem sair da p\xE1gina.
|
|
4163
|
+
/* @__PURE__ */ jsx("p", { children: "Pix e boleto acontecem dentro da sua loja: o cliente v\xEA o QR Code ou a linha digit\xE1vel sem sair da p\xE1gina. O cart\xE3o \xE9 diferente \u2014 ele \xE9 digitado na p\xE1gina segura da Vindi, e o cliente volta para a loja em seguida. \xC9 assim de prop\xF3sito: nenhum n\xFAmero de cart\xE3o passa pelo seu site." }),
|
|
4164
|
+
/* @__PURE__ */ jsxs("p", { children: [
|
|
4165
|
+
"Voc\xEA tamb\xE9m pode gerar um ",
|
|
4166
|
+
/* @__PURE__ */ jsx("strong", { children: "link de pagamento" }),
|
|
4167
|
+
" em Pedidos \u2192 Novo e mandar no WhatsApp. O cliente escolhe como pagar na p\xE1gina da Vindi, e o pedido aparece aqui sozinho quando o dinheiro cair."
|
|
4168
|
+
] }),
|
|
3978
4169
|
/* @__PURE__ */ jsx("p", { children: "Sandbox e produ\xE7\xE3o s\xE3o contas diferentes, com tokens diferentes. Se voc\xEA trocar o ambiente aqui, troque tamb\xE9m as credenciais \u2014 as de teste n\xE3o cobram em produ\xE7\xE3o e as de produ\xE7\xE3o n\xE3o funcionam no sandbox." }),
|
|
3979
4170
|
/* @__PURE__ */ jsx("p", { children: 'O valor cobrado \xE9 sempre recalculado aqui no servidor a partir do pedido. Pre\xE7o alterado no navegador n\xE3o \xE9 aceito, e clicar duas vezes em "pagar" gera uma cobran\xE7a s\xF3.' })
|
|
3980
4171
|
] }) : /* @__PURE__ */ jsx("p", { children: "O token da conta voc\xEA pega no painel da Vindi Pagamentos, em Minha Conta. Confira se ele \xE9 o do mesmo ambiente que voc\xEA vai escolher aqui \u2014 o token de sandbox n\xE3o cobra em produ\xE7\xE3o." }) });
|
|
@@ -3983,7 +4174,7 @@ var vindiConnectorDef = {
|
|
|
3983
4174
|
id: VINDI_CONNECTOR_ID,
|
|
3984
4175
|
hostPluginId: "shop",
|
|
3985
4176
|
name: "Vindi",
|
|
3986
|
-
description: "Pix e
|
|
4177
|
+
description: "Pix, boleto e cart\xE3o pela Vindi. A loja recebe na conta dela; o cart\xE3o \xE9 digitado na p\xE1gina segura da Vindi.",
|
|
3987
4178
|
icon: "CreditCard",
|
|
3988
4179
|
// Declared rather than borrowed from the catalogue, because the catalogue row
|
|
3989
4180
|
// is a change in another repo that has to be seeded before it exists anywhere:
|
|
@@ -4021,7 +4212,7 @@ var vindiConnectorDef = {
|
|
|
4021
4212
|
kind: "data",
|
|
4022
4213
|
resource: "payment",
|
|
4023
4214
|
actions: ["write"],
|
|
4024
|
-
reason: "Registrar aqui a cobran\xE7a aberta e a confirma\xE7\xE3o do pagamento. Dados do cart\xE3o n\xE3o passam por este app.",
|
|
4215
|
+
reason: "Registrar aqui a cobran\xE7a aberta e a confirma\xE7\xE3o do pagamento. Dados do cart\xE3o n\xE3o passam por este app \u2014 s\xE3o digitados na p\xE1gina da Vindi.",
|
|
4025
4216
|
sensitive: true
|
|
4026
4217
|
}
|
|
4027
4218
|
],
|
|
@@ -4035,7 +4226,7 @@ var vindiConnectorDef = {
|
|
|
4035
4226
|
invokedAt: [
|
|
4036
4227
|
{
|
|
4037
4228
|
key: "shop.checkout.session_open",
|
|
4038
|
-
label: "O cliente finaliza a compra e a cobran\xE7a \xE9 aberta na Vindi (Pix ou
|
|
4229
|
+
label: "O cliente finaliza a compra e a cobran\xE7a \xE9 aberta na Vindi (Pix, boleto ou a p\xE1gina de cart\xE3o)",
|
|
4039
4230
|
touches: ["order", "payment"]
|
|
4040
4231
|
},
|
|
4041
4232
|
{
|
|
@@ -4054,7 +4245,10 @@ var vindiConnectorDef = {
|
|
|
4054
4245
|
connected: !!connection?.active,
|
|
4055
4246
|
detail: connectionDetail(connection?.settings),
|
|
4056
4247
|
plane: "request",
|
|
4057
|
-
|
|
4248
|
+
// Judged against what THIS connection needs, not against a constant: a
|
|
4249
|
+
// store that ticked card owes a postcode, and one that did not owes
|
|
4250
|
+
// nothing. See `requiredSettingsFor`.
|
|
4251
|
+
...settingsStatus(requiredSettingsFor(connection?.settings), connection)
|
|
4058
4252
|
}),
|
|
4059
4253
|
{ store: () => store5 }
|
|
4060
4254
|
),
|
|
@@ -4582,116 +4776,138 @@ function MediaDetail({
|
|
|
4582
4776
|
document.addEventListener("keydown", onKey);
|
|
4583
4777
|
return () => document.removeEventListener("keydown", onKey);
|
|
4584
4778
|
}, [onNavigate]);
|
|
4585
|
-
return
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
|
|
4595
|
-
|
|
4596
|
-
|
|
4597
|
-
|
|
4598
|
-
|
|
4599
|
-
|
|
4600
|
-
|
|
4601
|
-
" de ",
|
|
4602
|
-
position.total
|
|
4603
|
-
] }),
|
|
4604
|
-
/* @__PURE__ */ jsx(
|
|
4605
|
-
"button",
|
|
4606
|
-
{
|
|
4607
|
-
type: "button",
|
|
4608
|
-
"aria-label": "Pr\xF3ximo arquivo",
|
|
4609
|
-
disabled: position.index === position.total - 1,
|
|
4610
|
-
onClick: () => onNavigate(1),
|
|
4611
|
-
className: "rounded-md border p-1 transition hover:bg-muted disabled:opacity-40",
|
|
4612
|
-
children: /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4" })
|
|
4613
|
-
}
|
|
4614
|
-
)
|
|
4615
|
-
] }) }),
|
|
4616
|
-
/* @__PURE__ */ jsxs("div", { className: "fz-split", children: [
|
|
4617
|
-
/* @__PURE__ */ jsx(Card, { className: "flex min-h-[320px] items-center justify-center overflow-hidden bg-muted p-2", children: file.kind === "image" ? /* @__PURE__ */ jsx(
|
|
4618
|
-
"img",
|
|
4619
|
-
{
|
|
4620
|
-
src: file.url,
|
|
4621
|
-
alt: file.name,
|
|
4622
|
-
className: "max-h-[70vh] w-auto max-w-full object-contain",
|
|
4623
|
-
onLoad: (e) => {
|
|
4624
|
-
const img = e.currentTarget;
|
|
4625
|
-
if (img.naturalWidth) onMeasured({ width: img.naturalWidth, height: img.naturalHeight });
|
|
4779
|
+
return (
|
|
4780
|
+
// `fz-container` é o ponto de MEDIÇÃO: sem ele a container query de
|
|
4781
|
+
// `fz-split` nunca casa e as duas colunas ficam empilhadas para sempre,
|
|
4782
|
+
// por mais larga que a janela esteja.
|
|
4783
|
+
/* @__PURE__ */ jsxs("div", { className: "fz-container space-y-4", children: [
|
|
4784
|
+
/* @__PURE__ */ jsx(PageHeader, { title: file.name, parentLabel: "Conte\xFAdo", onBack }),
|
|
4785
|
+
position.total > 1 && /* @__PURE__ */ jsx("div", { className: "flex items-center justify-end gap-3", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 text-xs text-muted-foreground", children: [
|
|
4786
|
+
/* @__PURE__ */ jsx(
|
|
4787
|
+
"button",
|
|
4788
|
+
{
|
|
4789
|
+
type: "button",
|
|
4790
|
+
"aria-label": "Arquivo anterior",
|
|
4791
|
+
disabled: position.index === 0,
|
|
4792
|
+
onClick: () => onNavigate(-1),
|
|
4793
|
+
className: "rounded-md border p-1 transition hover:bg-muted disabled:opacity-40",
|
|
4794
|
+
children: /* @__PURE__ */ jsx(ChevronLeft, { className: "h-4 w-4" })
|
|
4626
4795
|
}
|
|
4627
|
-
|
|
4628
|
-
|
|
4629
|
-
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
] }) }),
|
|
4633
|
-
/* @__PURE__ */ jsxs(Card, { className: "space-y-4 p-4", children: [
|
|
4634
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
4635
|
-
/* @__PURE__ */ jsx("p", { className: "break-words font-medium", title: file.name, children: file.name }),
|
|
4636
|
-
/* @__PURE__ */ jsx("p", { className: "mt-0.5 text-xs text-muted-foreground", children: /* @__PURE__ */ jsx(FileMeta, { file, dimensions }) }),
|
|
4637
|
-
isLowResolution(file, dimensions) && /* @__PURE__ */ jsxs("p", { className: "mt-2 rounded-md bg-warning/10 px-2 py-1.5 text-xs font-medium text-warning", children: [
|
|
4638
|
-
"Baixa resolu\xE7\xE3o \u2014 no zoom da loja essa foto fica borrada. Troque por uma de pelo menos ",
|
|
4639
|
-
LOW_RESOLUTION_PX,
|
|
4640
|
-
"px no lado maior."
|
|
4641
|
-
] })
|
|
4642
|
-
] }),
|
|
4643
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
4644
|
-
/* @__PURE__ */ jsx("p", { className: "text-[11px] uppercase tracking-wide text-muted-foreground", children: "Onde \xE9 usada" }),
|
|
4645
|
-
file.reference ? /* @__PURE__ */ jsx(RecordLink, { reference: file.reference, className: "mt-1 text-sm" }) : /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: "Biblioteca \u2014 este arquivo n\xE3o est\xE1 preso a nenhum registro." }),
|
|
4646
|
-
file.reference?.isCover && /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: "\xC9 a capa: \xE9 ela que aparece no cat\xE1logo, no carrinho e no pedido." })
|
|
4796
|
+
),
|
|
4797
|
+
/* @__PURE__ */ jsxs("span", { className: "px-1 tabular-nums", children: [
|
|
4798
|
+
position.index + 1,
|
|
4799
|
+
" de ",
|
|
4800
|
+
position.total
|
|
4647
4801
|
] }),
|
|
4648
|
-
/* @__PURE__ */
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
|
|
4802
|
+
/* @__PURE__ */ jsx(
|
|
4803
|
+
"button",
|
|
4804
|
+
{
|
|
4805
|
+
type: "button",
|
|
4806
|
+
"aria-label": "Pr\xF3ximo arquivo",
|
|
4807
|
+
disabled: position.index === position.total - 1,
|
|
4808
|
+
onClick: () => onNavigate(1),
|
|
4809
|
+
className: "rounded-md border p-1 transition hover:bg-muted disabled:opacity-40",
|
|
4810
|
+
children: /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4" })
|
|
4811
|
+
}
|
|
4812
|
+
)
|
|
4813
|
+
] }) }),
|
|
4814
|
+
/* @__PURE__ */ jsxs("div", { className: "fz-split", children: [
|
|
4815
|
+
/* @__PURE__ */ jsx(Card, { className: "flex min-h-[320px] items-center justify-center overflow-hidden bg-muted p-2", children: file.kind === "image" ? /* @__PURE__ */ jsx(
|
|
4816
|
+
"img",
|
|
4817
|
+
{
|
|
4818
|
+
src: file.url,
|
|
4819
|
+
alt: file.name,
|
|
4820
|
+
className: "max-h-[70vh] w-auto max-w-full object-contain",
|
|
4821
|
+
onLoad: (e) => {
|
|
4822
|
+
const img = e.currentTarget;
|
|
4823
|
+
if (img.naturalWidth) onMeasured({ width: img.naturalWidth, height: img.naturalHeight });
|
|
4824
|
+
}
|
|
4825
|
+
},
|
|
4826
|
+
file.url
|
|
4827
|
+
) : /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2 p-12 text-muted-foreground", children: [
|
|
4828
|
+
/* @__PURE__ */ jsx(KindIcon, { kind: file.kind, className: "h-10 w-10" }),
|
|
4829
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm", children: "Pr\xE9-visualiza\xE7\xE3o n\xE3o dispon\xEDvel" })
|
|
4830
|
+
] }) }),
|
|
4831
|
+
/* @__PURE__ */ jsxs(Card, { className: "space-y-4 p-4", children: [
|
|
4832
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4833
|
+
/* @__PURE__ */ jsx("p", { className: "break-words font-medium", title: file.name, children: file.name }),
|
|
4834
|
+
/* @__PURE__ */ jsx("p", { className: "mt-0.5 text-xs text-muted-foreground", children: /* @__PURE__ */ jsx(FileMeta, { file, dimensions }) }),
|
|
4835
|
+
isLowResolution(file, dimensions) && /* @__PURE__ */ jsxs("p", { className: "mt-2 rounded-md bg-warning/10 px-2 py-1.5 text-xs font-medium text-warning", children: [
|
|
4836
|
+
"Baixa resolu\xE7\xE3o \u2014 no zoom da loja essa foto fica borrada. Troque por uma de pelo menos ",
|
|
4837
|
+
LOW_RESOLUTION_PX,
|
|
4838
|
+
"px no lado maior."
|
|
4839
|
+
] })
|
|
4652
4840
|
] }),
|
|
4653
|
-
/* @__PURE__ */
|
|
4654
|
-
/* @__PURE__ */ jsx(
|
|
4655
|
-
"
|
|
4656
|
-
|
|
4657
|
-
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
|
|
4661
|
-
ref: replaceRef,
|
|
4662
|
-
type: "file",
|
|
4663
|
-
accept: file.kind === "image" ? "image/*" : void 0,
|
|
4664
|
-
className: "hidden",
|
|
4665
|
-
onChange: (e) => {
|
|
4666
|
-
const picked = e.target.files?.[0];
|
|
4667
|
-
e.target.value = "";
|
|
4668
|
-
if (picked) onReplace(picked);
|
|
4669
|
-
}
|
|
4670
|
-
}
|
|
4671
|
-
),
|
|
4672
|
-
/* @__PURE__ */ jsxs(
|
|
4673
|
-
Button,
|
|
4841
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
4842
|
+
/* @__PURE__ */ jsx("p", { className: "text-[11px] uppercase tracking-wide text-muted-foreground", children: "Onde \xE9 usada" }),
|
|
4843
|
+
file.reference ? /* @__PURE__ */ jsx(RecordLink, { reference: file.reference, className: "mt-1 text-sm" }) : /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: "Biblioteca \u2014 este arquivo n\xE3o est\xE1 preso a nenhum registro." }),
|
|
4844
|
+
file.reference?.isCover && /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: "\xC9 a capa: \xE9 ela que aparece no cat\xE1logo, no carrinho e no pedido." })
|
|
4845
|
+
] }),
|
|
4846
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
4847
|
+
file.kind === "image" && /* @__PURE__ */ jsx(
|
|
4848
|
+
AskAIButton,
|
|
4674
4849
|
{
|
|
4675
|
-
variant: "outline",
|
|
4676
4850
|
className: "w-full",
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
|
|
4682
|
-
|
|
4851
|
+
size: "lg",
|
|
4852
|
+
label: "Melhorar com IA",
|
|
4853
|
+
media: { url: file.url, name: file.name },
|
|
4854
|
+
draft: "Melhora essa imagem",
|
|
4855
|
+
hint: "o que voc\xEA quer mudar nessa foto",
|
|
4856
|
+
intro: {
|
|
4857
|
+
persona: "Est\xFAdio de imagem",
|
|
4858
|
+
pitch: `Vamos melhorar ${file.name}.`,
|
|
4859
|
+
description: "Posso limpar o fundo, corrigir luz e cor, e gerar uma vers\xE3o em resolu\xE7\xE3o maior para o cat\xE1logo.",
|
|
4860
|
+
suggestions: [
|
|
4861
|
+
{ label: "Fundo branco", prompt: "Remove o fundo e deixa branco" },
|
|
4862
|
+
{ label: "Mais n\xEDtida", prompt: "Aumenta a resolu\xE7\xE3o e a nitidez" },
|
|
4863
|
+
{ label: "Corrigir a luz", prompt: "Corrige a ilumina\xE7\xE3o e as cores" }
|
|
4864
|
+
]
|
|
4865
|
+
}
|
|
4683
4866
|
}
|
|
4684
4867
|
),
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4868
|
+
/* @__PURE__ */ jsx(Button, { asChild: true, variant: "outline", className: "w-full", children: /* @__PURE__ */ jsxs("a", { href: downloadUrlOf(file), download: file.name, children: [
|
|
4869
|
+
/* @__PURE__ */ jsx(Download, { className: "mr-2 h-4 w-4" }),
|
|
4870
|
+
"Baixar"
|
|
4871
|
+
] }) }),
|
|
4872
|
+
onReplace && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4873
|
+
/* @__PURE__ */ jsx(
|
|
4874
|
+
"input",
|
|
4875
|
+
{
|
|
4876
|
+
ref: replaceRef,
|
|
4877
|
+
type: "file",
|
|
4878
|
+
accept: file.kind === "image" ? "image/*" : void 0,
|
|
4879
|
+
className: "hidden",
|
|
4880
|
+
onChange: (e) => {
|
|
4881
|
+
const picked = e.target.files?.[0];
|
|
4882
|
+
e.target.value = "";
|
|
4883
|
+
if (picked) onReplace(picked);
|
|
4884
|
+
}
|
|
4885
|
+
}
|
|
4886
|
+
),
|
|
4887
|
+
/* @__PURE__ */ jsxs(
|
|
4888
|
+
Button,
|
|
4889
|
+
{
|
|
4890
|
+
variant: "outline",
|
|
4891
|
+
className: "w-full",
|
|
4892
|
+
disabled: replacing,
|
|
4893
|
+
onClick: () => replaceRef.current?.click(),
|
|
4894
|
+
children: [
|
|
4895
|
+
/* @__PURE__ */ jsx(RefreshCw, { className: `mr-2 h-4 w-4 ${replacing ? "animate-spin" : ""}` }),
|
|
4896
|
+
replacing ? "Trocando\u2026" : "Trocar arquivo"
|
|
4897
|
+
]
|
|
4898
|
+
}
|
|
4899
|
+
),
|
|
4900
|
+
file.reference && /* @__PURE__ */ jsx("p", { className: "text-[11px] text-muted-foreground", children: "A troca mant\xE9m a posi\xE7\xE3o da foto na galeria do produto." })
|
|
4901
|
+
] }),
|
|
4902
|
+
onDelete && /* @__PURE__ */ jsxs(Button, { variant: "ghost", className: "w-full text-destructive hover:text-destructive", onClick: onDelete, children: [
|
|
4903
|
+
/* @__PURE__ */ jsx(Trash2, { className: "mr-2 h-4 w-4" }),
|
|
4904
|
+
"Excluir"
|
|
4905
|
+
] })
|
|
4690
4906
|
] })
|
|
4691
4907
|
] })
|
|
4692
4908
|
] })
|
|
4693
4909
|
] })
|
|
4694
|
-
|
|
4910
|
+
);
|
|
4695
4911
|
}
|
|
4696
4912
|
function RecordLink({ reference, className = "" }) {
|
|
4697
4913
|
return /* @__PURE__ */ jsxs(
|
|
@@ -4730,16 +4946,16 @@ var BLING_SAMPLE_SIZE = 100;
|
|
|
4730
4946
|
var BLING_SIGNATURE_HEADER = "x-bling-signature-256";
|
|
4731
4947
|
var BLING_WEBHOOK_DEADLINE_MS = 5e3;
|
|
4732
4948
|
var BLING_FUNCTION = "bling-sync";
|
|
4733
|
-
function
|
|
4949
|
+
function client2() {
|
|
4734
4950
|
const supabase = getSupabaseClientOptional();
|
|
4735
4951
|
if (!supabase) throw new Error("Sem conex\xE3o com o banco para falar com o Bling.");
|
|
4736
4952
|
return supabase;
|
|
4737
4953
|
}
|
|
4738
|
-
async function
|
|
4954
|
+
async function invoke2(body) {
|
|
4739
4955
|
const tenantId = getShopTenantId();
|
|
4740
4956
|
if (!tenantId) throw new Error("Sem loja selecionada para sincronizar com o Bling.");
|
|
4741
4957
|
const runtimeToken = await connectorRuntimeToken({ tenantId });
|
|
4742
|
-
const { data, error } = await
|
|
4958
|
+
const { data, error } = await client2().functions.invoke(BLING_FUNCTION, {
|
|
4743
4959
|
body: { ...body, tenantId },
|
|
4744
4960
|
headers: { [CONNECTOR_RUNTIME_TOKEN_HEADER]: runtimeToken }
|
|
4745
4961
|
});
|
|
@@ -4747,19 +4963,19 @@ async function invoke(body) {
|
|
|
4747
4963
|
return data;
|
|
4748
4964
|
}
|
|
4749
4965
|
function pullCatalogue(mode) {
|
|
4750
|
-
return
|
|
4966
|
+
return invoke2({ action: "pull_products", ...{ mode } });
|
|
4751
4967
|
}
|
|
4752
|
-
function
|
|
4753
|
-
return
|
|
4968
|
+
function pushCatalogue2() {
|
|
4969
|
+
return invoke2({ action: "push_products" });
|
|
4754
4970
|
}
|
|
4755
4971
|
function pushCustomers() {
|
|
4756
|
-
return
|
|
4972
|
+
return invoke2({ action: "push_customers" });
|
|
4757
4973
|
}
|
|
4758
4974
|
function pushOrders() {
|
|
4759
|
-
return
|
|
4975
|
+
return invoke2({ action: "push_orders" });
|
|
4760
4976
|
}
|
|
4761
4977
|
function pushStock() {
|
|
4762
|
-
return
|
|
4978
|
+
return invoke2({ action: "push_stock" });
|
|
4763
4979
|
}
|
|
4764
4980
|
async function countRows(table, apply) {
|
|
4765
4981
|
const tenantId = getShopTenantId();
|
|
@@ -4836,7 +5052,7 @@ async function listOrderDeliveries(limit = 10) {
|
|
|
4836
5052
|
});
|
|
4837
5053
|
}
|
|
4838
5054
|
function reconcile() {
|
|
4839
|
-
return
|
|
5055
|
+
return invoke2({ action: "reconcile" });
|
|
4840
5056
|
}
|
|
4841
5057
|
|
|
4842
5058
|
// src/integrations/bling/connectorDef.tsx
|
|
@@ -5062,7 +5278,7 @@ var blingConnectorDef = {
|
|
|
5062
5278
|
},
|
|
5063
5279
|
pending: pendingProducts,
|
|
5064
5280
|
run: async () => {
|
|
5065
|
-
const result = await
|
|
5281
|
+
const result = await pushCatalogue2();
|
|
5066
5282
|
return { message: result.message, status: result.status };
|
|
5067
5283
|
}
|
|
5068
5284
|
},
|
|
@@ -5275,6 +5491,311 @@ async function acceptWebhook(request, options) {
|
|
|
5275
5491
|
}
|
|
5276
5492
|
return { status: 200, queued: true };
|
|
5277
5493
|
}
|
|
5494
|
+
|
|
5495
|
+
// src/integrations/neochef/limits.ts
|
|
5496
|
+
var NEOCHEF_CONNECTOR_ID = "neochef";
|
|
5497
|
+
var NEOCHEF_RATE_LIMIT = { perSecond: 5, perDay: 5e4 };
|
|
5498
|
+
var NEOCHEF_PAGE_SIZE = 100;
|
|
5499
|
+
var NEOCHEF_SAMPLE_SIZE = 100;
|
|
5500
|
+
var NEOCHEF_CURSOR_OVERLAP_MS = 6e4;
|
|
5501
|
+
var NEOCHEF_TOKEN_LEAD_MS = 10 * 6e4;
|
|
5502
|
+
|
|
5503
|
+
// src/integrations/neochef/mark.ts
|
|
5504
|
+
var NEOCHEF_MARK = "data:image/png;base64,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";
|
|
5505
|
+
var NEOCHEF_FUNCTION = "neochef-sync";
|
|
5506
|
+
function client3() {
|
|
5507
|
+
const supabase = getSupabaseClientOptional();
|
|
5508
|
+
if (!supabase) throw new Error("Sem conex\xE3o com o banco para falar com o NeoChef.");
|
|
5509
|
+
return supabase;
|
|
5510
|
+
}
|
|
5511
|
+
async function invoke3(body) {
|
|
5512
|
+
const tenantId = getShopTenantId();
|
|
5513
|
+
if (!tenantId) throw new Error("Sem loja selecionada para sincronizar com o NeoChef.");
|
|
5514
|
+
const runtimeToken = await connectorRuntimeToken({ tenantId });
|
|
5515
|
+
const { data, error } = await client3().functions.invoke(NEOCHEF_FUNCTION, {
|
|
5516
|
+
body: { ...body, tenantId },
|
|
5517
|
+
headers: { [CONNECTOR_RUNTIME_TOKEN_HEADER]: runtimeToken }
|
|
5518
|
+
});
|
|
5519
|
+
if (error) throw new Error(error.message);
|
|
5520
|
+
return data;
|
|
5521
|
+
}
|
|
5522
|
+
function testNeoChef() {
|
|
5523
|
+
return invoke3({ action: "test" });
|
|
5524
|
+
}
|
|
5525
|
+
function pullCatalogue2(mode) {
|
|
5526
|
+
return invoke3({ action: "pull_products", ...mode ? { mode } : {} });
|
|
5527
|
+
}
|
|
5528
|
+
function pushOrders2() {
|
|
5529
|
+
return invoke3({ action: "push_orders" });
|
|
5530
|
+
}
|
|
5531
|
+
function reconcile2() {
|
|
5532
|
+
return invoke3({ action: "reconcile" });
|
|
5533
|
+
}
|
|
5534
|
+
async function pendingOrders2() {
|
|
5535
|
+
const tenantId = getShopTenantId();
|
|
5536
|
+
const supabase = getSupabaseClientOptional();
|
|
5537
|
+
if (!tenantId || !supabase) return null;
|
|
5538
|
+
const { data: linked } = await supabase.from("plg_shop_order_links").select("order_id").eq("tenant_id", tenantId).eq("source", "neochef").eq("kind", "kitchen_order");
|
|
5539
|
+
const already = new Set((linked ?? []).map((row) => row.order_id));
|
|
5540
|
+
const { data, error } = await supabase.from("plg_shop_orders").select("id").eq("tenant_id", tenantId).neq("status", "cancelled");
|
|
5541
|
+
if (error) return null;
|
|
5542
|
+
return (data ?? []).filter((row) => !already.has(row.id)).length;
|
|
5543
|
+
}
|
|
5544
|
+
async function listOrderDeliveries2(limit = 10) {
|
|
5545
|
+
const tenantId = getShopTenantId();
|
|
5546
|
+
const supabase = getSupabaseClientOptional();
|
|
5547
|
+
if (!tenantId || !supabase) return [];
|
|
5548
|
+
const { data: orders } = await supabase.from("plg_shop_orders").select("id,order_number,paid_at,created_at,customer_name,status").eq("tenant_id", tenantId).order("created_at", { ascending: false }).limit(limit);
|
|
5549
|
+
const rows = orders ?? [];
|
|
5550
|
+
if (rows.length === 0) return [];
|
|
5551
|
+
const { data: filed } = await supabase.from("plg_shop_order_links").select("order_id,external_id,external_number,synced_at").eq("tenant_id", tenantId).eq("source", "neochef").eq("kind", "kitchen_order").in("order_id", rows.map((row) => row.id));
|
|
5552
|
+
const byOrder = new Map(
|
|
5553
|
+
(filed ?? []).map((row) => [row.order_id, row])
|
|
5554
|
+
);
|
|
5555
|
+
return rows.map((order) => {
|
|
5556
|
+
const subject = order.order_number ? `Pedido ${order.order_number}` : "Pedido";
|
|
5557
|
+
const link = byOrder.get(order.id);
|
|
5558
|
+
if (link) {
|
|
5559
|
+
return {
|
|
5560
|
+
subject,
|
|
5561
|
+
subjectId: order.id,
|
|
5562
|
+
status: "delivered",
|
|
5563
|
+
externalId: link.external_number ?? link.external_id,
|
|
5564
|
+
at: link.synced_at ?? order.paid_at,
|
|
5565
|
+
...order.customer_name ? { detail: String(order.customer_name) } : {}
|
|
5566
|
+
};
|
|
5567
|
+
}
|
|
5568
|
+
if (String(order.status ?? "") === "cancelled") {
|
|
5569
|
+
return {
|
|
5570
|
+
subject,
|
|
5571
|
+
subjectId: order.id,
|
|
5572
|
+
status: "failed",
|
|
5573
|
+
detail: "Cancelado \u2014 n\xE3o sobe para a cozinha.",
|
|
5574
|
+
at: order.created_at
|
|
5575
|
+
};
|
|
5576
|
+
}
|
|
5577
|
+
return {
|
|
5578
|
+
subject,
|
|
5579
|
+
subjectId: order.id,
|
|
5580
|
+
status: "pending",
|
|
5581
|
+
detail: "Ainda n\xE3o subiu \u2014 vai na pr\xF3xima sincroniza\xE7\xE3o.",
|
|
5582
|
+
at: order.paid_at ?? order.created_at
|
|
5583
|
+
};
|
|
5584
|
+
});
|
|
5585
|
+
}
|
|
5586
|
+
|
|
5587
|
+
// src/integrations/neochef/connectorDef.tsx
|
|
5588
|
+
var neoChefConnectionStore = () => createConnectionStore(NEOCHEF_CONNECTOR_ID, {
|
|
5589
|
+
settingsKeys: ["kitchenId", "backfillFrom", "stockOwner"]
|
|
5590
|
+
});
|
|
5591
|
+
var neoChefConnectorDef = {
|
|
5592
|
+
id: NEOCHEF_CONNECTOR_ID,
|
|
5593
|
+
hostPluginId: "shop",
|
|
5594
|
+
name: "NeoChef",
|
|
5595
|
+
description: "Traz o card\xE1pio, o pre\xE7o e o estoque do NeoChef para a loja e devolve cada pedido pago como pedido na cozinha.",
|
|
5596
|
+
// The first question anyone connecting asks, answered before they connect.
|
|
5597
|
+
howItSyncs: [
|
|
5598
|
+
"De tempos em tempos, sozinho: desce do NeoChef o que mudou l\xE1 e sobe o que estiver pendente daqui.",
|
|
5599
|
+
"A qualquer momento, no bot\xE3o Sincronizar agora.",
|
|
5600
|
+
"Nada sobe duas vezes: cada pedido guarda o n\xFAmero que recebeu na cozinha.",
|
|
5601
|
+
"Produto desativado no NeoChef sai de venda na loja \u2014 nenhum produto \xE9 apagado."
|
|
5602
|
+
],
|
|
5603
|
+
icon: "ChefHat",
|
|
5604
|
+
// The app's own mark, so the row wears the same face the consent screen does.
|
|
5605
|
+
// `icon` stays as the fallback the mark resolver advances to — see mark.ts.
|
|
5606
|
+
logoUrl: NEOCHEF_MARK,
|
|
5607
|
+
authKind: "oauth",
|
|
5608
|
+
// `erp` and not `ecommerce`: NeoChef is the back office, not the storefront.
|
|
5609
|
+
// Same reading of §2 that moved Bling off the word 'commerce'.
|
|
5610
|
+
category: "erp",
|
|
5611
|
+
// Both ways, and the connector says so before anyone connects: the catalogue
|
|
5612
|
+
// comes in, the paid order goes out.
|
|
5613
|
+
direction: "inbound",
|
|
5614
|
+
planes: ["sync"],
|
|
5615
|
+
docsUrl: "https://fayz.ai/docs/integrations/neochef",
|
|
5616
|
+
/**
|
|
5617
|
+
* The consent names these, entity by entity, on NeoChef's own screen — this
|
|
5618
|
+
* list is what the STORE says it will do with them, which is the other half
|
|
5619
|
+
* of the same sentence.
|
|
5620
|
+
*
|
|
5621
|
+
* `shop_product` is read as well as written because the catalogue is a
|
|
5622
|
+
* MIRROR: `reconcileMirror` has to see what is here before it can decide what
|
|
5623
|
+
* a product missing from a page means.
|
|
5624
|
+
*/
|
|
5625
|
+
permissions: [
|
|
5626
|
+
{
|
|
5627
|
+
kind: "data",
|
|
5628
|
+
resource: "shop_product",
|
|
5629
|
+
actions: ["read", "write"],
|
|
5630
|
+
reason: "Trazer do NeoChef o card\xE1pio, o pre\xE7o e o saldo do estoque, comparando com o que j\xE1 est\xE1 na loja para n\xE3o duplicar nem tirar de venda por engano."
|
|
5631
|
+
},
|
|
5632
|
+
{
|
|
5633
|
+
kind: "data",
|
|
5634
|
+
resource: "shop_order",
|
|
5635
|
+
actions: ["read", "write"],
|
|
5636
|
+
// `write` is the LINK, not the order: without it every sync would file the
|
|
5637
|
+
// same sale again.
|
|
5638
|
+
reason: "Ler o pedido pago para lan\xE7\xE1-lo na cozinha, e guardar aqui o n\xFAmero que ele recebeu l\xE1. O conte\xFAdo do pedido n\xE3o \xE9 alterado.",
|
|
5639
|
+
sensitive: true
|
|
5640
|
+
},
|
|
5641
|
+
{
|
|
5642
|
+
kind: "event",
|
|
5643
|
+
resource: "shop.order_paid",
|
|
5644
|
+
actions: ["listen"],
|
|
5645
|
+
reason: "Saber que um pedido foi pago, para mand\xE1-lo para a cozinha."
|
|
5646
|
+
},
|
|
5647
|
+
{
|
|
5648
|
+
kind: "event",
|
|
5649
|
+
resource: "shop.order_cancelled",
|
|
5650
|
+
actions: ["listen"],
|
|
5651
|
+
reason: "Saber que um pedido foi cancelado, para n\xE3o mand\xE1-lo para a cozinha."
|
|
5652
|
+
}
|
|
5653
|
+
],
|
|
5654
|
+
// Declared, so the scheduler owns the clock. The budget is ours and not the
|
|
5655
|
+
// provider's — see limits.ts.
|
|
5656
|
+
rateLimit: NEOCHEF_RATE_LIMIT,
|
|
5657
|
+
// A connect screen that waits for a whole catalogue is a connect screen nobody
|
|
5658
|
+
// finishes, so the first load answers with a page and the backfill follows.
|
|
5659
|
+
firstLoad: { sampleSize: NEOCHEF_SAMPLE_SIZE, samplePages: 1, stream: "products" },
|
|
5660
|
+
// With underscores. `shop.order.paid` is not a key anything publishes — the
|
|
5661
|
+
// shop builds its facts as `shop.${def.event}` over SHOP_EMAIL_EVENTS.
|
|
5662
|
+
subscribesTo: ["shop.order_paid", "shop.order_cancelled"],
|
|
5663
|
+
managedAutomations: [
|
|
5664
|
+
{ eventKey: "shop.order_paid", label: "Mandar o pedido pago para a cozinha do NeoChef" },
|
|
5665
|
+
{ eventKey: "shop.order_cancelled", label: "Parar de mandar para a cozinha um pedido cancelado" }
|
|
5666
|
+
],
|
|
5667
|
+
// What HAPPENS, not what is declared. Nothing here names a moment that has no
|
|
5668
|
+
// code behind it.
|
|
5669
|
+
invokedAt: [
|
|
5670
|
+
{
|
|
5671
|
+
key: "shop.order.push",
|
|
5672
|
+
label: "O pedido pago sobe como pedido na cozinha",
|
|
5673
|
+
plane: "sync",
|
|
5674
|
+
trigger: "scheduled",
|
|
5675
|
+
touches: ["shop_order"]
|
|
5676
|
+
},
|
|
5677
|
+
{
|
|
5678
|
+
key: "shop.catalogue.pull",
|
|
5679
|
+
label: "O card\xE1pio, o pre\xE7o e o estoque do NeoChef descem para a loja",
|
|
5680
|
+
plane: "sync",
|
|
5681
|
+
trigger: "scheduled",
|
|
5682
|
+
touches: ["shop_product"]
|
|
5683
|
+
}
|
|
5684
|
+
],
|
|
5685
|
+
// Read from the row the list already batched — one request for N connectors.
|
|
5686
|
+
...connectionStatus(
|
|
5687
|
+
NEOCHEF_CONNECTOR_ID,
|
|
5688
|
+
(connection) => {
|
|
5689
|
+
if (!connection?.active) return { connected: false };
|
|
5690
|
+
const kitchen = connection.settings?.kitchenId;
|
|
5691
|
+
return {
|
|
5692
|
+
connected: connection.status === "connected",
|
|
5693
|
+
detail: kitchen ? `Cozinha ${kitchen}` : void 0,
|
|
5694
|
+
plane: "sync"
|
|
5695
|
+
};
|
|
5696
|
+
},
|
|
5697
|
+
{ store: neoChefConnectionStore }
|
|
5698
|
+
),
|
|
5699
|
+
// The whole connect step. Declaring `oauth` and no `startOAuth` is what renders
|
|
5700
|
+
// the Conectar button disabled with nothing on screen saying why.
|
|
5701
|
+
startOAuth: fayzConnectorOAuth(NEOCHEF_CONNECTOR_ID),
|
|
5702
|
+
// The other half of the consent: the platform stores the token and the pool
|
|
5703
|
+
// stores "is it on?". With nobody writing the second, the connector answers
|
|
5704
|
+
// "não conectado" to a merchant who has just authorized.
|
|
5705
|
+
saveConnection: async () => {
|
|
5706
|
+
await neoChefConnectionStore().save({ active: true });
|
|
5707
|
+
},
|
|
5708
|
+
// Disconnect FREEZES the mirror. A merchant who unplugs the kitchen still has
|
|
5709
|
+
// a store, and a connector that empties the catalogue on disconnect is one
|
|
5710
|
+
// nobody dares to disconnect.
|
|
5711
|
+
disconnect: async () => {
|
|
5712
|
+
await neoChefConnectionStore().disconnect();
|
|
5713
|
+
},
|
|
5714
|
+
disconnectNote: "Desconectar congela o espelho: nenhum produto \xE9 apagado e o estoque para de ser atualizado.",
|
|
5715
|
+
...connectionRuns(neoChefConnectionStore),
|
|
5716
|
+
// The managed automation says a paid order goes to the kitchen; this says
|
|
5717
|
+
// whether it arrived.
|
|
5718
|
+
listDeliveries: (options) => listOrderDeliveries2(options?.limit ?? 10),
|
|
5719
|
+
syncActions: [
|
|
5720
|
+
{
|
|
5721
|
+
key: "reconcile",
|
|
5722
|
+
label: "Sincronizar agora",
|
|
5723
|
+
direction: "inbound",
|
|
5724
|
+
// The one that is right on an ordinary day; the rest fold away.
|
|
5725
|
+
primary: true,
|
|
5726
|
+
description: "Traz o que mudou no NeoChef e envia o que est\xE1 pendente daqui \u2014 card\xE1pio, pre\xE7o, estoque e pedidos pagos.",
|
|
5727
|
+
run: async () => {
|
|
5728
|
+
const result = await reconcile2();
|
|
5729
|
+
const legs = Object.values(result.push ?? {}).map((leg) => leg?.message ? String(leg.message) : null).filter(Boolean);
|
|
5730
|
+
return [`${result.pull?.fetched ?? 0} produto(s) lidos do NeoChef`, ...legs].join(" \xB7 ");
|
|
5731
|
+
}
|
|
5732
|
+
},
|
|
5733
|
+
{
|
|
5734
|
+
key: "pull_products",
|
|
5735
|
+
label: "Trazer card\xE1pio do NeoChef",
|
|
5736
|
+
direction: "inbound",
|
|
5737
|
+
description: "Pre\xE7o e estoque do NeoChef passam a valer aqui. Nada \xE9 apagado da loja.",
|
|
5738
|
+
run: async () => {
|
|
5739
|
+
const result = await pullCatalogue2("full");
|
|
5740
|
+
return `${result.fetched} produto(s) lidos, ${result.inserted} criado(s), ${result.updated} atualizado(s)`;
|
|
5741
|
+
}
|
|
5742
|
+
},
|
|
5743
|
+
{
|
|
5744
|
+
key: "push_orders",
|
|
5745
|
+
label: "Enviar pedidos para a cozinha",
|
|
5746
|
+
direction: "outbound",
|
|
5747
|
+
description: "Cada pedido pago vira um pedido na cozinha. Pedido cancelado n\xE3o sobe, e um j\xE1 enviado n\xE3o sobe duas vezes.",
|
|
5748
|
+
pending: pendingOrders2,
|
|
5749
|
+
run: async () => {
|
|
5750
|
+
const result = await pushOrders2();
|
|
5751
|
+
return { message: result.message, status: result.status };
|
|
5752
|
+
}
|
|
5753
|
+
}
|
|
5754
|
+
]
|
|
5755
|
+
};
|
|
5756
|
+
|
|
5757
|
+
// src/integrations/neochef/mapping.ts
|
|
5758
|
+
function toNumber2(value) {
|
|
5759
|
+
if (value === null || value === void 0 || value === "") return null;
|
|
5760
|
+
const n = typeof value === "number" ? value : Number(String(value).replace(",", "."));
|
|
5761
|
+
return Number.isFinite(n) ? n : null;
|
|
5762
|
+
}
|
|
5763
|
+
function toMirroredNeoChefProduct(raw) {
|
|
5764
|
+
if (!raw || raw.id === null || raw.id === void 0 || raw.id === "") return null;
|
|
5765
|
+
const inactive = raw.is_active === false || String(raw.status ?? "active").toLowerCase() === "archived";
|
|
5766
|
+
return {
|
|
5767
|
+
externalId: String(raw.id),
|
|
5768
|
+
sku: raw.sku ? String(raw.sku) : null,
|
|
5769
|
+
name: String(raw.name ?? "").trim() || `Produto ${raw.id}`,
|
|
5770
|
+
price: toNumber2(raw.price),
|
|
5771
|
+
// The kitchen owns this number. The store mirrors it; it does not decide it.
|
|
5772
|
+
inventoryCount: toNumber2(raw.stock),
|
|
5773
|
+
status: inactive ? "archived" : "active",
|
|
5774
|
+
imageUrl: raw.image_url ? String(raw.image_url) : null,
|
|
5775
|
+
// Unlike Bling, the far side DOES return its change stamp, so the cursor can
|
|
5776
|
+
// advance from the data instead of from the window we asked for.
|
|
5777
|
+
updatedAt: raw.updated_at ? String(raw.updated_at) : null
|
|
5778
|
+
};
|
|
5779
|
+
}
|
|
5780
|
+
function toNeoChefOrder(order) {
|
|
5781
|
+
return {
|
|
5782
|
+
kind: order.pickup === true ? "takeout" : "delivery",
|
|
5783
|
+
// The store's own number, so a human can match the two screens. Falls back
|
|
5784
|
+
// to the id rather than to empty: an order with no reference is unmatchable.
|
|
5785
|
+
reference_number: String(order.referenceNumber ?? order.id),
|
|
5786
|
+
// It arrives paid and confirmed — the store already took the money, and a
|
|
5787
|
+
// kitchen that has to re-confirm it is a kitchen doing the work twice.
|
|
5788
|
+
status: "confirmed",
|
|
5789
|
+
total: toNumber2(order.total),
|
|
5790
|
+
subtotal: toNumber2(order.subtotal),
|
|
5791
|
+
notes: order.notes ? String(order.notes) : null
|
|
5792
|
+
};
|
|
5793
|
+
}
|
|
5794
|
+
function advanceNeoChefCursor(products, overlapMs) {
|
|
5795
|
+
const stamps = products.map((product) => product.updatedAt ? Date.parse(product.updatedAt) : NaN).filter((value) => Number.isFinite(value));
|
|
5796
|
+
if (stamps.length === 0) return null;
|
|
5797
|
+
return new Date(Math.max(...stamps) - overlapMs).toISOString();
|
|
5798
|
+
}
|
|
5278
5799
|
var ORDERS = "plg_shop_rep_orders";
|
|
5279
5800
|
var ITEMS = "plg_shop_rep_order_items";
|
|
5280
5801
|
var CUSTOMERS = "plg_shop_rep_customers";
|
|
@@ -6102,7 +6623,7 @@ function buildShopAnalyticsCards() {
|
|
|
6102
6623
|
}
|
|
6103
6624
|
|
|
6104
6625
|
// src/index.ts
|
|
6105
|
-
var ShopPage = React8.lazy(() => import('./ShopPage-
|
|
6626
|
+
var ShopPage = React8.lazy(() => import('./ShopPage-VVLOH3RF.js').then((m) => ({ default: m.ShopPage })));
|
|
6106
6627
|
function createShopPlugin(options) {
|
|
6107
6628
|
const curr = { code: "BRL", locale: "pt-BR", symbol: "R$", ...options?.currency };
|
|
6108
6629
|
setShopTenantResolver(() => useOrganizationStore.getState().currentOrg?.id);
|
|
@@ -6133,6 +6654,24 @@ function createShopPlugin(options) {
|
|
|
6133
6654
|
const ProductsCrudPage = createCrudPage(buildShopProductEntity(curr.code, resolveProvider), {
|
|
6134
6655
|
dataProvider: createShopProductDataProvider(resolveProvider),
|
|
6135
6656
|
feature: "shop",
|
|
6657
|
+
// O produto da loja não tem tabela própria — vive atrás do provider de
|
|
6658
|
+
// commerce —, então as primitivas de dado do agente não o alcançam. A porta
|
|
6659
|
+
// funciona porque a lista empresta o próprio store: ver CrudAgentSurface.
|
|
6660
|
+
aiCreate: {
|
|
6661
|
+
hint: "Descreva o produto\u2026",
|
|
6662
|
+
description: "Descreva o produto e eu cadastro.",
|
|
6663
|
+
intro: {
|
|
6664
|
+
role: "operations",
|
|
6665
|
+
persona: "Cadastro de produtos",
|
|
6666
|
+
pitch: "Diga o produto que voc\xEA quer cadastrar.",
|
|
6667
|
+
description: "Nome, pre\xE7o, descri\xE7\xE3o, estoque \u2014 diga o que souber, do jeito que falar, e eu preencho o resto com o que faz sentido. Nasce como rascunho e voc\xEA confere antes de publicar.",
|
|
6668
|
+
suggestions: [
|
|
6669
|
+
{ label: "Camiseta preta, R$ 79, estoque 20" },
|
|
6670
|
+
{ label: "Cadastre 5 produtos de exemplo para eu testar a loja" },
|
|
6671
|
+
{ label: "Um combo com os dois produtos mais vendidos" }
|
|
6672
|
+
]
|
|
6673
|
+
}
|
|
6674
|
+
},
|
|
6136
6675
|
stats: (items, total) => [
|
|
6137
6676
|
{ id: "total", label: "Produtos", value: total, icon: Package },
|
|
6138
6677
|
{ id: "active", label: "Ativos", value: items?.filter((p) => p.status === "active").length ?? 0, icon: Eye },
|
|
@@ -6397,6 +6936,7 @@ function createShopPlugin(options) {
|
|
|
6397
6936
|
const READ = { feature: "shop", action: "read" };
|
|
6398
6937
|
return {
|
|
6399
6938
|
id: "shop",
|
|
6939
|
+
defaultAgentRole: "operations",
|
|
6400
6940
|
name: options?.navLabel ?? "Shop",
|
|
6401
6941
|
icon: "ShoppingBag",
|
|
6402
6942
|
version: "1.0.0",
|
|
@@ -6534,19 +7074,22 @@ function createShopPlugin(options) {
|
|
|
6534
7074
|
// screens (commerce-stack.md §0). Melhor Envio, AppMax and AbacatePay are
|
|
6535
7075
|
// REQUEST-plane connectors: the buyer is waiting, so each declares a latency
|
|
6536
7076
|
// budget and, because the carrier and the gateways want opposite answers to
|
|
6537
|
-
// the same failure, its own `onFailure`. Bling
|
|
6538
|
-
// nobody is waiting on
|
|
6539
|
-
// a
|
|
7077
|
+
// the same failure, its own `onFailure`. Bling and NeoChef are the SYNC-plane
|
|
7078
|
+
// ones — nobody is waiting on them, and what they declare instead is a call
|
|
7079
|
+
// budget and a cursor.
|
|
6540
7080
|
//
|
|
6541
7081
|
// Two gateways on the shelf is the point: the store picks one, and the
|
|
6542
|
-
// second one arriving changed no contract — only how it authorizes.
|
|
7082
|
+
// second one arriving changed no contract — only how it authorizes. NeoChef
|
|
7083
|
+
// makes the same point about the back office, and one better: its provider
|
|
7084
|
+
// is another Fayz app, and it still fits the shelf without a special case.
|
|
6543
7085
|
connectors: [
|
|
6544
7086
|
melhorEnvioConnectorDef,
|
|
6545
7087
|
appmaxConnectorDef,
|
|
6546
7088
|
abacatePayConnectorDef,
|
|
6547
7089
|
stripeConnectConnectorDef,
|
|
6548
7090
|
vindiConnectorDef,
|
|
6549
|
-
blingConnectorDef
|
|
7091
|
+
blingConnectorDef,
|
|
7092
|
+
neoChefConnectorDef
|
|
6550
7093
|
],
|
|
6551
7094
|
// What having a store makes plugable — the four above plus the ones still
|
|
6552
7095
|
// to be built. Carried over from the Fayz plugin page's "Integra com" row,
|
|
@@ -6556,6 +7099,6 @@ function createShopPlugin(options) {
|
|
|
6556
7099
|
};
|
|
6557
7100
|
}
|
|
6558
7101
|
|
|
6559
|
-
export { ABACATEPAY_CONNECTOR_ID, ABACATEPAY_LATENCY_BUDGET_MS, APPMAX_CONNECTOR_ID, APPMAX_LATENCY_BUDGET_MS, BLING_CONNECTOR_ID, BLING_MARKETPLACE_SOURCE, BLING_MAX_WINDOW_MS, BLING_PAGE_SIZE, BLING_RATE_LIMIT, BLING_SAMPLE_SIZE, BLING_SIGNATURE_HEADER, BLING_TOKEN_LEAD_MS, BLING_WEBHOOK_DEADLINE_MS, BLING_WINDOW_OVERLAP_MS, MELHOR_ENVIO_CONNECTOR_ID, MELHOR_ENVIO_LATENCY_BUDGET_MS, STRIPE_CONNECT_CONNECTOR_ID, STRIPE_CONNECT_LATENCY_BUDGET_MS, VINDI_CONNECTOR_ID, VINDI_LATENCY_BUDGET_MS, abacatePayConnectorDef, acceptWebhook, appmaxConnectorDef, blingConnectionStore, blingConnectorDef, buildShopAnalyticsCards, createShopPlugin, firstWindow, melhorEnvioConnectorDef, orphanConnection, pullProducts, routeCallback, sampleProducts, stripeConnectConnectorDef, toMirroredProduct, vindiConnectorDef, windowFor };
|
|
7102
|
+
export { ABACATEPAY_CONNECTOR_ID, ABACATEPAY_LATENCY_BUDGET_MS, APPMAX_CONNECTOR_ID, APPMAX_LATENCY_BUDGET_MS, BLING_CONNECTOR_ID, BLING_MARKETPLACE_SOURCE, BLING_MAX_WINDOW_MS, BLING_PAGE_SIZE, BLING_RATE_LIMIT, BLING_SAMPLE_SIZE, BLING_SIGNATURE_HEADER, BLING_TOKEN_LEAD_MS, BLING_WEBHOOK_DEADLINE_MS, BLING_WINDOW_OVERLAP_MS, MELHOR_ENVIO_CONNECTOR_ID, MELHOR_ENVIO_LATENCY_BUDGET_MS, NEOCHEF_CONNECTOR_ID, NEOCHEF_CURSOR_OVERLAP_MS, NEOCHEF_FUNCTION, NEOCHEF_MARK, NEOCHEF_PAGE_SIZE, NEOCHEF_RATE_LIMIT, NEOCHEF_SAMPLE_SIZE, NEOCHEF_TOKEN_LEAD_MS, STRIPE_CONNECT_CONNECTOR_ID, STRIPE_CONNECT_LATENCY_BUDGET_MS, VINDI_CONNECTOR_ID, VINDI_LATENCY_BUDGET_MS, abacatePayConnectorDef, acceptWebhook, advanceNeoChefCursor, appmaxConnectorDef, blingConnectionStore, blingConnectorDef, buildShopAnalyticsCards, createShopPlugin, firstWindow, listOrderDeliveries2 as listOrderDeliveries, melhorEnvioConnectorDef, neoChefConnectionStore, neoChefConnectorDef, orphanConnection, pendingOrders2 as pendingOrders, pullCatalogue2 as pullCatalogue, pullProducts, pushOrders2 as pushOrders, reconcile2 as reconcile, routeCallback, sampleProducts, stripeConnectConnectorDef, testNeoChef, toMirroredNeoChefProduct, toMirroredProduct, toNeoChefOrder, vindiConnectorDef, windowFor };
|
|
6560
7103
|
//# sourceMappingURL=index.js.map
|
|
6561
7104
|
//# sourceMappingURL=index.js.map
|