@fayz-ai/plugin-shop 0.18.2 → 0.19.1

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.
Files changed (52) hide show
  1. package/dist/{ShopPage-J34V43NW.js → ShopPage-2CTRGQTX.js} +176 -247
  2. package/dist/ShopPage-2CTRGQTX.js.map +1 -0
  3. package/dist/{chunk-6DRDPROL.js → chunk-XV3KZRQX.js} +136 -31
  4. package/dist/chunk-XV3KZRQX.js.map +1 -0
  5. package/dist/data/registries.d.ts +2 -0
  6. package/dist/data/registries.d.ts.map +1 -1
  7. package/dist/index.d.ts +23 -2
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +757 -511
  10. package/dist/index.js.map +1 -1
  11. package/dist/integrations/abacatepay/connectorDef.d.ts.map +1 -1
  12. package/dist/settings/ChoiceCards.d.ts.map +1 -1
  13. package/dist/settings/HandlingSettings.d.ts.map +1 -1
  14. package/dist/settings/MarketsSettings.d.ts +12 -0
  15. package/dist/settings/MarketsSettings.d.ts.map +1 -0
  16. package/dist/settings/PaymentProviderRow.d.ts.map +1 -1
  17. package/dist/settings/ShippingSettings.d.ts.map +1 -1
  18. package/dist/views/DeliveryAreaPicker.d.ts.map +1 -1
  19. package/dist/views/DeliveryRulesDraft.d.ts.map +1 -1
  20. package/dist/views/EmailTemplatePage.d.ts.map +1 -1
  21. package/dist/views/EmailsPage.d.ts.map +1 -1
  22. package/dist/views/FulfillmentProviderSelect.d.ts.map +1 -1
  23. package/dist/views/NewOrderCharge.d.ts.map +1 -1
  24. package/dist/views/NewOrderPage.d.ts.map +1 -1
  25. package/dist/views/OrderDetailView.d.ts.map +1 -1
  26. package/dist/views/OrderPaymentDetail.d.ts.map +1 -1
  27. package/dist/views/ProductMarketPricesTab.d.ts +19 -0
  28. package/dist/views/ProductMarketPricesTab.d.ts.map +1 -0
  29. package/dist/views/ProductPositionsTab.d.ts.map +1 -1
  30. package/dist/views/ProductStockTab.d.ts.map +1 -1
  31. package/dist/views/ProductVariantsTab.d.ts.map +1 -1
  32. package/dist/views/ShipOrderForm.d.ts.map +1 -1
  33. package/dist/views/ShipmentActions.d.ts.map +1 -1
  34. package/dist/views/ShippingProfileSelect.d.ts.map +1 -1
  35. package/dist/views/ShopPage.d.ts.map +1 -1
  36. package/dist/views/StockEntryModal.d.ts.map +1 -1
  37. package/dist/views/customerEntity.d.ts.map +1 -1
  38. package/dist/views/customerSegmentEntity.d.ts.map +1 -1
  39. package/dist/views/discountEntity.d.ts.map +1 -1
  40. package/dist/views/giftCardEntity.d.ts.map +1 -1
  41. package/dist/views/product-matching.d.ts.map +1 -1
  42. package/dist/views/productEntity.d.ts.map +1 -1
  43. package/dist/views/shippingZoneEntity.d.ts.map +1 -1
  44. package/package.json +7 -7
  45. package/dist/ShopPage-J34V43NW.js.map +0 -1
  46. package/dist/chunk-6DRDPROL.js.map +0 -1
  47. package/dist/integrations/bling/index.d.ts +0 -9
  48. package/dist/integrations/bling/index.d.ts.map +0 -1
  49. package/dist/integrations/neochef/index.d.ts +0 -8
  50. package/dist/integrations/neochef/index.d.ts.map +0 -1
  51. package/dist/settings/index.d.ts +0 -12
  52. package/dist/settings/index.d.ts.map +0 -1
package/dist/index.js CHANGED
@@ -1,14 +1,14 @@
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-XV3KZRQX.js';
2
2
  import * as React13 from 'react';
3
- import React13__default, { useState, useEffect, useRef, useCallback, useMemo } from 'react';
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';
3
+ import React13__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';
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, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, Modal, ModalContent, ModalHeader, ModalTitle, ModalDescription, Input, ModalFooter, Thumbnail, PageHeader, toast, ConfirmDialog, Checkbox, Hint, ModalBody, DataTable } 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
- import { normalizeMovementType } from '@fayz-ai/plugin-inventory';
11
+ import { normalizeMovementType } from '@fayz-ai/inventory/domain/movement';
12
12
  import { advanceWindow, createRateLimiter, sliceWindow, paginate, reconcileMirror, serializeCursor } from '@fayz-ai/core/connector-runtime';
13
13
 
14
14
  function buildShopOnboarding(siteRoute = "/site", withProducts = true) {
@@ -319,12 +319,14 @@ function ProductImagesTab({ item, getProvider, footer }) {
319
319
  /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-20" })
320
320
  ] })
321
321
  ] }, i)) }) : images.length === 0 || dragging ? /* @__PURE__ */ jsxs(
322
- "button",
322
+ Button,
323
323
  {
324
+ variant: "bare",
325
+ size: "bare",
324
326
  type: "button",
325
327
  disabled: busy,
326
328
  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"}`,
329
+ className: `font-normal whitespace-normal 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
330
  children: [
329
331
  /* @__PURE__ */ jsx(UploadCloud, { className: "h-6 w-6", "aria-hidden": true }),
330
332
  /* @__PURE__ */ jsx("span", { className: "font-medium", children: dragging ? "Solte para enviar" : "Arraste as fotos para c\xE1, ou clique para escolher" }),
@@ -359,12 +361,14 @@ function ProductImagesTab({ item, getProvider, footer }) {
359
361
  ] }),
360
362
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
361
363
  !image.isPrimary && update && /* @__PURE__ */ jsx(
362
- "button",
364
+ Button,
363
365
  {
366
+ variant: "bare",
367
+ size: "bare",
364
368
  type: "button",
365
369
  disabled: busy,
366
370
  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",
371
+ className: "font-normal whitespace-nowrap rounded px-1.5 py-0.5 text-xs text-muted-foreground hover:bg-muted hover:text-foreground disabled:opacity-50",
368
372
  children: "Usar como capa"
369
373
  }
370
374
  ),
@@ -390,12 +394,14 @@ function ProductImagesTab({ item, getProvider, footer }) {
390
394
  }
391
395
  ),
392
396
  /* @__PURE__ */ jsx(
393
- "button",
397
+ Button,
394
398
  {
399
+ variant: "bare",
400
+ size: "bare",
395
401
  type: "button",
396
402
  disabled: busy,
397
403
  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",
404
+ className: "font-normal rounded px-1.5 py-0.5 text-xs text-red-600 hover:bg-red-50 disabled:opacity-50",
399
405
  children: "Excluir"
400
406
  }
401
407
  )
@@ -410,14 +416,16 @@ function ProductImagesTab({ item, getProvider, footer }) {
410
416
  }
411
417
  function IconButton({ label, disabled, onClick, children }) {
412
418
  return /* @__PURE__ */ jsx(
413
- "button",
419
+ Button,
414
420
  {
421
+ variant: "bare",
422
+ size: "bare",
415
423
  type: "button",
416
424
  "aria-label": label,
417
425
  title: label,
418
426
  disabled,
419
427
  onClick,
420
- className: "rounded border px-1.5 py-0.5 text-xs text-muted-foreground transition hover:bg-muted hover:text-foreground disabled:opacity-40",
428
+ className: "font-normal disabled:pointer-events-auto rounded border px-1.5 py-0.5 text-xs text-muted-foreground transition hover:bg-muted hover:text-foreground disabled:opacity-40",
421
429
  children
422
430
  }
423
431
  );
@@ -535,18 +543,22 @@ function ProductVariantsTab({ item, getProvider }) {
535
543
  dirty && /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-3 rounded-lg border bg-muted/30 px-4 py-3", children: [
536
544
  /* @__PURE__ */ jsx("p", { className: "flex-1 text-xs text-muted-foreground", children: describePlan(plan) }),
537
545
  /* @__PURE__ */ jsx(
538
- "button",
546
+ Button,
539
547
  {
548
+ variant: "bare",
549
+ size: "bare",
540
550
  type: "button",
541
551
  disabled: busy,
542
552
  onClick: () => void reload(),
543
- className: "rounded-md px-3 py-1.5 text-xs text-muted-foreground hover:bg-muted disabled:opacity-40",
553
+ className: "font-normal rounded-md px-3 py-1.5 text-xs text-muted-foreground hover:bg-muted disabled:opacity-40",
544
554
  children: "Descartar"
545
555
  }
546
556
  ),
547
557
  /* @__PURE__ */ jsxs(
548
- "button",
558
+ Button,
549
559
  {
560
+ variant: "bare",
561
+ size: "bare",
550
562
  type: "button",
551
563
  disabled: busy || Boolean(axisError),
552
564
  onClick: save,
@@ -589,23 +601,25 @@ function AxisEditor({ axis, index, count, disabled, onChange, onMove, onRemove }
589
601
  }
590
602
  return /* @__PURE__ */ jsxs("li", { className: "rounded-card border bg-card p-3", children: [
591
603
  /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
592
- /* @__PURE__ */ jsx(
593
- "input",
604
+ /* @__PURE__ */ jsx("div", { className: "w-40", children: /* @__PURE__ */ jsx(
605
+ Input,
594
606
  {
595
607
  value: axis.name,
596
608
  disabled,
597
609
  onChange: (e) => onChange({ ...axis, name: e.target.value }),
598
610
  placeholder: "Tamanho",
599
611
  "aria-label": `Nome da op\xE7\xE3o ${index + 1}`,
600
- className: "h-8 w-40 rounded-input border border-input bg-background px-2 text-sm font-medium"
612
+ className: "h-8 bg-background px-2 font-medium shadow-none"
601
613
  }
602
- ),
614
+ ) }),
603
615
  /* @__PURE__ */ jsx("span", { className: "flex-1" }),
604
616
  /* @__PURE__ */ jsx(IconButton2, { label: "Mover para cima", disabled: disabled || index === 0, onClick: () => onMove(-1), children: "\u2191" }),
605
617
  /* @__PURE__ */ jsx(IconButton2, { label: "Mover para baixo", disabled: disabled || index === count - 1, onClick: () => onMove(1), children: "\u2193" }),
606
618
  /* @__PURE__ */ jsx(
607
- "button",
619
+ Button,
608
620
  {
621
+ variant: "bare",
622
+ size: "bare",
609
623
  type: "button",
610
624
  "aria-label": "Remover op\xE7\xE3o",
611
625
  disabled,
@@ -619,8 +633,10 @@ function AxisEditor({ axis, index, count, disabled, onChange, onMove, onRemove }
619
633
  axis.values.map((value, position) => /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1 rounded-full bg-muted px-2.5 py-1 text-xs", children: [
620
634
  value,
621
635
  /* @__PURE__ */ jsx(
622
- "button",
636
+ Button,
623
637
  {
638
+ variant: "bare",
639
+ size: "bare",
624
640
  type: "button",
625
641
  "aria-label": `Remover ${value}`,
626
642
  disabled,
@@ -630,8 +646,8 @@ function AxisEditor({ axis, index, count, disabled, onChange, onMove, onRemove }
630
646
  }
631
647
  )
632
648
  ] }, value)),
633
- /* @__PURE__ */ jsx(
634
- "input",
649
+ /* @__PURE__ */ jsx("div", { className: "min-w-28 flex-1", children: /* @__PURE__ */ jsx(
650
+ Input,
635
651
  {
636
652
  value: draft2,
637
653
  disabled,
@@ -645,13 +661,17 @@ function AxisEditor({ axis, index, count, disabled, onChange, onMove, onRemove }
645
661
  onBlur: () => commit(draft2),
646
662
  placeholder: axis.values.length === 0 ? "P, M, G" : "adicionar",
647
663
  "aria-label": `Valores da op\xE7\xE3o ${index + 1}`,
648
- className: "h-7 min-w-28 flex-1 rounded-input border border-dashed border-input bg-transparent px-2 text-xs"
664
+ className: "h-7 border-dashed bg-transparent px-2 text-xs shadow-none"
649
665
  }
650
- )
666
+ ) })
651
667
  ] })
652
668
  ] });
653
669
  }
654
670
  var UNITS = ["kg", "g", "lb"];
671
+ var INHERIT = "__inherit__";
672
+ var COVER = "__cover__";
673
+ var COMPACT_INPUT = "h-7 bg-background px-2 text-xs shadow-none";
674
+ var COMPACT_SELECT = "h-7 w-auto gap-1 bg-background px-1.5 text-xs shadow-none";
655
675
  function VariantGrid({ rows, axes, product, busy, dirty, selected, onSelect, onSave, onStock }) {
656
676
  const saved = rows.filter((row) => row.variant);
657
677
  const allSelected = saved.length > 0 && saved.every((row) => selected.has(row.variant.id));
@@ -688,9 +708,8 @@ function VariantGrid({ rows, axes, product, busy, dirty, selected, onSelect, onS
688
708
  /* @__PURE__ */ jsx("div", { className: "overflow-x-auto rounded-lg border", children: /* @__PURE__ */ jsxs("table", { className: "w-full min-w-[62rem] text-sm", children: [
689
709
  /* @__PURE__ */ jsx("thead", { className: "bg-muted/40 text-left text-xs text-muted-foreground", children: /* @__PURE__ */ jsxs("tr", { children: [
690
710
  /* @__PURE__ */ jsx("th", { className: "w-9 px-2 py-2", children: /* @__PURE__ */ jsx(
691
- "input",
711
+ Checkbox,
692
712
  {
693
- type: "checkbox",
694
713
  "aria-label": "Selecionar todas",
695
714
  checked: allSelected,
696
715
  disabled: busy || saved.length === 0,
@@ -734,9 +753,8 @@ function VariantRow({ row, axes, product, busy, checked, onToggle, onSave, onSto
734
753
  };
735
754
  return /* @__PURE__ */ jsxs("tr", { className: pending ? "bg-muted/20 text-muted-foreground" : void 0, children: [
736
755
  /* @__PURE__ */ jsx("td", { className: "px-2 py-1.5", children: /* @__PURE__ */ jsx(
737
- "input",
756
+ Checkbox,
738
757
  {
739
- type: "checkbox",
740
758
  "aria-label": `Selecionar ${label}`,
741
759
  checked,
742
760
  disabled: busy || pending,
@@ -799,16 +817,17 @@ function VariantRow({ row, axes, product, busy, checked, onToggle, onSave, onSto
799
817
  }
800
818
  ),
801
819
  /* @__PURE__ */ jsxs(
802
- "select",
820
+ Select,
803
821
  {
804
- value: variant?.weightUnit ?? "",
822
+ value: variant?.weightUnit ?? INHERIT,
805
823
  disabled: busy || pending,
806
- onChange: (e) => commit("weightUnit", e.target.value || null, variant?.weightUnit ?? null),
807
- "aria-label": `Unidade de peso de ${label}`,
808
- className: "h-7 rounded-input border border-input bg-background px-1 text-xs",
824
+ onValueChange: (v) => commit("weightUnit", v === INHERIT ? null : v, variant?.weightUnit ?? null),
809
825
  children: [
810
- /* @__PURE__ */ jsx("option", { value: "", children: product.weightUnit }),
811
- UNITS.map((unit) => /* @__PURE__ */ jsx("option", { value: unit, children: unit }, unit))
826
+ /* @__PURE__ */ jsx(SelectTrigger, { "aria-label": `Unidade de peso de ${label}`, className: COMPACT_SELECT, children: /* @__PURE__ */ jsx(SelectValue, {}) }),
827
+ /* @__PURE__ */ jsxs(SelectContent, { children: [
828
+ /* @__PURE__ */ jsx(SelectItem, { value: INHERIT, children: product.weightUnit }),
829
+ UNITS.map((unit) => /* @__PURE__ */ jsx(SelectItem, { value: unit, children: unit }, unit))
830
+ ] })
812
831
  ]
813
832
  }
814
833
  )
@@ -825,30 +844,30 @@ function VariantRow({ row, axes, product, busy, checked, onToggle, onSave, onSto
825
844
  key
826
845
  )) }) }),
827
846
  /* @__PURE__ */ jsx("td", { className: "px-2 py-1.5", children: /* @__PURE__ */ jsxs(
828
- "select",
847
+ Select,
829
848
  {
830
- value: variant?.imageId ?? "",
849
+ value: variant?.imageId ?? COVER,
831
850
  disabled: busy || pending || product.images.length === 0,
832
- onChange: (e) => commit("imageId", e.target.value || null, variant?.imageId ?? null),
833
- "aria-label": `Foto de ${label}`,
834
- className: "h-7 w-24 rounded-input border border-input bg-background px-1 text-xs",
851
+ onValueChange: (v) => commit("imageId", v === COVER ? null : v, variant?.imageId ?? null),
835
852
  children: [
836
- /* @__PURE__ */ jsx("option", { value: "", children: "capa" }),
837
- product.images.map((image, index) => /* @__PURE__ */ jsxs("option", { value: image.id, children: [
838
- "Foto ",
839
- index + 1
840
- ] }, image.id))
853
+ /* @__PURE__ */ jsx(SelectTrigger, { "aria-label": `Foto de ${label}`, className: `${COMPACT_SELECT} w-24`, children: /* @__PURE__ */ jsx(SelectValue, {}) }),
854
+ /* @__PURE__ */ jsxs(SelectContent, { children: [
855
+ /* @__PURE__ */ jsx(SelectItem, { value: COVER, children: "capa" }),
856
+ product.images.map((image, index) => /* @__PURE__ */ jsxs(SelectItem, { value: image.id, children: [
857
+ "Foto ",
858
+ index + 1
859
+ ] }, image.id))
860
+ ] })
841
861
  ]
842
862
  }
843
863
  ) }),
844
864
  /* @__PURE__ */ jsx("td", { className: "px-2 py-1.5", children: /* @__PURE__ */ jsx(
845
- "input",
865
+ Checkbox,
846
866
  {
847
- type: "checkbox",
848
867
  "aria-label": `${label} ativa`,
849
868
  checked: variant?.status === "active",
850
869
  disabled: busy || pending,
851
- onChange: (e) => commit("status", e.target.checked ? "active" : "archived", variant?.status)
870
+ onChange: (on) => commit("status", on ? "active" : "archived", variant?.status)
852
871
  }
853
872
  ) })
854
873
  ] });
@@ -864,68 +883,66 @@ function BulkBar({ count, disabled, onApply, onClear }) {
864
883
  count > 1 ? "s" : ""
865
884
  ] }),
866
885
  /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "\xB7" }),
867
- /* @__PURE__ */ jsx(
868
- "input",
886
+ /* @__PURE__ */ jsx("div", { className: "w-24", children: /* @__PURE__ */ jsx(
887
+ Input,
869
888
  {
870
889
  value: price,
871
890
  onChange: (e) => setPrice(e.target.value),
872
891
  placeholder: "Pre\xE7o",
873
892
  "aria-label": "Pre\xE7o para todas",
874
- className: "h-7 w-24 rounded-input border border-input bg-background px-2"
893
+ className: COMPACT_INPUT
875
894
  }
876
- ),
895
+ ) }),
877
896
  /* @__PURE__ */ jsx(
878
- "button",
897
+ Button,
879
898
  {
899
+ variant: "bare",
900
+ size: "bare",
880
901
  type: "button",
881
902
  disabled: disabled || parseNumber(price) == null,
882
903
  onClick: () => {
883
904
  onApply({ price: parseNumber(price) });
884
905
  setPrice("");
885
906
  },
886
- className: "rounded-md border px-2 py-1 font-medium hover:bg-muted disabled:opacity-40",
907
+ className: "rounded-md border px-2 py-1 text-xs font-medium hover:bg-muted disabled:opacity-40",
887
908
  children: "Aplicar pre\xE7o"
888
909
  }
889
910
  ),
890
911
  /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "\xB7" }),
891
- /* @__PURE__ */ jsx(
892
- "input",
912
+ /* @__PURE__ */ jsx("div", { className: "w-20", children: /* @__PURE__ */ jsx(
913
+ Input,
893
914
  {
894
915
  value: weight,
895
916
  onChange: (e) => setWeight(e.target.value),
896
917
  placeholder: "Peso",
897
918
  "aria-label": "Peso para todas",
898
- className: "h-7 w-20 rounded-input border border-input bg-background px-2"
899
- }
900
- ),
901
- /* @__PURE__ */ jsxs(
902
- "select",
903
- {
904
- value: unit,
905
- onChange: (e) => setUnit(e.target.value),
906
- "aria-label": "Unidade para todas",
907
- className: "h-7 rounded-input border border-input bg-background px-1",
908
- children: [
909
- /* @__PURE__ */ jsx("option", { value: "", children: "herdar" }),
910
- UNITS.map((u) => /* @__PURE__ */ jsx("option", { value: u, children: u }, u))
911
- ]
919
+ className: COMPACT_INPUT
912
920
  }
913
- ),
921
+ ) }),
922
+ /* @__PURE__ */ jsxs(Select, { value: unit || INHERIT, onValueChange: (v) => setUnit(v === INHERIT ? "" : v), children: [
923
+ /* @__PURE__ */ jsx(SelectTrigger, { "aria-label": "Unidade para todas", className: COMPACT_SELECT, children: /* @__PURE__ */ jsx(SelectValue, {}) }),
924
+ /* @__PURE__ */ jsxs(SelectContent, { children: [
925
+ /* @__PURE__ */ jsx(SelectItem, { value: INHERIT, children: "herdar" }),
926
+ UNITS.map((u) => /* @__PURE__ */ jsx(SelectItem, { value: u, children: u }, u))
927
+ ] })
928
+ ] }),
914
929
  /* @__PURE__ */ jsx(
915
- "button",
930
+ Button,
916
931
  {
932
+ variant: "bare",
933
+ size: "bare",
917
934
  type: "button",
918
935
  disabled: disabled || parseNumber(weight) == null,
919
936
  onClick: () => {
920
937
  onApply({ weight: parseNumber(weight), weightUnit: unit || null });
921
938
  setWeight("");
922
939
  },
923
- className: "rounded-md border px-2 py-1 font-medium hover:bg-muted disabled:opacity-40",
940
+ className: "rounded-md border px-2 py-1 text-xs font-medium hover:bg-muted disabled:opacity-40",
924
941
  children: "Aplicar peso"
925
942
  }
926
943
  ),
927
944
  /* @__PURE__ */ jsx("span", { className: "flex-1" }),
928
- /* @__PURE__ */ jsx("button", { type: "button", onClick: onClear, className: "text-muted-foreground hover:text-foreground", children: "limpar sele\xE7\xE3o" })
945
+ /* @__PURE__ */ jsx(Button, { variant: "bare", size: "bare", type: "button", onClick: onClear, className: "text-xs font-normal text-muted-foreground hover:text-foreground", children: "limpar sele\xE7\xE3o" })
929
946
  ] });
930
947
  }
931
948
  function parseNumber(raw) {
@@ -939,8 +956,8 @@ function NumberCell({ value, disabled, placeholder, onCommit, width = "w-20", in
939
956
  React13__default.useEffect(() => {
940
957
  setDraft(value == null ? "" : String(value));
941
958
  }, [value]);
942
- return /* @__PURE__ */ jsx(
943
- "input",
959
+ return /* @__PURE__ */ jsx("div", { className: width, children: /* @__PURE__ */ jsx(
960
+ Input,
944
961
  {
945
962
  value: draft2,
946
963
  disabled,
@@ -950,37 +967,39 @@ function NumberCell({ value, disabled, placeholder, onCommit, width = "w-20", in
950
967
  const parsed = parseNumber(draft2);
951
968
  onCommit(parsed == null ? null : integer ? Math.trunc(parsed) : parsed);
952
969
  },
953
- className: `h-7 ${width} rounded-input border border-input bg-background px-2 text-xs tabular-nums`
970
+ className: `${COMPACT_INPUT} tabular-nums`
954
971
  }
955
- );
972
+ ) });
956
973
  }
957
974
  function TextCell({ value, disabled, placeholder, onCommit }) {
958
975
  const [draft2, setDraft] = React13__default.useState(value);
959
976
  React13__default.useEffect(() => {
960
977
  setDraft(value);
961
978
  }, [value]);
962
- return /* @__PURE__ */ jsx(
963
- "input",
979
+ return /* @__PURE__ */ jsx("div", { className: "w-28", children: /* @__PURE__ */ jsx(
980
+ Input,
964
981
  {
965
982
  value: draft2,
966
983
  disabled,
967
984
  placeholder,
968
985
  onChange: (e) => setDraft(e.target.value),
969
986
  onBlur: () => onCommit(draft2.trim()),
970
- className: "h-7 w-28 rounded-input border border-input bg-background px-2 text-xs"
987
+ className: COMPACT_INPUT
971
988
  }
972
- );
989
+ ) });
973
990
  }
974
991
  function IconButton2({ label, disabled, onClick, children }) {
975
992
  return /* @__PURE__ */ jsx(
976
- "button",
993
+ Button,
977
994
  {
995
+ variant: "bare",
996
+ size: "bare",
978
997
  type: "button",
979
998
  "aria-label": label,
980
999
  title: label,
981
1000
  disabled,
982
1001
  onClick,
983
- className: "rounded border px-1.5 py-0.5 text-xs text-muted-foreground transition hover:bg-muted hover:text-foreground disabled:opacity-40",
1002
+ className: "font-normal disabled:pointer-events-auto rounded border px-1.5 py-0.5 text-xs text-muted-foreground transition hover:bg-muted hover:text-foreground disabled:opacity-40",
984
1003
  children
985
1004
  }
986
1005
  );
@@ -1041,13 +1060,13 @@ function NewAxisModal({ open, onClose, onCreate }) {
1041
1060
  /* @__PURE__ */ jsxs("label", { className: "block", children: [
1042
1061
  /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Nome" }),
1043
1062
  /* @__PURE__ */ jsx(
1044
- "input",
1063
+ Input,
1045
1064
  {
1046
1065
  autoFocus: true,
1047
1066
  value: name,
1048
1067
  onChange: (e) => setName(e.target.value),
1049
1068
  placeholder: "Tamanho",
1050
- className: "mt-1 h-9 w-full rounded-md border bg-background px-2.5 text-sm outline-none focus:border-primary"
1069
+ className: "mt-1 px-2.5"
1051
1070
  }
1052
1071
  )
1053
1072
  ] }),
@@ -1055,7 +1074,7 @@ function NewAxisModal({ open, onClose, onCreate }) {
1055
1074
  /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Valores" }),
1056
1075
  /* @__PURE__ */ jsx("ul", { className: "mt-1 space-y-1.5", children: values.map((value, index) => /* @__PURE__ */ jsxs("li", { className: "flex items-center gap-1.5", children: [
1057
1076
  /* @__PURE__ */ jsx(
1058
- "input",
1077
+ Input,
1059
1078
  {
1060
1079
  value,
1061
1080
  onChange: (e) => setValue(index, e.target.value),
@@ -1069,12 +1088,14 @@ function NewAxisModal({ open, onClose, onCreate }) {
1069
1088
  },
1070
1089
  placeholder: index === values.length - 1 ? "Adicionar valor" : "",
1071
1090
  "aria-label": `Valor ${index + 1}`,
1072
- className: "h-9 w-full rounded-md border bg-background px-2.5 text-sm outline-none focus:border-primary"
1091
+ className: "px-2.5"
1073
1092
  }
1074
1093
  ),
1075
1094
  index < values.length - 1 && /* @__PURE__ */ jsx(
1076
- "button",
1095
+ Button,
1077
1096
  {
1097
+ variant: "bare",
1098
+ size: "bare",
1078
1099
  type: "button",
1079
1100
  onClick: () => removeValue(index),
1080
1101
  "aria-label": `Remover valor ${index + 1}`,
@@ -1354,7 +1375,8 @@ var KIND_FOR = {
1354
1375
  perda: "loss"
1355
1376
  };
1356
1377
  var todayISO = () => (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
1357
- var field = "mt-1 w-full rounded-md border bg-background px-2.5 py-1.5 text-sm outline-none focus:border-primary";
1378
+ var field = "mt-1 px-2.5";
1379
+ var DEFAULT_REASON = "__default__";
1358
1380
  var STOCK_INTRO = {
1359
1381
  role: "operations",
1360
1382
  persona: "Estoquista",
@@ -1589,7 +1611,10 @@ function ProductPositionsTab({ item, getProvider }) {
1589
1611
  ] }),
1590
1612
  variants.length > 1 && /* @__PURE__ */ jsxs("label", { className: "block max-w-xs", children: [
1591
1613
  /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Variante" }),
1592
- /* @__PURE__ */ jsx("select", { value: variantId, onChange: (e) => setVariantId(e.target.value), className: field, children: variants.map((v) => /* @__PURE__ */ jsx("option", { value: v.id, children: Object.values(v.options ?? {}).join(" \xB7 ") || v.sku || v.id.slice(0, 8) }, v.id)) })
1614
+ /* @__PURE__ */ jsxs(Select, { value: variantId, onValueChange: setVariantId, children: [
1615
+ /* @__PURE__ */ jsx(SelectTrigger, { className: field, children: /* @__PURE__ */ jsx(SelectValue, {}) }),
1616
+ /* @__PURE__ */ jsx(SelectContent, { children: variants.map((v) => /* @__PURE__ */ jsx(SelectItem, { value: v.id, children: Object.values(v.options ?? {}).join(" \xB7 ") || v.sku || v.id.slice(0, 8) }, v.id)) })
1617
+ ] })
1593
1618
  ] }),
1594
1619
  /* @__PURE__ */ jsx(Modal, { open: type !== null, onOpenChange: (o) => {
1595
1620
  if (!o) close();
@@ -1600,8 +1625,10 @@ function ProductPositionsTab({ item, getProvider }) {
1600
1625
  ] }),
1601
1626
  /* @__PURE__ */ jsxs("div", { className: "p-1", children: [
1602
1627
  /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1", children: MOVEMENT_TYPES.map((t) => /* @__PURE__ */ jsx(
1603
- "button",
1628
+ Button,
1604
1629
  {
1630
+ variant: "bare",
1631
+ size: "bare",
1605
1632
  type: "button",
1606
1633
  onClick: () => setType(t.value),
1607
1634
  className: `fz-tap rounded-button px-3 py-1.5 text-xs font-medium transition-colors ${type === t.value ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:bg-muted hover:text-foreground"}`,
@@ -1613,7 +1640,7 @@ function ProductPositionsTab({ item, getProvider }) {
1613
1640
  /* @__PURE__ */ jsxs("label", { className: "block", children: [
1614
1641
  /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Quantidade" }),
1615
1642
  /* @__PURE__ */ jsx(
1616
- "input",
1643
+ Input,
1617
1644
  {
1618
1645
  ref: quantityRef,
1619
1646
  type: "number",
@@ -1647,15 +1674,18 @@ function ProductPositionsTab({ item, getProvider }) {
1647
1674
  ] }),
1648
1675
  /* @__PURE__ */ jsxs("label", { className: "block", children: [
1649
1676
  /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Motivo" }),
1650
- /* @__PURE__ */ jsxs("select", { value: reasonCode, onChange: (e) => setReasonCode(e.target.value), className: field, children: [
1651
- /* @__PURE__ */ jsx("option", { value: "", children: "Padr\xE3o" }),
1652
- reasons.map((r) => /* @__PURE__ */ jsx("option", { value: r.key, children: r.label }, r.key))
1677
+ /* @__PURE__ */ jsxs(Select, { value: reasonCode || DEFAULT_REASON, onValueChange: (v) => setReasonCode(v === DEFAULT_REASON ? "" : v), children: [
1678
+ /* @__PURE__ */ jsx(SelectTrigger, { className: field, children: /* @__PURE__ */ jsx(SelectValue, {}) }),
1679
+ /* @__PURE__ */ jsxs(SelectContent, { children: [
1680
+ /* @__PURE__ */ jsx(SelectItem, { value: DEFAULT_REASON, children: "Padr\xE3o" }),
1681
+ reasons.map((r) => /* @__PURE__ */ jsx(SelectItem, { value: r.key, children: r.label }, r.key))
1682
+ ] })
1653
1683
  ] })
1654
1684
  ] }),
1655
1685
  /* @__PURE__ */ jsxs("label", { className: "block", children: [
1656
1686
  /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: type === "entrada" ? "Chegou em" : "Quando" }),
1657
1687
  /* @__PURE__ */ jsx(
1658
- "input",
1688
+ Input,
1659
1689
  {
1660
1690
  type: "date",
1661
1691
  value: occurredOn,
@@ -1669,7 +1699,7 @@ function ProductPositionsTab({ item, getProvider }) {
1669
1699
  noteOpen ? /* @__PURE__ */ jsxs("label", { className: "mt-3 block", children: [
1670
1700
  /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Observa\xE7\xE3o" }),
1671
1701
  /* @__PURE__ */ jsx(
1672
- "input",
1702
+ Input,
1673
1703
  {
1674
1704
  autoFocus: true,
1675
1705
  value: note,
@@ -1679,8 +1709,10 @@ function ProductPositionsTab({ item, getProvider }) {
1679
1709
  }
1680
1710
  )
1681
1711
  ] }) : /* @__PURE__ */ jsx(
1682
- "button",
1712
+ Button,
1683
1713
  {
1714
+ variant: "bare",
1715
+ size: "bare",
1684
1716
  type: "button",
1685
1717
  onClick: () => setNoteOpen(true),
1686
1718
  className: "mt-2 text-xs font-medium text-muted-foreground underline-offset-2 hover:text-foreground hover:underline",
@@ -1760,11 +1792,13 @@ function PackageSelect({ value, onChange, getProvider }) {
1760
1792
  const label = selected ? `${selected.name} \u2014 ${packageMeasureLabel(selected)}` : storeDefault ? `Padr\xE3o da loja \u2022 ${storeDefault.name} \u2014 ${packageMeasureLabel(storeDefault)}` : "Padr\xE3o da loja";
1761
1793
  return /* @__PURE__ */ jsxs("div", { className: "relative", ref, children: [
1762
1794
  /* @__PURE__ */ jsxs(
1763
- "button",
1795
+ Button,
1764
1796
  {
1797
+ variant: "bare",
1798
+ size: "bare",
1765
1799
  type: "button",
1766
1800
  onClick: () => setOpen((v) => !v),
1767
- className: "flex h-9 w-full items-center gap-2 rounded-input border border-input bg-background px-3 text-left text-sm shadow-sm",
1801
+ className: "font-normal justify-start whitespace-normal flex h-9 w-full items-center gap-2 rounded-input border border-input bg-background px-3 text-left text-sm shadow-sm",
1768
1802
  children: [
1769
1803
  /* @__PURE__ */ jsx(Box, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
1770
1804
  /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: label }),
@@ -1774,14 +1808,16 @@ function PackageSelect({ value, onChange, getProvider }) {
1774
1808
  ),
1775
1809
  open && /* @__PURE__ */ jsxs("div", { className: "absolute z-30 mt-1 w-full overflow-hidden rounded-lg border bg-popover shadow-lg", children: [
1776
1810
  /* @__PURE__ */ jsxs(
1777
- "button",
1811
+ Button,
1778
1812
  {
1813
+ variant: "bare",
1814
+ size: "bare",
1779
1815
  type: "button",
1780
1816
  onClick: () => {
1781
1817
  setOpen(false);
1782
1818
  setCreating(true);
1783
1819
  },
1784
- className: "flex w-full items-center gap-2 px-3 py-2 text-left text-sm text-primary hover:bg-muted",
1820
+ className: "font-normal justify-start rounded-none whitespace-normal flex w-full items-center gap-2 px-3 py-2 text-left text-sm text-primary hover:bg-muted",
1785
1821
  children: [
1786
1822
  /* @__PURE__ */ jsx(Plus, { className: "h-4 w-4" }),
1787
1823
  " Adicionar embalagem"
@@ -1816,14 +1852,16 @@ function PackageSelect({ value, onChange, getProvider }) {
1816
1852
  ))
1817
1853
  ] }),
1818
1854
  /* @__PURE__ */ jsx(
1819
- "button",
1855
+ Button,
1820
1856
  {
1857
+ variant: "bare",
1858
+ size: "bare",
1821
1859
  type: "button",
1822
1860
  onClick: () => {
1823
1861
  setOpen(false);
1824
1862
  adminNavigateTo(PACKAGES_ROUTE);
1825
1863
  },
1826
- className: "w-full border-t px-3 py-2 text-left text-xs text-muted-foreground hover:bg-muted",
1864
+ className: "font-normal justify-start rounded-none whitespace-normal w-full border-t px-3 py-2 text-left text-xs text-muted-foreground hover:bg-muted",
1827
1865
  children: "Gerenciar embalagens"
1828
1866
  }
1829
1867
  )
@@ -1876,11 +1914,13 @@ function NewPackageModal({ onClose, onCreated }) {
1876
1914
  }
1877
1915
  function Option({ label, hint, active, onClick }) {
1878
1916
  return /* @__PURE__ */ jsxs(
1879
- "button",
1917
+ Button,
1880
1918
  {
1919
+ variant: "bare",
1920
+ size: "bare",
1881
1921
  type: "button",
1882
1922
  onClick,
1883
- className: `flex w-full flex-col px-3 py-2 text-left hover:bg-muted ${active ? "bg-muted/60" : ""}`,
1923
+ className: `font-normal justify-start items-stretch gap-0 rounded-none whitespace-normal flex w-full flex-col px-3 py-2 text-left hover:bg-muted ${active ? "bg-muted/60" : ""}`,
1884
1924
  children: [
1885
1925
  /* @__PURE__ */ jsx("span", { className: "text-sm", children: label }),
1886
1926
  /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: hint })
@@ -1888,6 +1928,7 @@ function Option({ label, hint, active, onClick }) {
1888
1928
  }
1889
1929
  );
1890
1930
  }
1931
+ var GENERAL = "__general__";
1891
1932
  function ShippingProfileSelect({ value, onChange, getProvider }) {
1892
1933
  const shop = React13__default.useMemo(() => getProvider?.() ?? getShopProvider(), [getProvider]);
1893
1934
  const [rows, setRows] = React13__default.useState(null);
@@ -1909,30 +1950,26 @@ function ShippingProfileSelect({ value, onChange, getProvider }) {
1909
1950
  const custom = (rows ?? []).filter((row) => !row.isDefault);
1910
1951
  const chosen = custom.find((row) => row.id === value) ?? null;
1911
1952
  return /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
1912
- /* @__PURE__ */ jsxs(
1913
- "select",
1914
- {
1915
- value: value ?? "",
1916
- onChange: (event) => onChange(event.target.value || null),
1917
- disabled: rows == null,
1918
- className: "flex h-9 w-full rounded-input border border-input bg-background px-3 py-1.5 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
1919
- children: [
1920
- /* @__PURE__ */ jsx("option", { value: "", children: "Geral \u2014 as zonas normais da loja" }),
1921
- custom.map((row) => /* @__PURE__ */ jsxs("option", { value: row.id, children: [
1922
- row.name,
1923
- row.carrierQuotes === false ? " \u2014 s\xF3 entrega pr\xF3pria" : ""
1924
- ] }, row.id))
1925
- ]
1926
- }
1927
- ),
1953
+ /* @__PURE__ */ jsxs(Select, { value: value ?? GENERAL, onValueChange: (v) => onChange(v === GENERAL ? null : v), disabled: rows == null, children: [
1954
+ /* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, {}) }),
1955
+ /* @__PURE__ */ jsxs(SelectContent, { children: [
1956
+ /* @__PURE__ */ jsx(SelectItem, { value: GENERAL, children: "Geral \u2014 as zonas normais da loja" }),
1957
+ custom.map((row) => /* @__PURE__ */ jsxs(SelectItem, { value: row.id, children: [
1958
+ row.name,
1959
+ row.carrierQuotes === false ? " \u2014 s\xF3 entrega pr\xF3pria" : ""
1960
+ ] }, row.id))
1961
+ ] })
1962
+ ] }),
1928
1963
  /* @__PURE__ */ jsxs("p", { className: "flex items-center gap-1.5 text-xs text-muted-foreground", children: [
1929
1964
  chosen?.carrierQuotes === false ? "Este produto n\xE3o \xE9 cotado por transportadora: sai s\xF3 pelas zonas do perfil." : custom.length === 0 ? "Nenhum perfil al\xE9m do geral." : "Perfil de entrega deste produto.",
1930
1965
  /* @__PURE__ */ jsxs(
1931
- "button",
1966
+ Button,
1932
1967
  {
1968
+ variant: "bare",
1969
+ size: "bare",
1933
1970
  type: "button",
1934
1971
  onClick: () => adminNavigateTo(shippingRegistryPath(SHIPPING_PROFILES_REGISTRY)),
1935
- className: "inline-flex items-center gap-1 text-primary hover:underline",
1972
+ className: "inline-flex items-center gap-1 text-xs font-normal text-primary hover:underline",
1936
1973
  children: [
1937
1974
  custom.length === 0 ? "Criar um perfil" : "Gerenciar perfis",
1938
1975
  /* @__PURE__ */ jsx(ExternalLink, { className: "h-3 w-3" })
@@ -1956,7 +1993,7 @@ var STATUS_LABEL = {
1956
1993
  function money(value, currency = "BRL") {
1957
1994
  const n = Number(value);
1958
1995
  if (!Number.isFinite(n)) return "\u2014";
1959
- return new Intl.NumberFormat("pt-BR", { style: "currency", currency }).format(n);
1996
+ return formatCurrency(n, currency);
1960
1997
  }
1961
1998
  function slugify(value) {
1962
1999
  return value.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
@@ -2397,7 +2434,7 @@ function buildShopDiscountEntity() {
2397
2434
  hint: "Percentual: 10 = 10%. Valor fixo: 10 = R$ 10,00. Frete gr\xE1tis ignora este campo.",
2398
2435
  showInTable: true,
2399
2436
  sortable: true,
2400
- renderCell: (_v, row) => /* @__PURE__ */ jsx("span", { className: "block text-right font-medium", children: row.type === "percentage" ? `${row.value}%` : row.type === "free_shipping" ? "\u2014" : new Intl.NumberFormat("pt-BR", { style: "currency", currency: "BRL" }).format(Number(row.value) || 0) })
2437
+ renderCell: (_v, row) => /* @__PURE__ */ jsx("span", { className: "block text-right font-medium", children: row.type === "percentage" ? `${row.value}%` : row.type === "free_shipping" ? "\u2014" : formatCurrency(Number(row.value) || 0, "BRL") })
2401
2438
  },
2402
2439
  // — Limites —
2403
2440
  {
@@ -2704,7 +2741,7 @@ var STATUS_LABEL2 = {
2704
2741
  disabled: "Desativado"
2705
2742
  };
2706
2743
  function buildShopGiftCardEntity(currencyCode = "BRL") {
2707
- const money3 = (v) => new Intl.NumberFormat("pt-BR", { style: "currency", currency: currencyCode }).format(Number(v) || 0);
2744
+ const money3 = (v) => formatCurrency(Number(v) || 0, currencyCode);
2708
2745
  const fields = [
2709
2746
  {
2710
2747
  key: "code",
@@ -2894,7 +2931,7 @@ function describeSegment(s, money3) {
2894
2931
  return parts.length ? parts.join(" \xB7 ") : "Todos os clientes";
2895
2932
  }
2896
2933
  function buildShopCustomerSegmentEntity(currencyCode = "BRL") {
2897
- const money3 = (v) => new Intl.NumberFormat("pt-BR", { style: "currency", currency: currencyCode }).format(v);
2934
+ const money3 = (v) => formatCurrency(v, currencyCode);
2898
2935
  const fields = [
2899
2936
  {
2900
2937
  key: "name",
@@ -3477,14 +3514,16 @@ function PaymentProviderRow({ connector, selected, onSelect, onOpen }) {
3477
3514
  const live = connector.state === "connected";
3478
3515
  return /* @__PURE__ */ jsxs("li", { className: `flex items-start gap-1 transition-colors ${selected ? "bg-primary/5" : ""}`, children: [
3479
3516
  /* @__PURE__ */ jsxs(
3480
- "button",
3517
+ Button,
3481
3518
  {
3519
+ variant: "bare",
3520
+ size: "bare",
3482
3521
  type: "button",
3483
3522
  role: "radio",
3484
3523
  "aria-checked": selected,
3485
3524
  disabled: !live,
3486
3525
  onClick: () => onSelect(connector),
3487
- className: `flex min-w-0 flex-1 items-start gap-3 p-4 text-left ${live ? "hover:bg-muted/40" : "cursor-default opacity-70"}`,
3526
+ className: `font-normal justify-start whitespace-normal flex min-w-0 flex-1 items-start gap-3 p-4 text-left ${live ? "hover:bg-muted/40" : "cursor-default disabled:opacity-70"}`,
3488
3527
  children: [
3489
3528
  /* @__PURE__ */ jsx(
3490
3529
  "span",
@@ -3506,11 +3545,13 @@ function PaymentProviderRow({ connector, selected, onSelect, onOpen }) {
3506
3545
  }
3507
3546
  ),
3508
3547
  /* @__PURE__ */ jsx(
3509
- "button",
3548
+ Button,
3510
3549
  {
3550
+ variant: "bare",
3551
+ size: "bare",
3511
3552
  type: "button",
3512
3553
  onClick: () => onOpen(connector),
3513
- className: "shrink-0 self-center whitespace-nowrap px-4 text-xs text-muted-foreground underline decoration-dotted underline-offset-4 hover:text-foreground",
3554
+ className: "font-normal shrink-0 self-center whitespace-nowrap px-4 text-xs text-muted-foreground underline decoration-dotted underline-offset-4 hover:text-foreground",
3514
3555
  children: live ? "Configurar conex\xE3o" : "Conectar"
3515
3556
  }
3516
3557
  )
@@ -3518,13 +3559,15 @@ function PaymentProviderRow({ connector, selected, onSelect, onOpen }) {
3518
3559
  }
3519
3560
  function ManualChargeRow({ selected, onSelect }) {
3520
3561
  return /* @__PURE__ */ jsx("li", { className: selected ? "bg-primary/5" : "", children: /* @__PURE__ */ jsxs(
3521
- "button",
3562
+ Button,
3522
3563
  {
3564
+ variant: "bare",
3565
+ size: "bare",
3523
3566
  type: "button",
3524
3567
  role: "radio",
3525
3568
  "aria-checked": selected,
3526
3569
  onClick: onSelect,
3527
- className: "flex w-full items-start gap-3 p-4 text-left hover:bg-muted/40",
3570
+ className: "font-normal justify-start rounded-none whitespace-normal flex w-full items-start gap-3 p-4 text-left hover:bg-muted/40",
3528
3571
  children: [
3529
3572
  /* @__PURE__ */ jsx(
3530
3573
  "span",
@@ -3833,11 +3876,13 @@ function HandlingSettings({ settings, provider }) {
3833
3876
  /* @__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." })
3834
3877
  ] }),
3835
3878
  /* @__PURE__ */ jsx("div", { className: "rounded-card border bg-card px-5 shadow-sm", children: /* @__PURE__ */ jsxs(
3836
- "button",
3879
+ Button,
3837
3880
  {
3881
+ variant: "bare",
3882
+ size: "bare",
3838
3883
  type: "button",
3839
3884
  onClick: () => adminNavigateTo(shippingRegistryPath(SHIPPING_PROFILES_REGISTRY)),
3840
- className: "flex w-full items-center gap-3 py-3.5 text-left",
3885
+ className: "font-normal justify-start whitespace-normal flex w-full items-center gap-3 py-3.5 text-left",
3841
3886
  children: [
3842
3887
  /* @__PURE__ */ jsx(Layers, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
3843
3888
  /* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1", children: [
@@ -3887,14 +3932,16 @@ function ChoiceCards({
3887
3932
  const chosen = value === choice.value;
3888
3933
  const Icon = choice.Icon;
3889
3934
  return /* @__PURE__ */ jsxs(
3890
- "button",
3935
+ Button,
3891
3936
  {
3937
+ variant: "bare",
3938
+ size: "bare",
3892
3939
  type: "button",
3893
3940
  role: "radio",
3894
3941
  "aria-checked": chosen,
3895
3942
  disabled,
3896
3943
  onClick: () => onChange(choice.value),
3897
- className: `flex w-full items-start gap-3 rounded-lg border p-3 text-left transition-colors ${chosen ? "border-primary bg-primary/5" : "border-border hover:bg-muted/40"} ${disabled ? "opacity-60" : ""}`,
3944
+ className: `font-normal justify-start whitespace-normal flex w-full items-start gap-3 rounded-lg border p-3 text-left transition-colors ${chosen ? "border-primary bg-primary/5" : "border-border hover:bg-muted/40"} disabled:opacity-60`,
3898
3945
  children: [
3899
3946
  /* @__PURE__ */ jsx(
3900
3947
  "span",
@@ -4536,12 +4583,12 @@ function AreaSearch({ provider, outcome, placeholder, onlyCityCodes, emptyHint }
4536
4583
  /* @__PURE__ */ jsxs("div", { className: "relative", children: [
4537
4584
  /* @__PURE__ */ jsx(Search, { className: "pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" }),
4538
4585
  /* @__PURE__ */ jsx(
4539
- "input",
4586
+ Input,
4540
4587
  {
4541
4588
  value: query,
4542
4589
  onChange: (e) => setQuery(e.target.value),
4543
4590
  placeholder,
4544
- className: "w-full rounded-lg border border-border bg-background py-2 pl-9 pr-9 text-sm"
4591
+ className: "h-auto rounded-lg border-border bg-background py-2 pl-9 pr-9"
4545
4592
  }
4546
4593
  ),
4547
4594
  loading && /* @__PURE__ */ jsx(Loader2, { className: "absolute right-3 top-1/2 h-4 w-4 -translate-y-1/2 animate-spin text-muted-foreground" })
@@ -4556,12 +4603,14 @@ function AreaSearch({ provider, outcome, placeholder, onlyCityCodes, emptyHint }
4556
4603
  districtKey: area.districtKey ?? null
4557
4604
  });
4558
4605
  return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
4559
- "button",
4606
+ Button,
4560
4607
  {
4608
+ variant: "bare",
4609
+ size: "bare",
4561
4610
  type: "button",
4562
4611
  onClick: () => add(area),
4563
4612
  disabled: already,
4564
- className: "flex w-full items-center gap-3 px-3 py-2.5 text-left transition hover:bg-muted/50 disabled:opacity-50",
4613
+ className: "font-normal justify-start rounded-none whitespace-normal flex w-full items-center gap-3 px-3 py-2.5 text-left transition hover:bg-muted/50 disabled:opacity-50",
4565
4614
  children: [
4566
4615
  area.kind === "city" ? /* @__PURE__ */ jsx(Building2, { className: "h-4 w-4 shrink-0 text-muted-foreground" }) : /* @__PURE__ */ jsx(MapPin, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
4567
4616
  /* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1", children: [
@@ -4592,8 +4641,10 @@ function DeliveryAreaPicker({ provider, onAskAssistant }) {
4592
4641
  /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-xs text-muted-foreground", children: 'Digite uma cidade, um bairro ou uma regi\xE3o \u2014 "Rio de Janeiro", "Ipanema", "Zona Sul". Se voc\xEA atende a cidade toda, uma linha s\xF3 resolve: escolha a cidade.' })
4593
4642
  ] }),
4594
4643
  onAskAssistant && /* @__PURE__ */ jsxs(
4595
- "button",
4644
+ Button,
4596
4645
  {
4646
+ variant: "bare",
4647
+ size: "bare",
4597
4648
  type: "button",
4598
4649
  onClick: onAskAssistant,
4599
4650
  className: "inline-flex items-center gap-1.5 rounded-md border border-border px-3 py-1.5 text-xs font-medium hover:bg-muted",
@@ -4658,6 +4709,9 @@ function parseMoney(raw) {
4658
4709
  return Number.isFinite(n) && n >= 0 ? Math.round(n * 100) / 100 : null;
4659
4710
  }
4660
4711
  var money2 = (v) => v == null ? "" : String(v).replace(".", ",");
4712
+ var BULK_INPUT = "h-auto rounded-md border-border bg-background px-2 py-1 text-xs shadow-none";
4713
+ var FIELD_FRAME = "inline-flex items-center rounded-md border border-border bg-background focus-within:ring-1 focus-within:ring-ring";
4714
+ var FRAMED_INPUT = "h-auto rounded-none border-0 bg-transparent py-1.5 text-xs shadow-none focus-visible:ring-0 focus-visible:ring-offset-0";
4661
4715
  function ruleArea(rule) {
4662
4716
  if (rule.matchKind === "postal_range") {
4663
4717
  const fmt = (c) => c ? `${c.slice(0, 5)}-${c.slice(5)}` : "?";
@@ -4675,6 +4729,127 @@ function DeliveryRulesDraft({ provider, onSaved }) {
4675
4729
  const refusing = draft2.rules.filter((r) => r.outcome === "refuse").length;
4676
4730
  const reviewing = draft2.rules.filter((r) => r.outcome === "review").length;
4677
4731
  const delivering = draft2.rules.length - refusing - reviewing;
4732
+ const columns = [
4733
+ {
4734
+ id: "region",
4735
+ header: "Regi\xE3o",
4736
+ meta: { className: "px-5 py-2.5" },
4737
+ cell: ({ row: { original: rule } }) => /* @__PURE__ */ jsxs(Fragment, { children: [
4738
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: rule.label }),
4739
+ /* @__PURE__ */ jsx("span", { className: "ml-2 text-xs text-muted-foreground", children: ruleArea(rule) }),
4740
+ rule.source && /* @__PURE__ */ jsxs("p", { className: "text-xs italic text-muted-foreground", children: [
4741
+ "\u201C",
4742
+ rule.source,
4743
+ "\u201D"
4744
+ ] })
4745
+ ] })
4746
+ },
4747
+ {
4748
+ id: "outcome",
4749
+ header: "O que fa\xE7o",
4750
+ meta: { className: "px-2 py-2.5" },
4751
+ cell: ({ row: { original: rule } }) => /* @__PURE__ */ jsxs(
4752
+ Select,
4753
+ {
4754
+ value: rule.outcome,
4755
+ onValueChange: (v) => updateDeliveryDraftRule(rule.id, { outcome: v }),
4756
+ children: [
4757
+ /* @__PURE__ */ jsx(SelectTrigger, { className: `h-auto w-auto gap-1.5 rounded-md border-border bg-background px-2 py-1.5 text-xs shadow-none ${OUTCOME_TONE[rule.outcome]}`, children: /* @__PURE__ */ jsx(SelectValue, {}) }),
4758
+ /* @__PURE__ */ jsx(SelectContent, { children: Object.keys(OUTCOME_LABEL).map((value) => /* @__PURE__ */ jsx(SelectItem, { value, children: OUTCOME_LABEL[value] }, value)) })
4759
+ ]
4760
+ }
4761
+ )
4762
+ },
4763
+ // Recusa não cobra: mostrar campo de preço numa linha que nunca o lê
4764
+ // convida a lojista a preencher e a achar que cobrou.
4765
+ {
4766
+ id: "rate",
4767
+ header: "Frete",
4768
+ meta: { className: "px-2 py-2.5" },
4769
+ cell: ({ row: { original: rule } }) => rule.outcome === "refuse" ? /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: "n\xE3o se cobra" }) : /* @__PURE__ */ jsxs("span", { className: FIELD_FRAME, children: [
4770
+ /* @__PURE__ */ jsx("span", { className: "pl-2 text-xs text-muted-foreground", children: "R$" }),
4771
+ /* @__PURE__ */ jsx("div", { className: "w-16", children: /* @__PURE__ */ jsx(
4772
+ Input,
4773
+ {
4774
+ value: money2(rule.rate),
4775
+ placeholder: "0,00",
4776
+ "aria-label": `Frete para ${rule.label}`,
4777
+ onChange: (e) => updateDeliveryDraftRule(rule.id, { rate: parseMoney(e.target.value) }),
4778
+ className: `${FRAMED_INPUT} px-1.5`
4779
+ }
4780
+ ) })
4781
+ ] })
4782
+ },
4783
+ {
4784
+ id: "freeAbove",
4785
+ header: "Gr\xE1tis acima de",
4786
+ meta: { className: "px-2 py-2.5" },
4787
+ cell: ({ row: { original: rule } }) => rule.outcome === "refuse" ? null : /* @__PURE__ */ jsxs("span", { className: FIELD_FRAME, children: [
4788
+ /* @__PURE__ */ jsx("span", { className: "pl-2 text-xs text-muted-foreground", children: "R$" }),
4789
+ /* @__PURE__ */ jsx("div", { className: "w-20", children: /* @__PURE__ */ jsx(
4790
+ Input,
4791
+ {
4792
+ value: money2(rule.freeAbove),
4793
+ placeholder: "nunca",
4794
+ "aria-label": `Frete gr\xE1tis acima de, em ${rule.label}`,
4795
+ onChange: (e) => updateDeliveryDraftRule(rule.id, { freeAbove: parseMoney(e.target.value) }),
4796
+ className: `${FRAMED_INPUT} px-1.5`
4797
+ }
4798
+ ) })
4799
+ ] })
4800
+ },
4801
+ {
4802
+ id: "eta",
4803
+ header: "Prazo (dias)",
4804
+ meta: { className: "px-2 py-2.5" },
4805
+ cell: ({ row: { original: rule } }) => rule.outcome === "refuse" ? null : /* @__PURE__ */ jsxs("span", { className: FIELD_FRAME, children: [
4806
+ /* @__PURE__ */ jsx("div", { className: "w-10", children: /* @__PURE__ */ jsx(
4807
+ Input,
4808
+ {
4809
+ value: rule.etaMinDays ?? "",
4810
+ placeholder: "0",
4811
+ inputMode: "numeric",
4812
+ "aria-label": `Prazo m\xEDnimo em ${rule.label}`,
4813
+ onChange: (e) => updateDeliveryDraftRule(rule.id, {
4814
+ etaMinDays: e.target.value ? Number(e.target.value) : null
4815
+ }),
4816
+ className: `${FRAMED_INPUT} pl-2 pr-0 text-center`
4817
+ }
4818
+ ) }),
4819
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: "a" }),
4820
+ /* @__PURE__ */ jsx("div", { className: "w-10", children: /* @__PURE__ */ jsx(
4821
+ Input,
4822
+ {
4823
+ value: rule.etaMaxDays ?? "",
4824
+ placeholder: "2",
4825
+ inputMode: "numeric",
4826
+ "aria-label": `Prazo m\xE1ximo em ${rule.label}`,
4827
+ onChange: (e) => updateDeliveryDraftRule(rule.id, {
4828
+ etaMaxDays: e.target.value ? Number(e.target.value) : null
4829
+ }),
4830
+ className: `${FRAMED_INPUT} pl-0 pr-2 text-center`
4831
+ }
4832
+ ) })
4833
+ ] })
4834
+ },
4835
+ {
4836
+ id: "remove",
4837
+ header: "",
4838
+ meta: { className: "px-5 py-2.5 text-right" },
4839
+ cell: ({ row: { original: rule } }) => /* @__PURE__ */ jsx(
4840
+ Button,
4841
+ {
4842
+ variant: "bare",
4843
+ size: "bare",
4844
+ type: "button",
4845
+ onClick: () => removeDeliveryDraftRule(rule.id),
4846
+ "aria-label": `Remover ${rule.label}`,
4847
+ className: "rounded-md p-1 text-muted-foreground hover:bg-muted hover:text-destructive",
4848
+ children: /* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5" })
4849
+ }
4850
+ )
4851
+ }
4852
+ ];
4678
4853
  const save = async () => {
4679
4854
  setSaving(true);
4680
4855
  setError(null);
@@ -4710,18 +4885,22 @@ function DeliveryRulesDraft({ provider, onSaved }) {
4710
4885
  ] })
4711
4886
  ] }),
4712
4887
  /* @__PURE__ */ jsx(
4713
- "button",
4888
+ Button,
4714
4889
  {
4890
+ variant: "bare",
4891
+ size: "bare",
4715
4892
  type: "button",
4716
4893
  onClick: clearDeliveryDraft,
4717
4894
  disabled: saving,
4718
- className: "rounded-md px-3 py-2 text-xs text-muted-foreground hover:bg-muted",
4895
+ className: "font-normal rounded-md px-3 py-2 text-xs text-muted-foreground hover:bg-muted",
4719
4896
  children: "Descartar"
4720
4897
  }
4721
4898
  ),
4722
4899
  /* @__PURE__ */ jsxs(
4723
- "button",
4900
+ Button,
4724
4901
  {
4902
+ variant: "bare",
4903
+ size: "bare",
4725
4904
  type: "button",
4726
4905
  onClick: save,
4727
4906
  disabled: saving || draft2.rules.length === 0,
@@ -4741,33 +4920,35 @@ function DeliveryRulesDraft({ provider, onSaved }) {
4741
4920
  /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: "Mesmo pre\xE7o em todas:" }),
4742
4921
  /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1", children: [
4743
4922
  /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: "R$" }),
4744
- /* @__PURE__ */ jsx(
4745
- "input",
4923
+ /* @__PURE__ */ jsx("div", { className: "w-20", children: /* @__PURE__ */ jsx(
4924
+ Input,
4746
4925
  {
4747
4926
  value: bulkRate,
4748
4927
  onChange: (e) => setBulkRate(e.target.value),
4749
4928
  placeholder: "15,00",
4750
4929
  "aria-label": "Frete para todas as regi\xF5es",
4751
- className: "w-20 rounded-md border border-border bg-background px-2 py-1 text-xs"
4930
+ className: BULK_INPUT
4752
4931
  }
4753
- )
4932
+ ) })
4754
4933
  ] }),
4755
4934
  /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1", children: [
4756
4935
  /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: "gr\xE1tis acima de R$" }),
4757
- /* @__PURE__ */ jsx(
4758
- "input",
4936
+ /* @__PURE__ */ jsx("div", { className: "w-24", children: /* @__PURE__ */ jsx(
4937
+ Input,
4759
4938
  {
4760
4939
  value: bulkFree,
4761
4940
  onChange: (e) => setBulkFree(e.target.value),
4762
4941
  placeholder: "opcional",
4763
4942
  "aria-label": "Frete gr\xE1tis acima de, para todas as regi\xF5es",
4764
- className: "w-24 rounded-md border border-border bg-background px-2 py-1 text-xs"
4943
+ className: BULK_INPUT
4765
4944
  }
4766
- )
4945
+ ) })
4767
4946
  ] }),
4768
4947
  /* @__PURE__ */ jsx(
4769
- "button",
4948
+ Button,
4770
4949
  {
4950
+ variant: "bare",
4951
+ size: "bare",
4771
4952
  type: "button",
4772
4953
  onClick: () => {
4773
4954
  setAllDeliveryDraftRates({
@@ -4783,103 +4964,7 @@ function DeliveryRulesDraft({ provider, onSaved }) {
4783
4964
  }
4784
4965
  )
4785
4966
  ] }),
4786
- /* @__PURE__ */ jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-sm", children: [
4787
- /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "text-left text-xs text-muted-foreground", children: [
4788
- /* @__PURE__ */ jsx("th", { className: "px-5 py-2.5 font-medium", children: "Regi\xE3o" }),
4789
- /* @__PURE__ */ jsx("th", { className: "px-2 py-2.5 font-medium", children: "O que fa\xE7o" }),
4790
- /* @__PURE__ */ jsx("th", { className: "px-2 py-2.5 font-medium", children: "Frete" }),
4791
- /* @__PURE__ */ jsx("th", { className: "px-2 py-2.5 font-medium", children: "Gr\xE1tis acima de" }),
4792
- /* @__PURE__ */ jsx("th", { className: "px-2 py-2.5 font-medium", children: "Prazo (dias)" }),
4793
- /* @__PURE__ */ jsx("th", { className: "px-2 py-2" })
4794
- ] }) }),
4795
- /* @__PURE__ */ jsx("tbody", { children: draft2.rules.map((rule) => /* @__PURE__ */ jsxs("tr", { className: "border-t border-primary/10", children: [
4796
- /* @__PURE__ */ jsxs("td", { className: "px-5 py-2.5", children: [
4797
- /* @__PURE__ */ jsx("span", { className: "font-medium", children: rule.label }),
4798
- /* @__PURE__ */ jsx("span", { className: "ml-2 text-xs text-muted-foreground", children: ruleArea(rule) }),
4799
- rule.source && /* @__PURE__ */ jsxs("p", { className: "text-xs italic text-muted-foreground", children: [
4800
- "\u201C",
4801
- rule.source,
4802
- "\u201D"
4803
- ] })
4804
- ] }),
4805
- /* @__PURE__ */ jsx("td", { className: "px-2 py-2.5", children: /* @__PURE__ */ jsx(
4806
- "select",
4807
- {
4808
- value: rule.outcome,
4809
- onChange: (e) => updateDeliveryDraftRule(rule.id, { outcome: e.target.value }),
4810
- className: `rounded-md border border-border bg-background px-2 py-1.5 text-xs ${OUTCOME_TONE[rule.outcome]}`,
4811
- children: Object.keys(OUTCOME_LABEL).map((value) => /* @__PURE__ */ jsx("option", { value, children: OUTCOME_LABEL[value] }, value))
4812
- }
4813
- ) }),
4814
- rule.outcome === "refuse" ? /* @__PURE__ */ jsx("td", { className: "px-2 py-2.5 text-xs text-muted-foreground", colSpan: 3, children: "n\xE3o se cobra" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
4815
- /* @__PURE__ */ jsx("td", { className: "px-2 py-2.5", children: /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center rounded-md border border-border bg-background focus-within:ring-1 focus-within:ring-ring", children: [
4816
- /* @__PURE__ */ jsx("span", { className: "pl-2 text-xs text-muted-foreground", children: "R$" }),
4817
- /* @__PURE__ */ jsx(
4818
- "input",
4819
- {
4820
- value: money2(rule.rate),
4821
- placeholder: "0,00",
4822
- "aria-label": `Frete para ${rule.label}`,
4823
- onChange: (e) => updateDeliveryDraftRule(rule.id, { rate: parseMoney(e.target.value) }),
4824
- className: "w-16 bg-transparent px-1.5 py-1.5 text-xs outline-none"
4825
- }
4826
- )
4827
- ] }) }),
4828
- /* @__PURE__ */ jsx("td", { className: "px-2 py-2.5", children: /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center rounded-md border border-border bg-background focus-within:ring-1 focus-within:ring-ring", children: [
4829
- /* @__PURE__ */ jsx("span", { className: "pl-2 text-xs text-muted-foreground", children: "R$" }),
4830
- /* @__PURE__ */ jsx(
4831
- "input",
4832
- {
4833
- value: money2(rule.freeAbove),
4834
- placeholder: "nunca",
4835
- "aria-label": `Frete gr\xE1tis acima de, em ${rule.label}`,
4836
- onChange: (e) => updateDeliveryDraftRule(rule.id, { freeAbove: parseMoney(e.target.value) }),
4837
- className: "w-20 bg-transparent px-1.5 py-1.5 text-xs outline-none"
4838
- }
4839
- )
4840
- ] }) }),
4841
- /* @__PURE__ */ jsx("td", { className: "px-2 py-2.5", children: /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center rounded-md border border-border bg-background focus-within:ring-1 focus-within:ring-ring", children: [
4842
- /* @__PURE__ */ jsx(
4843
- "input",
4844
- {
4845
- value: rule.etaMinDays ?? "",
4846
- placeholder: "0",
4847
- inputMode: "numeric",
4848
- "aria-label": `Prazo m\xEDnimo em ${rule.label}`,
4849
- onChange: (e) => updateDeliveryDraftRule(rule.id, {
4850
- etaMinDays: e.target.value ? Number(e.target.value) : null
4851
- }),
4852
- className: "w-10 bg-transparent py-1.5 pl-2 text-center text-xs outline-none"
4853
- }
4854
- ),
4855
- /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: "a" }),
4856
- /* @__PURE__ */ jsx(
4857
- "input",
4858
- {
4859
- value: rule.etaMaxDays ?? "",
4860
- placeholder: "2",
4861
- inputMode: "numeric",
4862
- "aria-label": `Prazo m\xE1ximo em ${rule.label}`,
4863
- onChange: (e) => updateDeliveryDraftRule(rule.id, {
4864
- etaMaxDays: e.target.value ? Number(e.target.value) : null
4865
- }),
4866
- className: "w-10 bg-transparent py-1.5 pr-2 text-center text-xs outline-none"
4867
- }
4868
- )
4869
- ] }) })
4870
- ] }),
4871
- /* @__PURE__ */ jsx("td", { className: "px-5 py-2.5 text-right", children: /* @__PURE__ */ jsx(
4872
- "button",
4873
- {
4874
- type: "button",
4875
- onClick: () => removeDeliveryDraftRule(rule.id),
4876
- "aria-label": `Remover ${rule.label}`,
4877
- className: "rounded-md p-1 text-muted-foreground hover:bg-muted hover:text-destructive",
4878
- children: /* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5" })
4879
- }
4880
- ) })
4881
- ] }, rule.id)) })
4882
- ] }) }),
4967
+ draft2.rules.length > 0 && /* @__PURE__ */ jsx(DataTable, { variant: "bare", columns, data: draft2.rules }),
4883
4968
  draft2.gaps.length > 0 && /* @__PURE__ */ jsxs("div", { className: "border-t border-primary/20 px-5 py-3.5", children: [
4884
4969
  /* @__PURE__ */ jsx("p", { className: "text-xs font-medium text-muted-foreground", children: "O que ficou de fora \u2014 e por qu\xEA" }),
4885
4970
  /* @__PURE__ */ jsx("ul", { className: "mt-1 space-y-1", children: draft2.gaps.map((gap) => /* @__PURE__ */ jsxs("li", { className: "flex items-start gap-2 text-xs text-muted-foreground", children: [
@@ -5099,13 +5184,15 @@ function ShippingSettings({ provider }) {
5099
5184
  /* @__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." })
5100
5185
  ] }),
5101
5186
  /* @__PURE__ */ jsx("div", { className: "rounded-card border bg-card px-5 shadow-sm", children: /* @__PURE__ */ jsxs(
5102
- "button",
5187
+ Button,
5103
5188
  {
5189
+ variant: "bare",
5190
+ size: "bare",
5104
5191
  type: "button",
5105
5192
  onClick: () => {
5106
5193
  window.location.hash = dispatching.length === 1 && dispatching[0] ? shippingRecordPath(LOCATIONS_REGISTRY, dispatching[0].id) : shippingRegistryPath(LOCATIONS_REGISTRY);
5107
5194
  },
5108
- className: "flex w-full items-center gap-3 py-3.5 text-left",
5195
+ className: "font-normal justify-start whitespace-normal flex w-full items-center gap-3 py-3.5 text-left",
5109
5196
  children: [
5110
5197
  /* @__PURE__ */ jsx(Warehouse, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
5111
5198
  /* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1", children: [
@@ -5137,13 +5224,15 @@ function ShippingSettings({ provider }) {
5137
5224
  /* @__PURE__ */ jsx(DeliveryAreaPicker, { provider }),
5138
5225
  /* @__PURE__ */ jsx(DeliveryRulesDraft, { provider, onSaved: reloadZones }),
5139
5226
  /* @__PURE__ */ jsx("div", { className: "rounded-card border bg-card px-5 shadow-sm", children: /* @__PURE__ */ jsxs(
5140
- "button",
5227
+ Button,
5141
5228
  {
5229
+ variant: "bare",
5230
+ size: "bare",
5142
5231
  type: "button",
5143
5232
  onClick: () => {
5144
5233
  window.location.hash = shippingRegistryPath(SHIPPING_ZONES_REGISTRY);
5145
5234
  },
5146
- className: "flex w-full items-center gap-3 py-3.5 text-left",
5235
+ className: "font-normal justify-start whitespace-normal flex w-full items-center gap-3 py-3.5 text-left",
5147
5236
  children: [
5148
5237
  /* @__PURE__ */ jsx(MapPin, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
5149
5238
  /* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1", children: [
@@ -5266,6 +5355,15 @@ function FulfillmentSettings({ provider }) {
5266
5355
  ] })
5267
5356
  ] });
5268
5357
  }
5358
+ function MarketsSettings({ basePath = "/settings/shop-markets" }) {
5359
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
5360
+ /* @__PURE__ */ jsxs("div", { className: "px-1 pt-4", children: [
5361
+ /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold", children: "Mercados" }),
5362
+ /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-xs text-muted-foreground", children: marketsRegistry.description })
5363
+ ] }),
5364
+ /* @__PURE__ */ jsx(RegistryCrudView, { registry: marketsRegistry, basePath, embedded: true })
5365
+ ] });
5366
+ }
5269
5367
  var MELHOR_ENVIO_CONNECTOR_ID = "melhor-envio";
5270
5368
  var MELHOR_ENVIO_LATENCY_BUDGET_MS = 2500;
5271
5369
  var MELHOR_ENVIO_SETTINGS = [
@@ -5658,8 +5756,10 @@ function CatalogueSync() {
5658
5756
  ] }),
5659
5757
  /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
5660
5758
  /* @__PURE__ */ jsx(
5661
- "button",
5759
+ Button,
5662
5760
  {
5761
+ variant: "bare",
5762
+ size: "bare",
5663
5763
  type: "button",
5664
5764
  onClick: () => {
5665
5765
  void run("push");
@@ -5670,8 +5770,10 @@ function CatalogueSync() {
5670
5770
  }
5671
5771
  ),
5672
5772
  /* @__PURE__ */ jsx(
5673
- "button",
5773
+ Button,
5674
5774
  {
5775
+ variant: "bare",
5776
+ size: "bare",
5675
5777
  type: "button",
5676
5778
  onClick: () => {
5677
5779
  void run("reconcile");
@@ -6759,12 +6861,14 @@ function KindIcon({ kind, className }) {
6759
6861
  function MediaCard({ file, dimensions, onMeasured, onOpen, onDelete }) {
6760
6862
  return /* @__PURE__ */ jsxs(Card, { className: "group relative overflow-hidden p-3", children: [
6761
6863
  /* @__PURE__ */ jsxs(
6762
- "button",
6864
+ Button,
6763
6865
  {
6866
+ variant: "bare",
6867
+ size: "bare",
6764
6868
  type: "button",
6765
6869
  onClick: onOpen,
6766
6870
  "aria-label": `Abrir ${file.name}`,
6767
- className: "relative flex aspect-square w-full items-center justify-center overflow-hidden rounded-md bg-muted",
6871
+ className: "font-normal gap-0 whitespace-normal relative flex aspect-square w-full items-center justify-center overflow-hidden rounded-md bg-muted",
6768
6872
  children: [
6769
6873
  file.kind === "image" ? /* @__PURE__ */ jsx(
6770
6874
  "img",
@@ -6784,8 +6888,10 @@ function MediaCard({ file, dimensions, onMeasured, onOpen, onDelete }) {
6784
6888
  }
6785
6889
  ),
6786
6890
  onDelete && /* @__PURE__ */ jsx(Hint, { label: "Excluir", children: /* @__PURE__ */ jsx(
6787
- "button",
6891
+ Button,
6788
6892
  {
6893
+ variant: "bare",
6894
+ size: "bare",
6789
6895
  type: "button",
6790
6896
  "aria-label": "Excluir",
6791
6897
  onClick: onDelete,
@@ -6827,8 +6933,10 @@ function MediaDetail({
6827
6933
  /* @__PURE__ */ jsx(PageHeader, { title: file.name, parentLabel: "Conte\xFAdo", onBack }),
6828
6934
  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: [
6829
6935
  /* @__PURE__ */ jsx(
6830
- "button",
6936
+ Button,
6831
6937
  {
6938
+ variant: "bare",
6939
+ size: "bare",
6832
6940
  type: "button",
6833
6941
  "aria-label": "Arquivo anterior",
6834
6942
  disabled: position.index === 0,
@@ -6843,8 +6951,10 @@ function MediaDetail({
6843
6951
  position.total
6844
6952
  ] }),
6845
6953
  /* @__PURE__ */ jsx(
6846
- "button",
6954
+ Button,
6847
6955
  {
6956
+ variant: "bare",
6957
+ size: "bare",
6848
6958
  type: "button",
6849
6959
  "aria-label": "Pr\xF3ximo arquivo",
6850
6960
  disabled: position.index === position.total - 1,
@@ -7367,206 +7477,38 @@ var blingConnectorDef = {
7367
7477
  ]
7368
7478
  };
7369
7479
 
7370
- // src/integrations/bling/mapping.ts
7371
- function toNumber(value) {
7372
- if (value === null || value === void 0 || value === "") return null;
7373
- const n = typeof value === "number" ? value : Number(String(value).replace(",", "."));
7374
- return Number.isFinite(n) ? n : null;
7480
+ // src/integrations/neochef/limits.ts
7481
+ var NEOCHEF_CONNECTOR_ID = "neochef";
7482
+ var NEOCHEF_RATE_LIMIT = { perSecond: 5, perDay: 5e4 };
7483
+ var NEOCHEF_PAGE_SIZE = 100;
7484
+ var NEOCHEF_SAMPLE_SIZE = 100;
7485
+ var NEOCHEF_CURSOR_OVERLAP_MS = 6e4;
7486
+ var NEOCHEF_TOKEN_LEAD_MS = 10 * 6e4;
7487
+
7488
+ // src/integrations/neochef/mark.ts
7489
+ var NEOCHEF_MARK = "data:image/png;base64,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";
7490
+ var NEOCHEF_FUNCTION = "neochef-sync";
7491
+ function client3() {
7492
+ const supabase = getSupabaseClientOptional();
7493
+ if (!supabase) throw new Error("Sem conex\xE3o com o banco para falar com o NeoChef.");
7494
+ return supabase;
7375
7495
  }
7376
- function toMirroredProduct(raw) {
7377
- if (!raw || raw.id === null || raw.id === void 0 || raw.id === "") return null;
7378
- return {
7379
- externalId: String(raw.id),
7380
- sku: raw.codigo ? String(raw.codigo) : null,
7381
- name: String(raw.nome ?? "").trim() || `Produto ${raw.id}`,
7382
- price: toNumber(raw.preco),
7383
- // Bling is the source of the stock number. The store mirrors it; it does not
7384
- // decide it. See docs/integrations/bling-integration-brief.md §3.
7385
- inventoryCount: toNumber(raw.estoque?.saldoVirtualTotal),
7386
- status: String(raw.situacao ?? "A").toUpperCase() === "A" ? "active" : "archived",
7387
- imageUrl: raw.imagemURL ? String(raw.imagemURL) : null,
7388
- // Always null in practice: Bling does not return a change date at all (see
7389
- // BlingProduto.dataAlteracao). Kept rather than deleted because the canonical
7390
- // shape is shared with providers that do, and the run stamps its own
7391
- // watermark either way.
7392
- updatedAt: raw.dataAlteracao ? String(raw.dataAlteracao) : null
7393
- };
7496
+ async function invoke3(body) {
7497
+ const tenantId = getShopTenantId();
7498
+ if (!tenantId) throw new Error("Sem loja selecionada para sincronizar com o NeoChef.");
7499
+ const runtimeToken = await connectorRuntimeToken({ tenantId });
7500
+ const { data, error } = await client3().functions.invoke(NEOCHEF_FUNCTION, {
7501
+ body: { ...body, tenantId },
7502
+ headers: { [CONNECTOR_RUNTIME_TOKEN_HEADER]: runtimeToken }
7503
+ });
7504
+ if (error) throw new Error(error.message);
7505
+ return data;
7394
7506
  }
7395
- function firstWindow(now, backfillFrom) {
7396
- const parsed = backfillFrom ? Date.parse(backfillFrom) : NaN;
7397
- const from = Number.isFinite(parsed) ? parsed : now - BLING_MAX_WINDOW_MS;
7398
- return {
7399
- kind: "window",
7400
- from: new Date(from).toISOString(),
7401
- to: new Date(now).toISOString(),
7402
- overlapMs: BLING_WINDOW_OVERLAP_MS
7403
- };
7507
+ function testNeoChef() {
7508
+ return invoke3({ action: "test" });
7404
7509
  }
7405
- function windowFor(options) {
7406
- const now = options.now ?? Date.now();
7407
- const previous = options.cursor;
7408
- if (previous?.kind === "window") return advanceWindow(previous, now);
7409
- return firstWindow(now, options.backfillFrom);
7410
- }
7411
- async function pullProducts(options) {
7412
- const now = options.now ?? Date.now();
7413
- const cursor = windowFor({ cursor: options.cursor, backfillFrom: options.backfillFrom, now });
7414
- const limiter = options.limiter ?? createRateLimiter(BLING_RATE_LIMIT);
7415
- const limite = options.pageSize ?? BLING_PAGE_SIZE;
7416
- const maxRecords = options.maxRecords ?? Number.POSITIVE_INFINITY;
7417
- const slices = sliceWindow(cursor.from, cursor.to, BLING_MAX_WINDOW_MS);
7418
- const products = [];
7419
- const seen = /* @__PURE__ */ new Set();
7420
- let pages = 0;
7421
- let calls = 0;
7422
- let written = 0;
7423
- let error;
7424
- try {
7425
- for (const slice of slices) {
7426
- if (products.length >= maxRecords) break;
7427
- const walked = await paginate({
7428
- first: { pagina: 1, from: slice.from, to: slice.to, limite },
7429
- maxPages: options.maxPages ?? 1e3,
7430
- fetchPage: async (request) => {
7431
- await limiter.take();
7432
- calls += 1;
7433
- const page = await options.fetchPage(request);
7434
- pages += 1;
7435
- const items = page.items ?? [];
7436
- const last = page.short === true || items.length < request.limite;
7437
- const enough = products.length + items.length >= maxRecords;
7438
- return { items, next: last || enough ? null : { ...request, pagina: request.pagina + 1 } };
7439
- }
7440
- });
7441
- for (const raw of walked.items) {
7442
- if (products.length >= maxRecords) break;
7443
- const mapped = toMirroredProduct(raw);
7444
- if (!mapped) continue;
7445
- seen.add(mapped.externalId);
7446
- products.push(mapped);
7447
- if (await options.upsert(mapped)) written += 1;
7448
- }
7449
- }
7450
- } catch (caught) {
7451
- error = String(caught?.message ?? caught);
7452
- }
7453
- const reconciled = reconcileMirror({
7454
- completeness: "additive",
7455
- observed: seen,
7456
- linked: options.linked ?? []
7457
- });
7458
- const advanced = error ? cursor : { ...cursor };
7459
- return {
7460
- status: error ? "error" : products.length >= maxRecords ? "partial" : "success",
7461
- completeness: "additive",
7462
- fetched: products.length,
7463
- written,
7464
- cursor: advanced,
7465
- keptOutOfRange: reconciled.keptOutOfRange,
7466
- products,
7467
- pages,
7468
- calls,
7469
- error,
7470
- stats: {
7471
- pages,
7472
- calls,
7473
- window_from: cursor.from,
7474
- window_to: cursor.to,
7475
- slices: slices.length,
7476
- kept_out_of_range: reconciled.keptOutOfRange.length,
7477
- cursor: serializeCursor(advanced)
7478
- }
7479
- };
7480
- }
7481
- function sampleProducts(options) {
7482
- return pullProducts({
7483
- ...options,
7484
- maxRecords: options.sampleSize ?? BLING_SAMPLE_SIZE,
7485
- maxPages: 1,
7486
- // A sample never reconciles: it saw one page of one window and knows less
7487
- // about absence than any other run in the system.
7488
- linked: []
7489
- });
7490
- }
7491
-
7492
- // src/integrations/bling/inbound.ts
7493
- var BLING_MARKETPLACE_SOURCE = "bling_marketplace";
7494
- function routeCallback(callback) {
7495
- const account = callback.companyId ? String(callback.companyId).trim() : "";
7496
- if (callback.state) return { mode: "tenant", state: callback.state, providerAccountKey: account || null };
7497
- if (account) return { mode: "orphan", providerAccountKey: account, source: BLING_MARKETPLACE_SOURCE };
7498
- return { mode: "reject", reason: "callback carried neither state nor companyId" };
7499
- }
7500
- function orphanConnection(route) {
7501
- return {
7502
- connectorId: BLING_CONNECTOR_ID,
7503
- // The Bling company is the account, so it is also the instance key: two
7504
- // companies are two connections, not two rows fighting over one.
7505
- instanceKey: route.providerAccountKey,
7506
- providerAccountKey: route.providerAccountKey,
7507
- status: "pending",
7508
- settings: { companyId: route.providerAccountKey, source: route.source, stockOwner: "bling" }
7509
- };
7510
- }
7511
- async function acceptWebhook(request, options) {
7512
- let ok = false;
7513
- try {
7514
- ok = await options.verify(request.body, request.signature);
7515
- } catch (error) {
7516
- options.onError?.(error);
7517
- ok = false;
7518
- }
7519
- if (!ok) return { status: 401, queued: false, reason: "signature" };
7520
- const account = request.providerAccountKey ? String(request.providerAccountKey) : "";
7521
- if (!account) return { status: 200, queued: false, reason: "no account in payload" };
7522
- let target = null;
7523
- try {
7524
- target = await options.resolve(account);
7525
- } catch (error) {
7526
- options.onError?.(error);
7527
- }
7528
- if (!target) return { status: 200, queued: false, reason: "unclaimed account" };
7529
- try {
7530
- await options.enqueue({ ...target, body: request.body });
7531
- } catch (error) {
7532
- options.onError?.(error);
7533
- return { status: 500, queued: false, reason: "enqueue failed" };
7534
- }
7535
- return { status: 200, queued: true };
7536
- }
7537
-
7538
- // src/integrations/neochef/limits.ts
7539
- var NEOCHEF_CONNECTOR_ID = "neochef";
7540
- var NEOCHEF_RATE_LIMIT = { perSecond: 5, perDay: 5e4 };
7541
- var NEOCHEF_PAGE_SIZE = 100;
7542
- var NEOCHEF_SAMPLE_SIZE = 100;
7543
- var NEOCHEF_CURSOR_OVERLAP_MS = 6e4;
7544
- var NEOCHEF_TOKEN_LEAD_MS = 10 * 6e4;
7545
-
7546
- // src/integrations/neochef/mark.ts
7547
- var NEOCHEF_MARK = "data:image/png;base64,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";
7548
- var NEOCHEF_FUNCTION = "neochef-sync";
7549
- function client3() {
7550
- const supabase = getSupabaseClientOptional();
7551
- if (!supabase) throw new Error("Sem conex\xE3o com o banco para falar com o NeoChef.");
7552
- return supabase;
7553
- }
7554
- async function invoke3(body) {
7555
- const tenantId = getShopTenantId();
7556
- if (!tenantId) throw new Error("Sem loja selecionada para sincronizar com o NeoChef.");
7557
- const runtimeToken = await connectorRuntimeToken({ tenantId });
7558
- const { data, error } = await client3().functions.invoke(NEOCHEF_FUNCTION, {
7559
- body: { ...body, tenantId },
7560
- headers: { [CONNECTOR_RUNTIME_TOKEN_HEADER]: runtimeToken }
7561
- });
7562
- if (error) throw new Error(error.message);
7563
- return data;
7564
- }
7565
- function testNeoChef() {
7566
- return invoke3({ action: "test" });
7567
- }
7568
- function pullCatalogue2(mode) {
7569
- return invoke3({ action: "pull_products", ...mode ? { mode } : {} });
7510
+ function pullCatalogue2(mode) {
7511
+ return invoke3({ action: "pull_products", ...mode ? { mode } : {} });
7570
7512
  }
7571
7513
  function pushOrders2() {
7572
7514
  return invoke3({ action: "push_orders" });
@@ -7796,49 +7738,6 @@ var neoChefConnectorDef = {
7796
7738
  }
7797
7739
  ]
7798
7740
  };
7799
-
7800
- // src/integrations/neochef/mapping.ts
7801
- function toNumber2(value) {
7802
- if (value === null || value === void 0 || value === "") return null;
7803
- const n = typeof value === "number" ? value : Number(String(value).replace(",", "."));
7804
- return Number.isFinite(n) ? n : null;
7805
- }
7806
- function toMirroredNeoChefProduct(raw) {
7807
- if (!raw || raw.id === null || raw.id === void 0 || raw.id === "") return null;
7808
- const inactive = raw.is_active === false || String(raw.status ?? "active").toLowerCase() === "archived";
7809
- return {
7810
- externalId: String(raw.id),
7811
- sku: raw.sku ? String(raw.sku) : null,
7812
- name: String(raw.name ?? "").trim() || `Produto ${raw.id}`,
7813
- price: toNumber2(raw.price),
7814
- // The kitchen owns this number. The store mirrors it; it does not decide it.
7815
- inventoryCount: toNumber2(raw.stock),
7816
- status: inactive ? "archived" : "active",
7817
- imageUrl: raw.image_url ? String(raw.image_url) : null,
7818
- // Unlike Bling, the far side DOES return its change stamp, so the cursor can
7819
- // advance from the data instead of from the window we asked for.
7820
- updatedAt: raw.updated_at ? String(raw.updated_at) : null
7821
- };
7822
- }
7823
- function toNeoChefOrder(order) {
7824
- return {
7825
- kind: order.pickup === true ? "takeout" : "delivery",
7826
- // The store's own number, so a human can match the two screens. Falls back
7827
- // to the id rather than to empty: an order with no reference is unmatchable.
7828
- reference_number: String(order.referenceNumber ?? order.id),
7829
- // It arrives paid and confirmed — the store already took the money, and a
7830
- // kitchen that has to re-confirm it is a kitchen doing the work twice.
7831
- status: "confirmed",
7832
- total: toNumber2(order.total),
7833
- subtotal: toNumber2(order.subtotal),
7834
- notes: order.notes ? String(order.notes) : null
7835
- };
7836
- }
7837
- function advanceNeoChefCursor(products, overlapMs) {
7838
- const stamps = products.map((product) => product.updatedAt ? Date.parse(product.updatedAt) : NaN).filter((value) => Number.isFinite(value));
7839
- if (stamps.length === 0) return null;
7840
- return new Date(Math.max(...stamps) - overlapMs).toISOString();
7841
- }
7842
7741
  var ORDERS = "plg_shop_rep_orders";
7843
7742
  var ITEMS = "plg_shop_rep_order_items";
7844
7743
  var CUSTOMERS = "plg_shop_rep_customers";
@@ -8664,6 +8563,217 @@ function buildShopAnalyticsCards() {
8664
8563
  }
8665
8564
  ];
8666
8565
  }
8566
+
8567
+ // src/integrations/bling/mapping.ts
8568
+ function toNumber(value) {
8569
+ if (value === null || value === void 0 || value === "") return null;
8570
+ const n = typeof value === "number" ? value : Number(String(value).replace(",", "."));
8571
+ return Number.isFinite(n) ? n : null;
8572
+ }
8573
+ function toMirroredProduct(raw) {
8574
+ if (!raw || raw.id === null || raw.id === void 0 || raw.id === "") return null;
8575
+ return {
8576
+ externalId: String(raw.id),
8577
+ sku: raw.codigo ? String(raw.codigo) : null,
8578
+ name: String(raw.nome ?? "").trim() || `Produto ${raw.id}`,
8579
+ price: toNumber(raw.preco),
8580
+ // Bling is the source of the stock number. The store mirrors it; it does not
8581
+ // decide it. See docs/integrations/bling-integration-brief.md §3.
8582
+ inventoryCount: toNumber(raw.estoque?.saldoVirtualTotal),
8583
+ status: String(raw.situacao ?? "A").toUpperCase() === "A" ? "active" : "archived",
8584
+ imageUrl: raw.imagemURL ? String(raw.imagemURL) : null,
8585
+ // Always null in practice: Bling does not return a change date at all (see
8586
+ // BlingProduto.dataAlteracao). Kept rather than deleted because the canonical
8587
+ // shape is shared with providers that do, and the run stamps its own
8588
+ // watermark either way.
8589
+ updatedAt: raw.dataAlteracao ? String(raw.dataAlteracao) : null
8590
+ };
8591
+ }
8592
+ function firstWindow(now, backfillFrom) {
8593
+ const parsed = backfillFrom ? Date.parse(backfillFrom) : NaN;
8594
+ const from = Number.isFinite(parsed) ? parsed : now - BLING_MAX_WINDOW_MS;
8595
+ return {
8596
+ kind: "window",
8597
+ from: new Date(from).toISOString(),
8598
+ to: new Date(now).toISOString(),
8599
+ overlapMs: BLING_WINDOW_OVERLAP_MS
8600
+ };
8601
+ }
8602
+ function windowFor(options) {
8603
+ const now = options.now ?? Date.now();
8604
+ const previous = options.cursor;
8605
+ if (previous?.kind === "window") return advanceWindow(previous, now);
8606
+ return firstWindow(now, options.backfillFrom);
8607
+ }
8608
+ async function pullProducts(options) {
8609
+ const now = options.now ?? Date.now();
8610
+ const cursor = windowFor({ cursor: options.cursor, backfillFrom: options.backfillFrom, now });
8611
+ const limiter = options.limiter ?? createRateLimiter(BLING_RATE_LIMIT);
8612
+ const limite = options.pageSize ?? BLING_PAGE_SIZE;
8613
+ const maxRecords = options.maxRecords ?? Number.POSITIVE_INFINITY;
8614
+ const slices = sliceWindow(cursor.from, cursor.to, BLING_MAX_WINDOW_MS);
8615
+ const products = [];
8616
+ const seen = /* @__PURE__ */ new Set();
8617
+ let pages = 0;
8618
+ let calls = 0;
8619
+ let written = 0;
8620
+ let error;
8621
+ try {
8622
+ for (const slice of slices) {
8623
+ if (products.length >= maxRecords) break;
8624
+ const walked = await paginate({
8625
+ first: { pagina: 1, from: slice.from, to: slice.to, limite },
8626
+ maxPages: options.maxPages ?? 1e3,
8627
+ fetchPage: async (request) => {
8628
+ await limiter.take();
8629
+ calls += 1;
8630
+ const page = await options.fetchPage(request);
8631
+ pages += 1;
8632
+ const items = page.items ?? [];
8633
+ const last = page.short === true || items.length < request.limite;
8634
+ const enough = products.length + items.length >= maxRecords;
8635
+ return { items, next: last || enough ? null : { ...request, pagina: request.pagina + 1 } };
8636
+ }
8637
+ });
8638
+ for (const raw of walked.items) {
8639
+ if (products.length >= maxRecords) break;
8640
+ const mapped = toMirroredProduct(raw);
8641
+ if (!mapped) continue;
8642
+ seen.add(mapped.externalId);
8643
+ products.push(mapped);
8644
+ if (await options.upsert(mapped)) written += 1;
8645
+ }
8646
+ }
8647
+ } catch (caught) {
8648
+ error = String(caught?.message ?? caught);
8649
+ }
8650
+ const reconciled = reconcileMirror({
8651
+ completeness: "additive",
8652
+ observed: seen,
8653
+ linked: options.linked ?? []
8654
+ });
8655
+ const advanced = error ? cursor : { ...cursor };
8656
+ return {
8657
+ status: error ? "error" : products.length >= maxRecords ? "partial" : "success",
8658
+ completeness: "additive",
8659
+ fetched: products.length,
8660
+ written,
8661
+ cursor: advanced,
8662
+ keptOutOfRange: reconciled.keptOutOfRange,
8663
+ products,
8664
+ pages,
8665
+ calls,
8666
+ error,
8667
+ stats: {
8668
+ pages,
8669
+ calls,
8670
+ window_from: cursor.from,
8671
+ window_to: cursor.to,
8672
+ slices: slices.length,
8673
+ kept_out_of_range: reconciled.keptOutOfRange.length,
8674
+ cursor: serializeCursor(advanced)
8675
+ }
8676
+ };
8677
+ }
8678
+ function sampleProducts(options) {
8679
+ return pullProducts({
8680
+ ...options,
8681
+ maxRecords: options.sampleSize ?? BLING_SAMPLE_SIZE,
8682
+ maxPages: 1,
8683
+ // A sample never reconciles: it saw one page of one window and knows less
8684
+ // about absence than any other run in the system.
8685
+ linked: []
8686
+ });
8687
+ }
8688
+
8689
+ // src/integrations/bling/inbound.ts
8690
+ var BLING_MARKETPLACE_SOURCE = "bling_marketplace";
8691
+ function routeCallback(callback) {
8692
+ const account = callback.companyId ? String(callback.companyId).trim() : "";
8693
+ if (callback.state) return { mode: "tenant", state: callback.state, providerAccountKey: account || null };
8694
+ if (account) return { mode: "orphan", providerAccountKey: account, source: BLING_MARKETPLACE_SOURCE };
8695
+ return { mode: "reject", reason: "callback carried neither state nor companyId" };
8696
+ }
8697
+ function orphanConnection(route) {
8698
+ return {
8699
+ connectorId: BLING_CONNECTOR_ID,
8700
+ // The Bling company is the account, so it is also the instance key: two
8701
+ // companies are two connections, not two rows fighting over one.
8702
+ instanceKey: route.providerAccountKey,
8703
+ providerAccountKey: route.providerAccountKey,
8704
+ status: "pending",
8705
+ settings: { companyId: route.providerAccountKey, source: route.source, stockOwner: "bling" }
8706
+ };
8707
+ }
8708
+ async function acceptWebhook(request, options) {
8709
+ let ok = false;
8710
+ try {
8711
+ ok = await options.verify(request.body, request.signature);
8712
+ } catch (error) {
8713
+ options.onError?.(error);
8714
+ ok = false;
8715
+ }
8716
+ if (!ok) return { status: 401, queued: false, reason: "signature" };
8717
+ const account = request.providerAccountKey ? String(request.providerAccountKey) : "";
8718
+ if (!account) return { status: 200, queued: false, reason: "no account in payload" };
8719
+ let target = null;
8720
+ try {
8721
+ target = await options.resolve(account);
8722
+ } catch (error) {
8723
+ options.onError?.(error);
8724
+ }
8725
+ if (!target) return { status: 200, queued: false, reason: "unclaimed account" };
8726
+ try {
8727
+ await options.enqueue({ ...target, body: request.body });
8728
+ } catch (error) {
8729
+ options.onError?.(error);
8730
+ return { status: 500, queued: false, reason: "enqueue failed" };
8731
+ }
8732
+ return { status: 200, queued: true };
8733
+ }
8734
+
8735
+ // src/integrations/neochef/mapping.ts
8736
+ function toNumber2(value) {
8737
+ if (value === null || value === void 0 || value === "") return null;
8738
+ const n = typeof value === "number" ? value : Number(String(value).replace(",", "."));
8739
+ return Number.isFinite(n) ? n : null;
8740
+ }
8741
+ function toMirroredNeoChefProduct(raw) {
8742
+ if (!raw || raw.id === null || raw.id === void 0 || raw.id === "") return null;
8743
+ const inactive = raw.is_active === false || String(raw.status ?? "active").toLowerCase() === "archived";
8744
+ return {
8745
+ externalId: String(raw.id),
8746
+ sku: raw.sku ? String(raw.sku) : null,
8747
+ name: String(raw.name ?? "").trim() || `Produto ${raw.id}`,
8748
+ price: toNumber2(raw.price),
8749
+ // The kitchen owns this number. The store mirrors it; it does not decide it.
8750
+ inventoryCount: toNumber2(raw.stock),
8751
+ status: inactive ? "archived" : "active",
8752
+ imageUrl: raw.image_url ? String(raw.image_url) : null,
8753
+ // Unlike Bling, the far side DOES return its change stamp, so the cursor can
8754
+ // advance from the data instead of from the window we asked for.
8755
+ updatedAt: raw.updated_at ? String(raw.updated_at) : null
8756
+ };
8757
+ }
8758
+ function toNeoChefOrder(order) {
8759
+ return {
8760
+ kind: order.pickup === true ? "takeout" : "delivery",
8761
+ // The store's own number, so a human can match the two screens. Falls back
8762
+ // to the id rather than to empty: an order with no reference is unmatchable.
8763
+ reference_number: String(order.referenceNumber ?? order.id),
8764
+ // It arrives paid and confirmed — the store already took the money, and a
8765
+ // kitchen that has to re-confirm it is a kitchen doing the work twice.
8766
+ status: "confirmed",
8767
+ total: toNumber2(order.total),
8768
+ subtotal: toNumber2(order.subtotal),
8769
+ notes: order.notes ? String(order.notes) : null
8770
+ };
8771
+ }
8772
+ function advanceNeoChefCursor(products, overlapMs) {
8773
+ const stamps = products.map((product) => product.updatedAt ? Date.parse(product.updatedAt) : NaN).filter((value) => Number.isFinite(value));
8774
+ if (stamps.length === 0) return null;
8775
+ return new Date(Math.max(...stamps) - overlapMs).toISOString();
8776
+ }
8667
8777
  function ProductContentTab({ item, getProvider, libraryHref = "#/content" }) {
8668
8778
  const catalogId = item?.id;
8669
8779
  const [product, setProduct] = useState(void 0);
@@ -8721,10 +8831,127 @@ function ProductContentTab({ item, getProvider, libraryHref = "#/content" }) {
8721
8831
  }
8722
8832
  );
8723
8833
  }
8834
+ var SYMBOLS = { BRL: "R$", EUR: "\u20AC", USD: "US$", GBP: "\xA3", ARS: "AR$", MXN: "MX$" };
8835
+ function ProductMarketPricesTab({ item, getProvider, settingsHref = "#/settings/shop-markets" }) {
8836
+ const catalogId = item?.id;
8837
+ const basePrice = Number(item?.salePrice ?? item?.price ?? 0);
8838
+ const [markets, setMarkets] = useState(void 0);
8839
+ const [saved, setSaved] = useState({});
8840
+ const [draft2, setDraft] = useState({});
8841
+ const [error, setError] = useState(null);
8842
+ const [saving, setSaving] = useState(false);
8843
+ const [done, setDone] = useState(false);
8844
+ useEffect(() => {
8845
+ if (!catalogId) return;
8846
+ let alive = true;
8847
+ const provider = getProvider();
8848
+ if (!provider.listAdminMarkets || !provider.getCatalogMarketPrices) {
8849
+ setMarkets([]);
8850
+ return;
8851
+ }
8852
+ Promise.all([provider.listAdminMarkets(), provider.getCatalogMarketPrices(catalogId)]).then(([list, prices]) => {
8853
+ if (!alive) return;
8854
+ const byMarket = Object.fromEntries(prices.map((p) => [p.marketId, p.price]));
8855
+ setMarkets(list);
8856
+ setSaved(byMarket);
8857
+ setDraft(byMarket);
8858
+ }).catch((err) => {
8859
+ if (alive) {
8860
+ setMarkets([]);
8861
+ setError(errorMessage(err));
8862
+ }
8863
+ });
8864
+ return () => {
8865
+ alive = false;
8866
+ };
8867
+ }, [catalogId]);
8868
+ const dirty = useMemo(
8869
+ () => Object.keys(draft2).some((id) => (draft2[id] ?? null) !== (saved[id] ?? null)),
8870
+ [draft2, saved]
8871
+ );
8872
+ async function save() {
8873
+ if (!catalogId) return;
8874
+ const provider = getProvider();
8875
+ if (!provider.setCatalogMarketPrice) return;
8876
+ setSaving(true);
8877
+ setError(null);
8878
+ setDone(false);
8879
+ try {
8880
+ for (const id of Object.keys(draft2)) {
8881
+ const next = draft2[id] ?? null;
8882
+ if (next !== (saved[id] ?? null)) await provider.setCatalogMarketPrice(catalogId, id, next);
8883
+ }
8884
+ setSaved({ ...draft2 });
8885
+ setDone(true);
8886
+ } catch (err) {
8887
+ setError(errorMessage(err));
8888
+ } finally {
8889
+ setSaving(false);
8890
+ }
8891
+ }
8892
+ if (markets === void 0) {
8893
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-3", "aria-busy": "true", children: [
8894
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-48" }),
8895
+ [0, 1].map((i) => /* @__PURE__ */ jsx(Skeleton, { className: "h-16 w-full" }, i))
8896
+ ] });
8897
+ }
8898
+ if (markets.length === 0) {
8899
+ 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: [
8900
+ "A loja vende numa moeda s\xF3. Para vender em outros pa\xEDses com pre\xE7o pr\xF3prio,",
8901
+ " ",
8902
+ /* @__PURE__ */ jsx("a", { href: settingsHref, className: "font-medium text-primary underline underline-offset-2", children: "crie os mercados" }),
8903
+ "."
8904
+ ] }) });
8905
+ }
8906
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
8907
+ /* @__PURE__ */ jsxs("div", { children: [
8908
+ /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold", children: "Pre\xE7os por mercado" }),
8909
+ /* @__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." })
8910
+ ] }),
8911
+ /* @__PURE__ */ jsx("ul", { className: "divide-y rounded-lg border", children: markets.map((market) => {
8912
+ const value = draft2[market.id] ?? null;
8913
+ const symbol = SYMBOLS[market.currency] ?? market.currency;
8914
+ return /* @__PURE__ */ jsxs("li", { className: "flex flex-wrap items-center gap-4 px-4 py-3", children: [
8915
+ /* @__PURE__ */ jsxs("div", { className: "min-w-[12rem] flex-1", children: [
8916
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm font-medium", children: [
8917
+ market.name,
8918
+ /* @__PURE__ */ jsx(Badge, { variant: "secondary", children: market.currency }),
8919
+ market.isDefault && /* @__PURE__ */ jsx(Badge, { variant: "outline", children: "Padr\xE3o" }),
8920
+ !market.isActive && /* @__PURE__ */ jsx(Badge, { variant: "outline", children: "Inativo" })
8921
+ ] }),
8922
+ /* @__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" })
8923
+ ] }),
8924
+ /* @__PURE__ */ jsx("div", { className: "w-48", children: /* @__PURE__ */ jsx(
8925
+ CurrencyInput,
8926
+ {
8927
+ value: value ?? 0,
8928
+ onChange: (next) => {
8929
+ setDone(false);
8930
+ setDraft((d) => ({ ...d, [market.id]: next > 0 ? next : null }));
8931
+ },
8932
+ symbol,
8933
+ currencyCode: market.currency,
8934
+ locale: market.locale ?? "pt-BR",
8935
+ placeholder: market.isDefault && basePrice ? String(basePrice) : void 0
8936
+ }
8937
+ ) }),
8938
+ /* @__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." }) })
8939
+ ] }, market.id);
8940
+ }) }),
8941
+ error && /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: error }),
8942
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
8943
+ /* @__PURE__ */ jsx(Button, { onClick: () => {
8944
+ void save();
8945
+ }, disabled: !dirty || saving, children: saving ? "Salvando\u2026" : "Salvar pre\xE7os" }),
8946
+ done && !dirty && /* @__PURE__ */ jsx("span", { className: "text-sm text-emerald-600", children: "Pre\xE7os salvos." }),
8947
+ /* @__PURE__ */ jsx("a", { href: settingsHref, className: "ml-auto text-xs text-muted-foreground underline underline-offset-2", children: "Gerenciar mercados" })
8948
+ ] })
8949
+ ] });
8950
+ }
8724
8951
 
8725
8952
  // 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 })));
8953
+ var ShopPage = React13__default.lazy(() => import('./ShopPage-2CTRGQTX.js').then((m) => ({ default: m.ShopPage })));
8954
+ var LazyOrderDetail = React13__default.lazy(() => import('./ShopPage-2CTRGQTX.js').then((m) => ({ default: m.ShopOrderDetailSlot })));
8728
8955
  function ShopOrderDetail(provider) {
8729
8956
  const Detail = (props) => React13__default.createElement(
8730
8957
  React13__default.Suspense,
@@ -8912,7 +9139,7 @@ function createShopPlugin(options) {
8912
9139
  dataProvider: createShopGiftCardDataProvider(resolveProvider),
8913
9140
  feature: "shop",
8914
9141
  stats: (items, total) => {
8915
- const money3 = (v) => new Intl.NumberFormat(curr.locale, { style: "currency", currency: curr.code }).format(v);
9142
+ const money3 = (v) => formatCurrency(v, curr.code);
8916
9143
  const active = items?.filter((g) => g.status === "active") ?? [];
8917
9144
  return [
8918
9145
  { id: "total", label: "Cart\xF5es emitidos", value: total, icon: CreditCard },
@@ -9171,6 +9398,16 @@ function createShopPlugin(options) {
9171
9398
  order: 30,
9172
9399
  permission: READ
9173
9400
  },
9401
+ {
9402
+ // Onde a loja vende (0116): moeda, países, filial e frete por mercado.
9403
+ id: "shop-markets",
9404
+ label: "Mercados",
9405
+ icon: "Globe",
9406
+ group: COMMERCE_GROUP,
9407
+ component: settingsTab("MarketsSettings", () => React13__default.createElement(MarketsSettings, {})),
9408
+ order: 30.5,
9409
+ permission: READ
9410
+ },
9174
9411
  {
9175
9412
  id: "shop-payments",
9176
9413
  label: "Pagamentos",
@@ -9251,7 +9488,16 @@ function shopProductContentTab(options) {
9251
9488
  props: { getProvider: options.provider, libraryHref: options.libraryHref ?? "#/content" }
9252
9489
  };
9253
9490
  }
9491
+ function shopProductMarketPricesTab(options) {
9492
+ return {
9493
+ id: "market-prices",
9494
+ label: options.label ?? "Pre\xE7os por mercado",
9495
+ icon: "Globe",
9496
+ component: ProductMarketPricesTab,
9497
+ props: { getProvider: options.provider, settingsHref: options.settingsHref ?? "#/settings/shop-markets" }
9498
+ };
9499
+ }
9254
9500
 
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 };
9501
+ 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
9502
  //# sourceMappingURL=index.js.map
9257
9503
  //# sourceMappingURL=index.js.map