@fayz-ai/plugin-shop 0.17.0 → 0.18.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-4B2NPTRT.js → ShopPage-J34V43NW.js} +22 -11
- package/dist/ShopPage-J34V43NW.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +235 -81
- package/dist/index.js.map +1 -1
- package/dist/views/OrderDetailView.d.ts +4 -2
- package/dist/views/OrderDetailView.d.ts.map +1 -1
- package/dist/views/ProductContentTab.d.ts +17 -0
- package/dist/views/ProductContentTab.d.ts.map +1 -0
- package/dist/views/ProductImagesTab.d.ts +3 -1
- package/dist/views/ProductImagesTab.d.ts.map +1 -1
- package/dist/views/ShopPage.d.ts +7 -0
- package/dist/views/ShopPage.d.ts.map +1 -1
- package/package.json +7 -7
- package/dist/ShopPage-4B2NPTRT.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -20,6 +20,14 @@ export interface ShopPluginOptions {
|
|
|
20
20
|
* Pedidos, clientes, conteúdo e descontos continuam de pé.
|
|
21
21
|
*/
|
|
22
22
|
products?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* The shop's own orders LIST at `/orders`. On by default. Turn it off when
|
|
25
|
+
* the app mounts an orders list that already covers every sale of the
|
|
26
|
+
* account: two plugins drawing `/orders` is one of them never showing.
|
|
27
|
+
* The shop keeps `/orders/new`, `/orders/:id/edit` and its detail page,
|
|
28
|
+
* which it offers through the `orders.detail` component slot.
|
|
29
|
+
*/
|
|
30
|
+
orders?: boolean;
|
|
23
31
|
};
|
|
24
32
|
scope?: PluginScope;
|
|
25
33
|
verticalId?: VerticalId;
|
|
@@ -48,6 +56,19 @@ export interface ShopPluginOptions {
|
|
|
48
56
|
export declare function createShopPlugin(options?: ShopPluginOptions): PluginManifest;
|
|
49
57
|
export * from './integrations/bling';
|
|
50
58
|
export * from './integrations/neochef';
|
|
59
|
+
export { ProductContentTab } from './views/ProductContentTab';
|
|
60
|
+
import type { DetailTab } from '@fayz-ai/core';
|
|
61
|
+
import type { ShopProvider as ShopProviderForTab } from '@fayz-ai/shop';
|
|
62
|
+
/**
|
|
63
|
+
* The "Conteúdo" tab for a product record owned by another plugin: the app
|
|
64
|
+
* hands it to that plugin's own tab option. The shop offers; the app composes.
|
|
65
|
+
*/
|
|
66
|
+
export declare function shopProductContentTab(options: {
|
|
67
|
+
provider: () => ShopProviderForTab;
|
|
68
|
+
/** Where the content library lives in this app. */
|
|
69
|
+
libraryHref?: string;
|
|
70
|
+
label?: string;
|
|
71
|
+
}): DetailTab;
|
|
51
72
|
export { buildShopAnalyticsCards } from './analytics/cards';
|
|
52
73
|
export type { Product, Order, ShopCustomer, Discount, Category, CreateProductInput, UpdateProductInput, ListProductsOptions, CreateOrderInput, UpdateOrderInput, ListOrdersOptions, } from '@fayz-ai/shop';
|
|
53
74
|
export { melhorEnvioConnectorDef, MELHOR_ENVIO_CONNECTOR_ID, MELHOR_ENVIO_LATENCY_BUDGET_MS } from './integrations/melhor-envio/connectorDef';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAkC5E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAA;AAwB5D,MAAM,WAAW,iBAAiB;IAChC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,UAAU,CAAA;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,wEAAwE;IACxE,aAAa,CAAC,EAAE,OAAO,CAAC,MAAM,CAC1B,UAAU,GAAG,QAAQ,GAAG,WAAW,GAAG,WAAW,GAAG,UAAU,GAC9D,aAAa,GAAG,YAAY,GAAG,WAAW,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,GAC3E,gBAAgB,GAAG,kBAAkB,GAAG,OAAO,EAAE,MAAM,CAAC,CAAC,CAAA;IAC7D;;;OAGG;IACH,OAAO,CAAC,EAAE;QACR;;;;;;;WAOG;QACH,QAAQ,CAAC,EAAE,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { shopCustomerLookup, resolve, invalidateProductLists, listProductsDetailed, applyQuery,
|
|
1
|
+
import { errorMessage, shopCustomerLookup, resolve, invalidateProductLists, listProductsDetailed, applyQuery, listProductsCached, resolveTerm, candidateMeta, SHIPPING_PROFILES_REGISTRY, packageMeasureLabel, PACKAGES_REGISTRY, packagesRegistry, SHIPPING_ZONES_REGISTRY, buildShopRegistries, locationSummary, LOCATIONS_REGISTRY } from './chunk-6DRDPROL.js';
|
|
2
2
|
import * as React13 from 'react';
|
|
3
3
|
import React13__default, { useState, useEffect, useRef, useCallback, useMemo } from 'react';
|
|
4
|
-
import { createConnectionStore, connectionSettings, connectionStatus, settingsStatus, connectionRuns, tl, getActiveTenantId, getSupabaseClientOptional, registerMessageDefaults, connectorRuntimeToken, CONNECTOR_RUNTIME_TOKEN_HEADER, countByTenant, describeError, errorMessage as errorMessage$1, emitDataChanged, resolveDataProvider } from '@fayz-ai/core';
|
|
4
|
+
import { createConnectionStore, connectionSettings, connectionStatus, settingsStatus, connectionRuns, tl, getActiveTenantId, getSupabaseClientOptional, registerMessageDefaults, registerComponent, connectorRuntimeToken, CONNECTOR_RUNTIME_TOKEN_HEADER, countByTenant, describeError, errorMessage as errorMessage$1, emitDataChanged, resolveDataProvider } from '@fayz-ai/core';
|
|
5
5
|
import { getShopTenantId, setShopTenantResolver, buildShopMessageDefaults, registerShippingLabelProvider, getShopProvider, buildShopDomainEvents, axesFromOptions, planVariantMatrix, validateVariantAxes, hasOnlyDefaultVariant, MAX_VARIANT_AXES, leavesNothingSellable, productImageToMediaFile, formatVariantCombination, applyVariantMatrix } from '@fayz-ai/shop';
|
|
6
|
-
import { fayzConnectorOAuth, describeConnectorAccount, useOrganizationStore, registerEntityPath, registerPersonLookup, createCrudPage, registerCrudNavTabs, adminNavigateTo,
|
|
7
|
-
import { Package, Eye, FileEdit, PackageX, Users, UsersRound, Filter, UserX, Tag, TicketCheck, Layers, CreditCard, CircleDollarSign, Upload, ImageOff,
|
|
8
|
-
import { PageTabs, PageHeaderActions, Card,
|
|
6
|
+
import { fayzConnectorOAuth, describeConnectorAccount, useOrganizationStore, registerEntityPath, registerPersonLookup, createCrudPage, registerCrudNavTabs, adminNavigateTo, DetailTabHeader, AskAIButton, PageActions, useAgentSurface, askAI, CrudFormPage, SettingsGroup, SelectRow, ToggleRow, useConnectors, useConnectorsPanelAvailable, openConnectorsPanel, MultiSelectRow, AddConnectorButton, AddConnectorPanel, ConnectorDetail, RegistryCrudView, TextRow, ConnectorRow, ConnectorMark, StateChip } from '@fayz-ai/admin';
|
|
7
|
+
import { Package, Eye, FileEdit, PackageX, Users, UsersRound, Filter, UserX, Tag, TicketCheck, Layers, CreditCard, CircleDollarSign, Plus, UploadCloud, Upload, ImageOff, Loader2, WandSparkles, ChevronLeft, ChevronRight, Download, RefreshCw, Trash2, AlertTriangle, X, ExternalLink, Box, ChevronDown, Film, FileText, Warehouse, ArrowRight, MapPin, Car, Truck, Info, Check, Sparkles, Ban, ListChecks, Search, Building2 } from 'lucide-react';
|
|
8
|
+
import { Skeleton, Button, PageTabs, PageHeaderActions, Card, Modal, ModalContent, ModalHeader, ModalTitle, ModalDescription, ModalFooter, Thumbnail, PageHeader, toast, ConfirmDialog, Hint, ModalBody } from '@fayz-ai/ui';
|
|
9
9
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
10
10
|
import { listStockReasonCodes, resolveStockStore, createSupabaseStockStore } from '@fayz-ai/shop/inventory';
|
|
11
11
|
import { normalizeMovementType } from '@fayz-ai/plugin-inventory';
|
|
@@ -207,9 +207,10 @@ function createMelhorEnvioLabelProvider(resolve3) {
|
|
|
207
207
|
track: async (orderId) => await resolve3().trackShippingLabel?.(orderId, MELHOR_ENVIO_CARRIER) ?? null
|
|
208
208
|
};
|
|
209
209
|
}
|
|
210
|
-
function ProductImagesTab({ item, getProvider }) {
|
|
210
|
+
function ProductImagesTab({ item, getProvider, footer }) {
|
|
211
211
|
const product = item;
|
|
212
|
-
const [images, setImages] = useState(
|
|
212
|
+
const [images, setImages] = useState(null);
|
|
213
|
+
const [dragging, setDragging] = useState(false);
|
|
213
214
|
const [busy, setBusy] = useState(false);
|
|
214
215
|
const [error, setError] = useState(null);
|
|
215
216
|
const fileRef = useRef(null);
|
|
@@ -218,7 +219,10 @@ function ProductImagesTab({ item, getProvider }) {
|
|
|
218
219
|
setImages(sortImages(fresh?.images ?? []));
|
|
219
220
|
}
|
|
220
221
|
useEffect(() => {
|
|
221
|
-
|
|
222
|
+
setImages(null);
|
|
223
|
+
void reload().catch((err) => {
|
|
224
|
+
setImages([]);
|
|
225
|
+
setError(errorMessage(err));
|
|
222
226
|
});
|
|
223
227
|
}, [product.id]);
|
|
224
228
|
async function run(action) {
|
|
@@ -233,10 +237,11 @@ function ProductImagesTab({ item, getProvider }) {
|
|
|
233
237
|
setBusy(false);
|
|
234
238
|
}
|
|
235
239
|
}
|
|
236
|
-
async function upload(
|
|
237
|
-
|
|
240
|
+
async function upload(picked) {
|
|
241
|
+
const files = Array.from(picked ?? []).filter((file) => file.type.startsWith("image/"));
|
|
242
|
+
if (!files.length) return;
|
|
238
243
|
await run(async () => {
|
|
239
|
-
for (const file of
|
|
244
|
+
for (const file of files) {
|
|
240
245
|
await getProvider().uploadProductImage(product.id, file);
|
|
241
246
|
}
|
|
242
247
|
if (fileRef.current) fileRef.current.value = "";
|
|
@@ -244,7 +249,7 @@ function ProductImagesTab({ item, getProvider }) {
|
|
|
244
249
|
}
|
|
245
250
|
function move(index, delta) {
|
|
246
251
|
const target = index + delta;
|
|
247
|
-
if (target < 0 || target >= images.length) return;
|
|
252
|
+
if (!images || target < 0 || target >= images.length) return;
|
|
248
253
|
const a = images[index];
|
|
249
254
|
const b = images[target];
|
|
250
255
|
void run(async () => {
|
|
@@ -255,87 +260,153 @@ function ProductImagesTab({ item, getProvider }) {
|
|
|
255
260
|
});
|
|
256
261
|
}
|
|
257
262
|
const update = getProvider().updateProductImage;
|
|
258
|
-
return
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
description: "A primeira foto \xE9 a capa \u2014 aparece no cat\xE1logo, no carrinho e no pedido. As demais viram o carrossel na p\xE1gina do produto.",
|
|
264
|
-
actions: (
|
|
265
|
-
// The same Button as every other tab. It used to be a <label> hand-
|
|
266
|
-
// painted to look like one, which drifted the moment the real button
|
|
267
|
-
// changed — different height, no icon, no disabled state.
|
|
268
|
-
/* @__PURE__ */ jsxs(Button, { disabled: busy, onClick: () => fileRef.current?.click(), children: [
|
|
269
|
-
/* @__PURE__ */ jsx(Plus, { className: "mr-1.5 h-4 w-4" }),
|
|
270
|
-
busy ? "Enviando\u2026" : "Adicionar fotos"
|
|
271
|
-
] })
|
|
272
|
-
)
|
|
273
|
-
}
|
|
274
|
-
),
|
|
275
|
-
/* @__PURE__ */ jsx(
|
|
276
|
-
"input",
|
|
263
|
+
return (
|
|
264
|
+
// The whole tab takes a drop: aiming at a small box with six files in hand
|
|
265
|
+
// is the part of uploading that goes wrong.
|
|
266
|
+
/* @__PURE__ */ jsxs(
|
|
267
|
+
"div",
|
|
277
268
|
{
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
269
|
+
className: "space-y-4",
|
|
270
|
+
onDragOver: (event) => {
|
|
271
|
+
if (event.dataTransfer.types.includes("Files")) {
|
|
272
|
+
event.preventDefault();
|
|
273
|
+
setDragging(true);
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
onDragLeave: (event) => {
|
|
277
|
+
if (!event.currentTarget.contains(event.relatedTarget)) setDragging(false);
|
|
278
|
+
},
|
|
279
|
+
onDrop: (event) => {
|
|
280
|
+
if (!event.dataTransfer.files.length) return;
|
|
281
|
+
event.preventDefault();
|
|
282
|
+
setDragging(false);
|
|
283
|
+
void upload(event.dataTransfer.files);
|
|
284
|
+
},
|
|
285
|
+
children: [
|
|
295
286
|
/* @__PURE__ */ jsx(
|
|
296
|
-
|
|
287
|
+
DetailTabHeader,
|
|
297
288
|
{
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
289
|
+
title: "Fotos do produto",
|
|
290
|
+
description: "A capa \xE9 a foto do produto em todo lugar: no cadastro, no estoque, no cat\xE1logo, no carrinho e no pedido. As demais viram o carrossel na p\xE1gina do produto.",
|
|
291
|
+
actions: (
|
|
292
|
+
// The same Button as every other tab. It used to be a <label> hand-
|
|
293
|
+
// painted to look like one, which drifted the moment the real button
|
|
294
|
+
// changed — different height, no icon, no disabled state.
|
|
295
|
+
/* @__PURE__ */ jsxs(Button, { disabled: busy, onClick: () => fileRef.current?.click(), children: [
|
|
296
|
+
/* @__PURE__ */ jsx(Plus, { className: "mr-1.5 h-4 w-4" }),
|
|
297
|
+
busy ? "Enviando\u2026" : "Adicionar fotos"
|
|
298
|
+
] })
|
|
299
|
+
)
|
|
302
300
|
}
|
|
303
301
|
),
|
|
304
302
|
/* @__PURE__ */ jsx(
|
|
305
|
-
|
|
306
|
-
{
|
|
307
|
-
label: "Mover para frente",
|
|
308
|
-
disabled: busy || index === images.length - 1,
|
|
309
|
-
onClick: () => move(index, 1),
|
|
310
|
-
children: "\u2192"
|
|
311
|
-
}
|
|
312
|
-
)
|
|
313
|
-
] }),
|
|
314
|
-
/* @__PURE__ */ jsxs("div", { className: "flex gap-1", children: [
|
|
315
|
-
!image.isPrimary && update && /* @__PURE__ */ jsx(
|
|
316
|
-
"button",
|
|
303
|
+
"input",
|
|
317
304
|
{
|
|
318
|
-
|
|
305
|
+
ref: fileRef,
|
|
306
|
+
type: "file",
|
|
307
|
+
accept: "image/*",
|
|
308
|
+
multiple: true,
|
|
319
309
|
disabled: busy,
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
children: "Usar como capa"
|
|
310
|
+
className: "hidden",
|
|
311
|
+
onChange: (event) => void upload(event.target.files)
|
|
323
312
|
}
|
|
324
313
|
),
|
|
325
|
-
/* @__PURE__ */ jsx(
|
|
314
|
+
error && /* @__PURE__ */ jsx("p", { className: "rounded-md border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-800", children: error }),
|
|
315
|
+
images === null ? /* @__PURE__ */ jsx("ul", { className: "fz-cards gap-3", "aria-busy": "true", children: [0, 1, 2, 3].map((i) => /* @__PURE__ */ jsxs("li", { className: "overflow-hidden rounded-lg border", children: [
|
|
316
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "aspect-square w-full rounded-none" }),
|
|
317
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 px-2 py-2", children: [
|
|
318
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-14" }),
|
|
319
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-20" })
|
|
320
|
+
] })
|
|
321
|
+
] }, i)) }) : images.length === 0 || dragging ? /* @__PURE__ */ jsxs(
|
|
326
322
|
"button",
|
|
327
323
|
{
|
|
328
324
|
type: "button",
|
|
329
325
|
disabled: busy,
|
|
330
|
-
onClick: () =>
|
|
331
|
-
className:
|
|
332
|
-
children:
|
|
326
|
+
onClick: () => fileRef.current?.click(),
|
|
327
|
+
className: `flex w-full flex-col items-center gap-2 rounded-lg border border-dashed px-4 py-10 text-center text-sm transition-colors ${dragging ? "border-primary bg-primary/5 text-foreground" : "text-muted-foreground hover:bg-muted/40"}`,
|
|
328
|
+
children: [
|
|
329
|
+
/* @__PURE__ */ jsx(UploadCloud, { className: "h-6 w-6", "aria-hidden": true }),
|
|
330
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: dragging ? "Solte para enviar" : "Arraste as fotos para c\xE1, ou clique para escolher" }),
|
|
331
|
+
!dragging && /* @__PURE__ */ jsx("span", { className: "max-w-md text-xs", children: "Produtos com mais de uma foto vendem melhor \u2014 mostre a embalagem, o produto pronto e uma refer\xEAncia de tamanho." })
|
|
332
|
+
]
|
|
333
333
|
}
|
|
334
|
-
)
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
334
|
+
) : /* @__PURE__ */ jsx("ul", { className: "fz-cards gap-3", children: images.map((image, index) => /* @__PURE__ */ jsxs("li", { className: "overflow-hidden rounded-lg border", children: [
|
|
335
|
+
/* @__PURE__ */ jsxs("div", { className: "relative aspect-square bg-muted", children: [
|
|
336
|
+
/* @__PURE__ */ jsx("img", { src: image.url, alt: image.altText ?? "", className: "h-full w-full object-cover" }),
|
|
337
|
+
image.isPrimary && /* @__PURE__ */ jsx("span", { className: "absolute left-2 top-2 rounded-full bg-primary px-2 py-0.5 text-[11px] font-bold text-primary-foreground", children: "Capa" })
|
|
338
|
+
] }),
|
|
339
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center justify-between gap-x-1 gap-y-1.5 px-2 py-1.5", children: [
|
|
340
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-1", children: [
|
|
341
|
+
/* @__PURE__ */ jsx(
|
|
342
|
+
IconButton,
|
|
343
|
+
{
|
|
344
|
+
label: "Mover para tr\xE1s",
|
|
345
|
+
disabled: busy || index === 0,
|
|
346
|
+
onClick: () => move(index, -1),
|
|
347
|
+
children: "\u2190"
|
|
348
|
+
}
|
|
349
|
+
),
|
|
350
|
+
/* @__PURE__ */ jsx(
|
|
351
|
+
IconButton,
|
|
352
|
+
{
|
|
353
|
+
label: "Mover para frente",
|
|
354
|
+
disabled: busy || index === images.length - 1,
|
|
355
|
+
onClick: () => move(index, 1),
|
|
356
|
+
children: "\u2192"
|
|
357
|
+
}
|
|
358
|
+
)
|
|
359
|
+
] }),
|
|
360
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
361
|
+
!image.isPrimary && update && /* @__PURE__ */ jsx(
|
|
362
|
+
"button",
|
|
363
|
+
{
|
|
364
|
+
type: "button",
|
|
365
|
+
disabled: busy,
|
|
366
|
+
onClick: () => void run(() => update(image.id, { isPrimary: true })),
|
|
367
|
+
className: "whitespace-nowrap rounded px-1.5 py-0.5 text-xs text-muted-foreground hover:bg-muted hover:text-foreground disabled:opacity-50",
|
|
368
|
+
children: "Usar como capa"
|
|
369
|
+
}
|
|
370
|
+
),
|
|
371
|
+
/* @__PURE__ */ jsx(
|
|
372
|
+
AskAIButton,
|
|
373
|
+
{
|
|
374
|
+
size: "sm",
|
|
375
|
+
variant: "outline",
|
|
376
|
+
className: "h-6 px-2 text-xs",
|
|
377
|
+
label: "IA",
|
|
378
|
+
media: { url: image.url, name: image.altText ?? product.name },
|
|
379
|
+
draft: "Melhora essa imagem",
|
|
380
|
+
hint: "o que voc\xEA quer mudar nessa foto",
|
|
381
|
+
intro: {
|
|
382
|
+
persona: "Est\xFAdio de imagem",
|
|
383
|
+
pitch: `Vamos melhorar a foto de ${product.name}.`,
|
|
384
|
+
description: "Posso limpar o fundo, corrigir luz e cor, e gerar uma vers\xE3o em resolu\xE7\xE3o maior para o cat\xE1logo.",
|
|
385
|
+
suggestions: [
|
|
386
|
+
{ label: "Fundo branco", prompt: "Remove o fundo e deixa branco" },
|
|
387
|
+
{ label: "Mais n\xEDtida", prompt: "Aumenta a resolu\xE7\xE3o e a nitidez" }
|
|
388
|
+
]
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
),
|
|
392
|
+
/* @__PURE__ */ jsx(
|
|
393
|
+
"button",
|
|
394
|
+
{
|
|
395
|
+
type: "button",
|
|
396
|
+
disabled: busy,
|
|
397
|
+
onClick: () => void run(() => getProvider().deleteProductImage(image.id)),
|
|
398
|
+
className: "rounded px-1.5 py-0.5 text-xs text-red-600 hover:bg-red-50 disabled:opacity-50",
|
|
399
|
+
children: "Excluir"
|
|
400
|
+
}
|
|
401
|
+
)
|
|
402
|
+
] })
|
|
403
|
+
] })
|
|
404
|
+
] }, image.id)) }),
|
|
405
|
+
footer
|
|
406
|
+
]
|
|
407
|
+
}
|
|
408
|
+
)
|
|
409
|
+
);
|
|
339
410
|
}
|
|
340
411
|
function IconButton({ label, disabled, onClick, children }) {
|
|
341
412
|
return /* @__PURE__ */ jsx(
|
|
@@ -8593,9 +8664,76 @@ function buildShopAnalyticsCards() {
|
|
|
8593
8664
|
}
|
|
8594
8665
|
];
|
|
8595
8666
|
}
|
|
8667
|
+
function ProductContentTab({ item, getProvider, libraryHref = "#/content" }) {
|
|
8668
|
+
const catalogId = item?.id;
|
|
8669
|
+
const [product, setProduct] = useState(void 0);
|
|
8670
|
+
const [error, setError] = useState(null);
|
|
8671
|
+
useEffect(() => {
|
|
8672
|
+
if (!catalogId) {
|
|
8673
|
+
setProduct(null);
|
|
8674
|
+
return;
|
|
8675
|
+
}
|
|
8676
|
+
let alive = true;
|
|
8677
|
+
setProduct(void 0);
|
|
8678
|
+
const provider = getProvider();
|
|
8679
|
+
const lookup = provider.getProductByCatalogId ? provider.getProductByCatalogId(catalogId) : provider.getProduct(catalogId);
|
|
8680
|
+
lookup.then((found) => {
|
|
8681
|
+
if (alive) setProduct(found);
|
|
8682
|
+
}).catch((err) => {
|
|
8683
|
+
if (alive) {
|
|
8684
|
+
setProduct(null);
|
|
8685
|
+
setError(errorMessage(err));
|
|
8686
|
+
}
|
|
8687
|
+
});
|
|
8688
|
+
return () => {
|
|
8689
|
+
alive = false;
|
|
8690
|
+
};
|
|
8691
|
+
}, [catalogId]);
|
|
8692
|
+
if (product === void 0) {
|
|
8693
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-4", "aria-busy": "true", children: [
|
|
8694
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
8695
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-40" }),
|
|
8696
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-full max-w-lg" })
|
|
8697
|
+
] }),
|
|
8698
|
+
/* @__PURE__ */ jsx("ul", { className: "fz-cards gap-3", children: [0, 1, 2, 3].map((i) => /* @__PURE__ */ jsxs("li", { className: "overflow-hidden rounded-lg border", children: [
|
|
8699
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "aspect-square w-full rounded-none" }),
|
|
8700
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2 px-2 py-2", children: [
|
|
8701
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-14" }),
|
|
8702
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-20" })
|
|
8703
|
+
] })
|
|
8704
|
+
] }, i)) })
|
|
8705
|
+
] });
|
|
8706
|
+
}
|
|
8707
|
+
if (!product) {
|
|
8708
|
+
return /* @__PURE__ */ jsx("p", { className: "rounded-lg border border-dashed px-4 py-10 text-center text-sm text-muted-foreground", children: error ?? "Este produto ainda n\xE3o est\xE1 na loja, ent\xE3o n\xE3o tem galeria. Publique-o na loja para adicionar fotos." });
|
|
8709
|
+
}
|
|
8710
|
+
return /* @__PURE__ */ jsx(
|
|
8711
|
+
ProductImagesTab,
|
|
8712
|
+
{
|
|
8713
|
+
item: product,
|
|
8714
|
+
getProvider,
|
|
8715
|
+
footer: /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
|
|
8716
|
+
"Estas fotos tamb\xE9m aparecem em",
|
|
8717
|
+
" ",
|
|
8718
|
+
/* @__PURE__ */ jsx("a", { href: libraryHref, className: "font-medium text-primary underline underline-offset-2 hover:opacity-80", children: "Conte\xFAdo" }),
|
|
8719
|
+
", junto com as de todos os produtos."
|
|
8720
|
+
] })
|
|
8721
|
+
}
|
|
8722
|
+
);
|
|
8723
|
+
}
|
|
8596
8724
|
|
|
8597
8725
|
// src/index.ts
|
|
8598
|
-
var ShopPage = React13__default.lazy(() => import('./ShopPage-
|
|
8726
|
+
var ShopPage = React13__default.lazy(() => import('./ShopPage-J34V43NW.js').then((m) => ({ default: m.ShopPage })));
|
|
8727
|
+
var LazyOrderDetail = React13__default.lazy(() => import('./ShopPage-J34V43NW.js').then((m) => ({ default: m.ShopOrderDetailSlot })));
|
|
8728
|
+
function ShopOrderDetail(provider) {
|
|
8729
|
+
const Detail = (props) => React13__default.createElement(
|
|
8730
|
+
React13__default.Suspense,
|
|
8731
|
+
{ fallback: null },
|
|
8732
|
+
React13__default.createElement(LazyOrderDetail, { ...props, provider })
|
|
8733
|
+
);
|
|
8734
|
+
Detail.displayName = "ShopOrderDetail";
|
|
8735
|
+
return Detail;
|
|
8736
|
+
}
|
|
8599
8737
|
function createShopPlugin(options) {
|
|
8600
8738
|
const curr = { code: "BRL", locale: "pt-BR", symbol: "R$", ...options?.currency };
|
|
8601
8739
|
setShopTenantResolver(() => useOrganizationStore.getState().currentOrg?.id);
|
|
@@ -8920,7 +9058,13 @@ function createShopPlugin(options) {
|
|
|
8920
9058
|
];
|
|
8921
9059
|
const withProducts = options?.modules?.products !== false;
|
|
8922
9060
|
const isProductRoute = (route) => route === "/products" || route.startsWith("/products/");
|
|
8923
|
-
const
|
|
9061
|
+
const withOrders = options?.modules?.orders !== false;
|
|
9062
|
+
const ACTIVE_NAV = NAV.filter((entry) => (withProducts || !isProductRoute(entry.route)) && (withOrders || entry.route !== "/orders"));
|
|
9063
|
+
const ORDER_FORM_ROUTES = [
|
|
9064
|
+
{ path: "/orders/new", component: pageFor("orders") },
|
|
9065
|
+
{ path: "/orders/:id/edit", component: pageFor("orders") }
|
|
9066
|
+
];
|
|
9067
|
+
registerComponent("orders.detail", ShopOrderDetail(options?.provider));
|
|
8924
9068
|
const ACTIVE_LEGACY = withProducts ? LEGACY_ROUTES : LEGACY_ROUTES.map((r) => r.path === "/shop" || r.path === "/shop/products" ? { path: r.path, component: redirectTo("/orders") } : r);
|
|
8925
9069
|
const READ = { feature: "shop", action: "read" };
|
|
8926
9070
|
return {
|
|
@@ -8951,6 +9095,7 @@ function createShopPlugin(options) {
|
|
|
8951
9095
|
})),
|
|
8952
9096
|
routes: [
|
|
8953
9097
|
...ACTIVE_NAV.map((entry) => ({ path: entry.route, component: entry.component, permission: READ })),
|
|
9098
|
+
...ORDER_FORM_ROUTES.map((r) => ({ ...r, permission: READ })),
|
|
8954
9099
|
...HIDDEN_ROUTES.map((r) => ({ ...r, permission: READ })),
|
|
8955
9100
|
...ACTIVE_LEGACY.map((r) => ({ ...r, permission: READ }))
|
|
8956
9101
|
],
|
|
@@ -9097,7 +9242,16 @@ function createShopPlugin(options) {
|
|
|
9097
9242
|
integrations: ["shopify", "stripe"]
|
|
9098
9243
|
};
|
|
9099
9244
|
}
|
|
9245
|
+
function shopProductContentTab(options) {
|
|
9246
|
+
return {
|
|
9247
|
+
id: "content",
|
|
9248
|
+
label: options.label ?? "Conte\xFAdo",
|
|
9249
|
+
icon: "Image",
|
|
9250
|
+
component: ProductContentTab,
|
|
9251
|
+
props: { getProvider: options.provider, libraryHref: options.libraryHref ?? "#/content" }
|
|
9252
|
+
};
|
|
9253
|
+
}
|
|
9100
9254
|
|
|
9101
|
-
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, MERCADOPAGO_CONNECTOR_ID, MERCADOPAGO_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, mercadoPagoConnectorDef, 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 };
|
|
9255
|
+
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, MERCADOPAGO_CONNECTOR_ID, MERCADOPAGO_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, ProductContentTab, 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, mercadoPagoConnectorDef, neoChefConnectionStore, neoChefConnectorDef, orphanConnection, pendingOrders2 as pendingOrders, pullCatalogue2 as pullCatalogue, pullProducts, pushOrders2 as pushOrders, reconcile2 as reconcile, routeCallback, sampleProducts, shopProductContentTab, stripeConnectConnectorDef, testNeoChef, toMirroredNeoChefProduct, toMirroredProduct, toNeoChefOrder, vindiConnectorDef, windowFor };
|
|
9102
9256
|
//# sourceMappingURL=index.js.map
|
|
9103
9257
|
//# sourceMappingURL=index.js.map
|