@fayz-ai/plugin-shop 0.18.1 → 0.19.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/index.js CHANGED
@@ -1,11 +1,11 @@
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';
1
+ import { errorMessage, shopCustomerLookup, resolve, invalidateProductLists, listProductsDetailed, applyQuery, listProductsCached, resolveTerm, candidateMeta, SHIPPING_PROFILES_REGISTRY, packageMeasureLabel, PACKAGES_REGISTRY, packagesRegistry, SHIPPING_ZONES_REGISTRY, marketsRegistry, buildShopRegistries, locationSummary, LOCATIONS_REGISTRY } from './chunk-ATWU5BRP.js';
2
2
  import * as React13 from 'react';
3
- import React13__default, { useState, useEffect, useRef, useCallback, useMemo } from 'react';
3
+ import React13__default, { useState, useEffect, useMemo, useRef, useCallback } from 'react';
4
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, 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';
6
+ import { fayzConnectorOAuth, describeConnectorAccount, useOrganizationStore, registerEntityPath, registerPersonLookup, createCrudPage, registerCrudNavTabs, adminNavigateTo, DetailTabHeader, AskAIButton, PageActions, useAgentSurface, askAI, CrudFormPage, SettingsGroup, SelectRow, ToggleRow, RegistryCrudView, useConnectors, useConnectorsPanelAvailable, openConnectorsPanel, MultiSelectRow, AddConnectorButton, AddConnectorPanel, ConnectorDetail, TextRow, ConnectorRow, ConnectorMark, StateChip } from '@fayz-ai/admin';
7
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';
8
+ import { Skeleton, Badge, CurrencyInput, 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';
@@ -5218,6 +5218,15 @@ function ShippingSettings({ provider }) {
5218
5218
  )
5219
5219
  ] });
5220
5220
  }
5221
+ function MarketsSettings({ basePath = "/settings/shop-markets" }) {
5222
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
5223
+ /* @__PURE__ */ jsxs("div", { className: "px-1 pt-4", children: [
5224
+ /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold", children: "Mercados" }),
5225
+ /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-xs text-muted-foreground", children: marketsRegistry.description })
5226
+ ] }),
5227
+ /* @__PURE__ */ jsx(RegistryCrudView, { registry: marketsRegistry, basePath, embedded: true })
5228
+ ] });
5229
+ }
5221
5230
  var POLICIES = [
5222
5231
  {
5223
5232
  value: "on_payment",
@@ -8721,10 +8730,127 @@ function ProductContentTab({ item, getProvider, libraryHref = "#/content" }) {
8721
8730
  }
8722
8731
  );
8723
8732
  }
8733
+ var SYMBOLS = { BRL: "R$", EUR: "\u20AC", USD: "US$", GBP: "\xA3", ARS: "AR$", MXN: "MX$" };
8734
+ function ProductMarketPricesTab({ item, getProvider, settingsHref = "#/settings/shop-markets" }) {
8735
+ const catalogId = item?.id;
8736
+ const basePrice = Number(item?.salePrice ?? item?.price ?? 0);
8737
+ const [markets, setMarkets] = useState(void 0);
8738
+ const [saved, setSaved] = useState({});
8739
+ const [draft2, setDraft] = useState({});
8740
+ const [error, setError] = useState(null);
8741
+ const [saving, setSaving] = useState(false);
8742
+ const [done, setDone] = useState(false);
8743
+ useEffect(() => {
8744
+ if (!catalogId) return;
8745
+ let alive = true;
8746
+ const provider = getProvider();
8747
+ if (!provider.listAdminMarkets || !provider.getCatalogMarketPrices) {
8748
+ setMarkets([]);
8749
+ return;
8750
+ }
8751
+ Promise.all([provider.listAdminMarkets(), provider.getCatalogMarketPrices(catalogId)]).then(([list, prices]) => {
8752
+ if (!alive) return;
8753
+ const byMarket = Object.fromEntries(prices.map((p) => [p.marketId, p.price]));
8754
+ setMarkets(list);
8755
+ setSaved(byMarket);
8756
+ setDraft(byMarket);
8757
+ }).catch((err) => {
8758
+ if (alive) {
8759
+ setMarkets([]);
8760
+ setError(errorMessage(err));
8761
+ }
8762
+ });
8763
+ return () => {
8764
+ alive = false;
8765
+ };
8766
+ }, [catalogId]);
8767
+ const dirty = useMemo(
8768
+ () => Object.keys(draft2).some((id) => (draft2[id] ?? null) !== (saved[id] ?? null)),
8769
+ [draft2, saved]
8770
+ );
8771
+ async function save() {
8772
+ if (!catalogId) return;
8773
+ const provider = getProvider();
8774
+ if (!provider.setCatalogMarketPrice) return;
8775
+ setSaving(true);
8776
+ setError(null);
8777
+ setDone(false);
8778
+ try {
8779
+ for (const id of Object.keys(draft2)) {
8780
+ const next = draft2[id] ?? null;
8781
+ if (next !== (saved[id] ?? null)) await provider.setCatalogMarketPrice(catalogId, id, next);
8782
+ }
8783
+ setSaved({ ...draft2 });
8784
+ setDone(true);
8785
+ } catch (err) {
8786
+ setError(errorMessage(err));
8787
+ } finally {
8788
+ setSaving(false);
8789
+ }
8790
+ }
8791
+ if (markets === void 0) {
8792
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-3", "aria-busy": "true", children: [
8793
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-48" }),
8794
+ [0, 1].map((i) => /* @__PURE__ */ jsx(Skeleton, { className: "h-16 w-full" }, i))
8795
+ ] });
8796
+ }
8797
+ if (markets.length === 0) {
8798
+ return /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-dashed px-4 py-10 text-center text-sm text-muted-foreground", children: error ?? /* @__PURE__ */ jsxs(Fragment, { children: [
8799
+ "A loja vende numa moeda s\xF3. Para vender em outros pa\xEDses com pre\xE7o pr\xF3prio,",
8800
+ " ",
8801
+ /* @__PURE__ */ jsx("a", { href: settingsHref, className: "font-medium text-primary underline underline-offset-2", children: "crie os mercados" }),
8802
+ "."
8803
+ ] }) });
8804
+ }
8805
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
8806
+ /* @__PURE__ */ jsxs("div", { children: [
8807
+ /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold", children: "Pre\xE7os por mercado" }),
8808
+ /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-xs text-muted-foreground", children: "O pre\xE7o deste produto em cada mercado, na moeda dele. No mercado padr\xE3o, vazio usa o pre\xE7o de venda do produto; nos outros, vazio quer dizer que o produto n\xE3o \xE9 vendido l\xE1." })
8809
+ ] }),
8810
+ /* @__PURE__ */ jsx("ul", { className: "divide-y rounded-lg border", children: markets.map((market) => {
8811
+ const value = draft2[market.id] ?? null;
8812
+ const symbol = SYMBOLS[market.currency] ?? market.currency;
8813
+ return /* @__PURE__ */ jsxs("li", { className: "flex flex-wrap items-center gap-4 px-4 py-3", children: [
8814
+ /* @__PURE__ */ jsxs("div", { className: "min-w-[12rem] flex-1", children: [
8815
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm font-medium", children: [
8816
+ market.name,
8817
+ /* @__PURE__ */ jsx(Badge, { variant: "secondary", children: market.currency }),
8818
+ market.isDefault && /* @__PURE__ */ jsx(Badge, { variant: "outline", children: "Padr\xE3o" }),
8819
+ !market.isActive && /* @__PURE__ */ jsx(Badge, { variant: "outline", children: "Inativo" })
8820
+ ] }),
8821
+ /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-xs text-muted-foreground", children: market.countries.length ? market.countries.join(", ") : "Todos os pa\xEDses sem outro mercado" })
8822
+ ] }),
8823
+ /* @__PURE__ */ jsx("div", { className: "w-48", children: /* @__PURE__ */ jsx(
8824
+ CurrencyInput,
8825
+ {
8826
+ value: value ?? 0,
8827
+ onChange: (next) => {
8828
+ setDone(false);
8829
+ setDraft((d) => ({ ...d, [market.id]: next > 0 ? next : null }));
8830
+ },
8831
+ symbol,
8832
+ currencyCode: market.currency,
8833
+ locale: market.locale ?? "pt-BR",
8834
+ placeholder: market.isDefault && basePrice ? String(basePrice) : void 0
8835
+ }
8836
+ ) }),
8837
+ /* @__PURE__ */ jsx("p", { className: "w-full text-xs sm:w-56", children: value != null ? /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Pre\xE7o pr\xF3prio neste mercado." }) : market.isDefault ? /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "Usa o pre\xE7o de venda do produto." }) : /* @__PURE__ */ jsx("span", { className: "text-amber-600", children: "Sem pre\xE7o \u2014 n\xE3o aparece \xE0 venda neste mercado." }) })
8838
+ ] }, market.id);
8839
+ }) }),
8840
+ error && /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: error }),
8841
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
8842
+ /* @__PURE__ */ jsx(Button, { onClick: () => {
8843
+ void save();
8844
+ }, disabled: !dirty || saving, children: saving ? "Salvando\u2026" : "Salvar pre\xE7os" }),
8845
+ done && !dirty && /* @__PURE__ */ jsx("span", { className: "text-sm text-emerald-600", children: "Pre\xE7os salvos." }),
8846
+ /* @__PURE__ */ jsx("a", { href: settingsHref, className: "ml-auto text-xs text-muted-foreground underline underline-offset-2", children: "Gerenciar mercados" })
8847
+ ] })
8848
+ ] });
8849
+ }
8724
8850
 
8725
8851
  // src/index.ts
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 })));
8852
+ var ShopPage = React13__default.lazy(() => import('./ShopPage-FYRAFY7R.js').then((m) => ({ default: m.ShopPage })));
8853
+ var LazyOrderDetail = React13__default.lazy(() => import('./ShopPage-FYRAFY7R.js').then((m) => ({ default: m.ShopOrderDetailSlot })));
8728
8854
  function ShopOrderDetail(provider) {
8729
8855
  const Detail = (props) => React13__default.createElement(
8730
8856
  React13__default.Suspense,
@@ -9171,6 +9297,16 @@ function createShopPlugin(options) {
9171
9297
  order: 30,
9172
9298
  permission: READ
9173
9299
  },
9300
+ {
9301
+ // Onde a loja vende (0116): moeda, países, filial e frete por mercado.
9302
+ id: "shop-markets",
9303
+ label: "Mercados",
9304
+ icon: "Globe",
9305
+ group: COMMERCE_GROUP,
9306
+ component: settingsTab("MarketsSettings", () => React13__default.createElement(MarketsSettings, {})),
9307
+ order: 30.5,
9308
+ permission: READ
9309
+ },
9174
9310
  {
9175
9311
  id: "shop-payments",
9176
9312
  label: "Pagamentos",
@@ -9251,7 +9387,16 @@ function shopProductContentTab(options) {
9251
9387
  props: { getProvider: options.provider, libraryHref: options.libraryHref ?? "#/content" }
9252
9388
  };
9253
9389
  }
9390
+ function shopProductMarketPricesTab(options) {
9391
+ return {
9392
+ id: "market-prices",
9393
+ label: options.label ?? "Pre\xE7os por mercado",
9394
+ icon: "Globe",
9395
+ component: ProductMarketPricesTab,
9396
+ props: { getProvider: options.provider, settingsHref: options.settingsHref ?? "#/settings/shop-markets" }
9397
+ };
9398
+ }
9254
9399
 
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 };
9400
+ 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, ProductMarketPricesTab, 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, shopProductMarketPricesTab, stripeConnectConnectorDef, testNeoChef, toMirroredNeoChefProduct, toMirroredProduct, toNeoChefOrder, vindiConnectorDef, windowFor };
9256
9401
  //# sourceMappingURL=index.js.map
9257
9402
  //# sourceMappingURL=index.js.map