@fayz-ai/plugin-shop 0.23.0 → 0.24.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,9 +1,9 @@
1
1
  import { errorMessage, shopCustomerLookup, resolve, invalidateProductLists, listProductsDetailed, applyQuery, buildShopRegistries, locationSummary, LOCATIONS_REGISTRY, SHIPPING_ZONES_REGISTRY, listProductsCached, resolveTerm, candidateMeta, SHIPPING_PROFILES_REGISTRY, packageMeasureLabel, packagesRegistry, PACKAGES_REGISTRY, marketsRegistry } from './chunk-XV3KZRQX.js';
2
2
  import * as React14 from 'react';
3
3
  import React14__default, { useState, useEffect, useMemo, useRef, useCallback } from 'react';
4
- import { createConnectionStore, connectionSettings, connectionStatus, settingsStatus, connectionRuns, tl, getActiveTenantId, getSupabaseClientOptional, registerMessageDefaults, registerComponent, formatCurrency, 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, formatCurrency, connectorRuntimeToken, CONNECTOR_RUNTIME_TOKEN_HEADER, countByTenant, describeError, useActiveUnitId, 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, SettingsGroup, ToggleRow, useAgentSurface, askAI, TextRow, useConnectors, useConnectorsPanelAvailable, openConnectorsPanel, RegistryCrudView, ConnectorRow, ConnectorDetail, CrudFormPage, SelectRow, MultiSelectRow, AddConnectorButton, AddConnectorPanel, ConnectorMark, StateChip } from '@fayz-ai/admin';
6
+ import { fayzConnectorOAuth, describeConnectorAccount, useOrganizationStore, registerEntityPath, registerPersonLookup, createCrudPage, registerCrudNavTabs, adminNavigateTo, DetailTabHeader, AskAIButton, PageActions, SettingsGroup, useAgentSurface, askAI, useSettingKeys, TextRow, useConnectors, useConnectorsPanelAvailable, openConnectorsPanel, RegistryCrudView, ConnectorRow, ConnectorDetail, CrudFormPage, SelectRow, ToggleRow, MultiSelectRow, AddConnectorButton, AddConnectorPanel, 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, ArrowRight, AlertTriangle, Warehouse, MapPin, Car, Truck, X, ExternalLink, Box, ChevronDown, Film, FileText, Sparkles, Ban, ListChecks, Check, Search, Building2, Info } from 'lucide-react';
8
8
  import { Skeleton, Badge, CurrencyInput, Button, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, PageTabs, PageHeaderActions, Card, Modal, ModalContent, ModalHeader, ModalTitle, ModalDescription, Input, ModalFooter, Thumbnail, PageHeader, toast, ConfirmDialog, Checkbox, Hint, DataTable, ModalBody } from '@fayz-ai/ui';
9
9
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
@@ -5212,9 +5212,7 @@ function ShippingSettings({ provider, variant = "full" }) {
5212
5212
  return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-card p-5 text-sm shadow-sm", "data-testid": "shipping-is-delivery", children: [
5213
5213
  /* @__PURE__ */ jsx("p", { className: "font-medium", children: "Esta loja \xE9 um delivery" }),
5214
5214
  /* @__PURE__ */ jsx("p", { className: "mt-1 text-muted-foreground", children: "Taxa de entrega, frete gr\xE1tis, regi\xF5es, pedido m\xEDnimo e tempo estimado ficam em Configura\xE7\xF5es \u203A Delivery. Esta tela \xE9 das lojas que despacham por transportadora." }),
5215
- /* @__PURE__ */ jsxs(Button, { className: "mt-3", size: "sm", onClick: () => {
5216
- window.location.hash = "#/settings/orders-delivery";
5217
- }, children: [
5215
+ /* @__PURE__ */ jsxs(Button, { className: "mt-3", size: "sm", onClick: () => adminNavigateTo("/settings/orders-delivery"), children: [
5218
5216
  "Abrir Delivery ",
5219
5217
  /* @__PURE__ */ jsx(ArrowRight, { className: "ml-1 h-3.5 w-3.5" })
5220
5218
  ] })
@@ -5242,7 +5240,7 @@ function ShippingSettings({ provider, variant = "full" }) {
5242
5240
  ] }) : /* @__PURE__ */ jsxs(
5243
5241
  SettingsGroup,
5244
5242
  {
5245
- title: embedded ? "Taxa de entrega" : "Pre\xE7o base",
5243
+ title: embedded ? "Quanto custa a entrega" : "Pre\xE7o base",
5246
5244
  description: embedded ? "O que o site cobra para entregar quando nenhuma regi\xE3o abaixo tem pre\xE7o pr\xF3prio." : "O que a loja cobra quando nenhuma zona cobre o endere\xE7o. Uma zona que cobre o CEP sempre ganha deste n\xFAmero.",
5247
5245
  children: [
5248
5246
  /* @__PURE__ */ jsx(
@@ -5443,26 +5441,101 @@ function NumberRow({ label, description, hint, value, onCommit, placeholder, int
5443
5441
  }
5444
5442
  );
5445
5443
  }
5444
+ function EtaRow({ minutes, onCommit }) {
5445
+ const [unit, setUnit] = React14__default.useState(() => minutes != null && minutes >= 60 && minutes % 60 === 0 ? "h" : "min");
5446
+ const shown = (m, u) => m == null ? "" : u === "h" ? String(+(m / 60).toFixed(2)).replace(".", ",") : String(m);
5447
+ const [draft2, setDraft] = React14__default.useState(() => shown(minutes, unit));
5448
+ const [invalid, setInvalid] = React14__default.useState(false);
5449
+ React14__default.useEffect(() => {
5450
+ setDraft(shown(minutes, unit));
5451
+ }, [minutes, unit]);
5452
+ const commit = (raw, u) => {
5453
+ const parsed = parseNumber2(raw);
5454
+ if (Number.isNaN(parsed)) {
5455
+ setInvalid(true);
5456
+ return;
5457
+ }
5458
+ setInvalid(false);
5459
+ onCommit(parsed == null || parsed === 0 ? null : Math.round(u === "h" ? parsed * 60 : parsed));
5460
+ };
5461
+ return /* @__PURE__ */ jsxs("div", { className: "py-3", children: [
5462
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: "Tempo estimado" }),
5463
+ /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-xs text-muted-foreground", children: "Da confirma\xE7\xE3o at\xE9 a porta. Aparece no topo do card\xE1pio e no aviso de pedido aceito \u2014 de 24 h em diante, como \xABat\xE9 24 h\xBB." }),
5464
+ /* @__PURE__ */ jsxs("div", { className: "mt-2 flex max-w-xs items-center gap-2", children: [
5465
+ /* @__PURE__ */ jsx(
5466
+ Input,
5467
+ {
5468
+ value: draft2,
5469
+ placeholder: "N\xE3o informar",
5470
+ "aria-invalid": invalid || void 0,
5471
+ "aria-label": "Tempo estimado",
5472
+ onChange: (e) => {
5473
+ setDraft(e.target.value);
5474
+ setInvalid(false);
5475
+ },
5476
+ onBlur: () => commit(draft2, unit),
5477
+ onKeyDown: (e) => {
5478
+ if (e.key === "Enter") commit(draft2, unit);
5479
+ },
5480
+ "data-testid": "delivery-eta-value"
5481
+ }
5482
+ ),
5483
+ /* @__PURE__ */ jsx("div", { role: "radiogroup", "aria-label": "Unidade", className: "flex shrink-0 rounded-md border p-0.5 text-xs", children: ["min", "h"].map((u) => /* @__PURE__ */ jsx(
5484
+ "button",
5485
+ {
5486
+ type: "button",
5487
+ role: "radio",
5488
+ "aria-checked": unit === u,
5489
+ "data-testid": `delivery-eta-unit-${u}`,
5490
+ onClick: () => {
5491
+ if (u !== unit) {
5492
+ setUnit(u);
5493
+ setDraft(shown(minutes, u));
5494
+ }
5495
+ },
5496
+ className: `rounded px-2.5 py-1 ${unit === u ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:bg-muted"}`,
5497
+ children: u === "min" ? "minutos" : "horas"
5498
+ },
5499
+ u
5500
+ )) })
5501
+ ] }),
5502
+ /* @__PURE__ */ jsx("p", { className: `mt-1 text-xs ${invalid ? "text-destructive" : "text-muted-foreground"}`, children: invalid ? "Use um n\xFAmero, como 45 ou 1,5." : "Vazio = n\xE3o mostrar." })
5503
+ ] });
5504
+ }
5505
+ function DeliverySwitchStatus() {
5506
+ const unitId = useActiveUnitId();
5507
+ const s = useSettingKeys(["delivery.enabled"], unitId ?? null);
5508
+ if (!s.supported || s.loading || s.loadError) return null;
5509
+ const open = s.values["delivery.enabled"] !== false;
5510
+ return /* @__PURE__ */ jsxs("p", { "data-testid": "delivery-switch-status", className: "flex items-center gap-2 py-3 text-sm", children: [
5511
+ /* @__PURE__ */ jsx("span", { className: `h-2 w-2 shrink-0 rounded-full ${open ? "bg-emerald-500" : "bg-amber-500"}`, "aria-hidden": true }),
5512
+ open ? /* @__PURE__ */ jsxs("span", { children: [
5513
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: "Delivery aberto agora" }),
5514
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: " \xB7 pause pela chave Delivery no topo" })
5515
+ ] }) : /* @__PURE__ */ jsxs("span", { children: [
5516
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: "Delivery pausado" }),
5517
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: " \xB7 o site mostra fechado" })
5518
+ ] })
5519
+ ] });
5520
+ }
5446
5521
  function DeliveryStoreSettings({ provider }) {
5447
5522
  const settings = useStoreSettings(provider);
5448
5523
  const { value, set } = settings;
5449
5524
  return /* @__PURE__ */ jsxs("div", { className: "space-y-4", "data-testid": "delivery-store-settings", children: [
5450
- /* @__PURE__ */ jsxs(
5525
+ /* @__PURE__ */ jsx(
5451
5526
  SettingsGroup,
5452
5527
  {
5453
5528
  title: "Pedidos do site",
5454
- description: "Como o delivery do site funciona: a opera\xE7\xE3o aceita cada pedido, despacha e avisa o cliente a cada passo.",
5529
+ description: "O delivery do site abre e pausa pela chave Delivery no topo do sistema.",
5530
+ children: /* @__PURE__ */ jsx(DeliverySwitchStatus, {})
5531
+ }
5532
+ ),
5533
+ /* @__PURE__ */ jsxs(
5534
+ SettingsGroup,
5535
+ {
5536
+ title: "Pedido m\xEDnimo e tempo",
5537
+ description: "O que o site exige e promete em cada pedido de delivery.",
5455
5538
  children: [
5456
- /* @__PURE__ */ jsx(
5457
- ToggleRow,
5458
- {
5459
- label: "A loja entrega pelo site",
5460
- description: "Ligado, cada pedido do site entra no quadro de Delivery como Novo, e o cliente recebe os avisos por WhatsApp e e-mail.",
5461
- checked: value.deliveryFlow === true,
5462
- onChange: (checked) => set({ deliveryFlow: checked }),
5463
- disabled: settings.loading || !settings.supported
5464
- }
5465
- ),
5466
5539
  /* @__PURE__ */ jsx(
5467
5540
  NumberRow,
5468
5541
  {
@@ -5474,17 +5547,7 @@ function DeliveryStoreSettings({ provider }) {
5474
5547
  onCommit: (next) => set({ minOrderTotal: next ?? null })
5475
5548
  }
5476
5549
  ),
5477
- /* @__PURE__ */ jsx(
5478
- NumberRow,
5479
- {
5480
- label: "Tempo estimado (min)",
5481
- description: "Da confirma\xE7\xE3o at\xE9 a porta. Aparece no topo do card\xE1pio e no aviso de pedido aceito.",
5482
- value: value.deliveryEtaMinutes,
5483
- placeholder: "N\xE3o informar",
5484
- integer: true,
5485
- onCommit: (next) => set({ deliveryEtaMinutes: next ?? null })
5486
- }
5487
- )
5550
+ /* @__PURE__ */ jsx(EtaRow, { minutes: value.deliveryEtaMinutes, onCommit: (next) => set({ deliveryEtaMinutes: next }) })
5488
5551
  ]
5489
5552
  }
5490
5553
  ),