@fayz-ai/plugin-shop 0.24.4 → 0.24.6

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 (61) hide show
  1. package/dist/CheckoutSettings-GQRYZF6I.js +128 -0
  2. package/dist/CheckoutSettings-GQRYZF6I.js.map +1 -0
  3. package/dist/ContentPage-2PHOZSFZ.js +510 -0
  4. package/dist/ContentPage-2PHOZSFZ.js.map +1 -0
  5. package/dist/DeliveryStoreSettings-L2RXOVB6.js +172 -0
  6. package/dist/DeliveryStoreSettings-L2RXOVB6.js.map +1 -0
  7. package/dist/FulfillmentSettings-PW233UOK.js +61 -0
  8. package/dist/FulfillmentSettings-PW233UOK.js.map +1 -0
  9. package/dist/MarketsSettings-YUEVDLIR.js +19 -0
  10. package/dist/MarketsSettings-YUEVDLIR.js.map +1 -0
  11. package/dist/PaymentsSettings-5CI74TY2.js +318 -0
  12. package/dist/PaymentsSettings-5CI74TY2.js.map +1 -0
  13. package/dist/ProductContentTab-PSNDS7JZ.js +4 -0
  14. package/dist/ProductContentTab-PSNDS7JZ.js.map +1 -0
  15. package/dist/ProductListingTab-55Y5RXU7.js +4 -0
  16. package/dist/ProductListingTab-55Y5RXU7.js.map +1 -0
  17. package/dist/ProductMarketPricesTab-QD2ZXEWL.js +4 -0
  18. package/dist/ProductMarketPricesTab-QD2ZXEWL.js.map +1 -0
  19. package/dist/ShippingSettings-UBTNRBJ4.js +9 -0
  20. package/dist/ShippingSettings-UBTNRBJ4.js.map +1 -0
  21. package/dist/{ShopPage-NUIIWBCB.js → ShopPage-NARKHXOO.js} +6 -3
  22. package/dist/ShopPage-NARKHXOO.js.map +1 -0
  23. package/dist/StoreGeneralSettings-DEZ2CMVG.js +97 -0
  24. package/dist/StoreGeneralSettings-DEZ2CMVG.js.map +1 -0
  25. package/dist/chunk-2MXOKJQO.js +23 -0
  26. package/dist/chunk-2MXOKJQO.js.map +1 -0
  27. package/dist/chunk-4JM32Z7J.js +51 -0
  28. package/dist/chunk-4JM32Z7J.js.map +1 -0
  29. package/dist/chunk-53Y6VLAW.js +132 -0
  30. package/dist/chunk-53Y6VLAW.js.map +1 -0
  31. package/dist/chunk-6V2VAUWP.js +24 -0
  32. package/dist/chunk-6V2VAUWP.js.map +1 -0
  33. package/dist/chunk-FQQMEM26.js +59 -0
  34. package/dist/chunk-FQQMEM26.js.map +1 -0
  35. package/dist/chunk-JYT6BTRE.js +298 -0
  36. package/dist/chunk-JYT6BTRE.js.map +1 -0
  37. package/dist/chunk-MFEOIJI7.js +127 -0
  38. package/dist/chunk-MFEOIJI7.js.map +1 -0
  39. package/dist/chunk-R5CUDFOI.js +61 -0
  40. package/dist/chunk-R5CUDFOI.js.map +1 -0
  41. package/dist/chunk-STHGZWBQ.js +1455 -0
  42. package/dist/chunk-STHGZWBQ.js.map +1 -0
  43. package/dist/{chunk-XV3KZRQX.js → chunk-STZYH32S.js} +9 -140
  44. package/dist/chunk-STZYH32S.js.map +1 -0
  45. package/dist/chunk-TDV3SFXT.js +75 -0
  46. package/dist/chunk-TDV3SFXT.js.map +1 -0
  47. package/dist/chunk-YUG6XQHJ.js +55 -0
  48. package/dist/chunk-YUG6XQHJ.js.map +1 -0
  49. package/dist/data/registry-routes.d.ts.map +1 -1
  50. package/dist/index.d.ts.map +1 -1
  51. package/dist/index.js +129 -3456
  52. package/dist/index.js.map +1 -1
  53. package/dist/settings/ShippingSettings.d.ts.map +1 -1
  54. package/dist/views/EmailTemplatePage.d.ts.map +1 -1
  55. package/dist/views/EmailsPage.d.ts.map +1 -1
  56. package/dist/views/ProductContentTab.d.ts.map +1 -1
  57. package/dist/views/ProductMarketPricesTab.d.ts.map +1 -1
  58. package/dist/views/media-links.d.ts.map +1 -1
  59. package/package.json +7 -7
  60. package/dist/ShopPage-NUIIWBCB.js.map +0 -1
  61. package/dist/chunk-XV3KZRQX.js.map +0 -1
@@ -0,0 +1,97 @@
1
+ import { SettingsState } from './chunk-FQQMEM26.js';
2
+ import { useStoreSettings } from './chunk-R5CUDFOI.js';
3
+ import './chunk-YUG6XQHJ.js';
4
+ import './chunk-2MXOKJQO.js';
5
+ import { SettingsGroup, SelectRow, ToggleRow } from '@fayz-ai/admin';
6
+ import { jsxs, jsx } from 'react/jsx-runtime';
7
+
8
+ var CURRENCIES = [
9
+ { value: "BRL", label: "Real (R$)" },
10
+ { value: "USD", label: "US Dollar ($)" },
11
+ { value: "EUR", label: "Euro (\u20AC)" },
12
+ { value: "GBP", label: "British Pound (\xA3)" }
13
+ ];
14
+ var LOCALES = [
15
+ { value: "pt-BR", label: "Portugu\xEAs (Brasil)" },
16
+ { value: "en-US", label: "English (US)" },
17
+ { value: "es-ES", label: "Espa\xF1ol" }
18
+ ];
19
+ function StoreGeneralSettings({ currency, provider }) {
20
+ const settings = useStoreSettings(provider, {
21
+ currency: currency?.code ?? "BRL",
22
+ locale: currency?.locale ?? "pt-BR",
23
+ showOutOfStock: true,
24
+ requireSku: false,
25
+ notifyNewOrder: true,
26
+ notifyLowStock: false
27
+ });
28
+ const { value, set } = settings;
29
+ return /* @__PURE__ */ jsxs(SettingsState, { ...settings, children: [
30
+ /* @__PURE__ */ jsxs(SettingsGroup, { title: "Loja", description: "Moeda e formata\xE7\xE3o da vitrine.", children: [
31
+ /* @__PURE__ */ jsx(
32
+ SelectRow,
33
+ {
34
+ label: "Moeda",
35
+ description: "Moeda padr\xE3o para pre\xE7os e checkout.",
36
+ value: value.currency ?? "BRL",
37
+ options: CURRENCIES,
38
+ onChange: (v) => set({ currency: v })
39
+ }
40
+ ),
41
+ /* @__PURE__ */ jsx(
42
+ SelectRow,
43
+ {
44
+ label: "Idioma / formato",
45
+ description: "Formata\xE7\xE3o de n\xFAmeros, pre\xE7os e datas.",
46
+ value: value.locale ?? "pt-BR",
47
+ options: LOCALES,
48
+ onChange: (v) => set({ locale: v })
49
+ }
50
+ )
51
+ ] }),
52
+ /* @__PURE__ */ jsxs(SettingsGroup, { title: "Cat\xE1logo", description: "Como os produtos aparecem e s\xE3o gerenciados.", children: [
53
+ /* @__PURE__ */ jsx(
54
+ ToggleRow,
55
+ {
56
+ label: "Mostrar produtos esgotados",
57
+ description: "Exibir itens sem estoque na vitrine.",
58
+ checked: value.showOutOfStock ?? true,
59
+ onChange: (v) => set({ showOutOfStock: v })
60
+ }
61
+ ),
62
+ /* @__PURE__ */ jsx(
63
+ ToggleRow,
64
+ {
65
+ label: "Exigir SKU",
66
+ description: "Tornar o SKU obrigat\xF3rio ao criar produtos.",
67
+ checked: value.requireSku ?? false,
68
+ onChange: (v) => set({ requireSku: v })
69
+ }
70
+ )
71
+ ] }),
72
+ /* @__PURE__ */ jsxs(SettingsGroup, { title: "Notifica\xE7\xF5es", description: "Avisos por e-mail da loja.", children: [
73
+ /* @__PURE__ */ jsx(
74
+ ToggleRow,
75
+ {
76
+ label: "E-mail de novo pedido",
77
+ description: "Notificar a equipe a cada novo pedido.",
78
+ checked: value.notifyNewOrder ?? true,
79
+ onChange: (v) => set({ notifyNewOrder: v })
80
+ }
81
+ ),
82
+ /* @__PURE__ */ jsx(
83
+ ToggleRow,
84
+ {
85
+ label: "Alerta de estoque baixo",
86
+ description: "Avisar quando produtos atingirem o m\xEDnimo.",
87
+ checked: value.notifyLowStock ?? false,
88
+ onChange: (v) => set({ notifyLowStock: v })
89
+ }
90
+ )
91
+ ] })
92
+ ] });
93
+ }
94
+
95
+ export { StoreGeneralSettings };
96
+ //# sourceMappingURL=StoreGeneralSettings-DEZ2CMVG.js.map
97
+ //# sourceMappingURL=StoreGeneralSettings-DEZ2CMVG.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/settings/StoreGeneralSettings.tsx"],"names":[],"mappings":";;;;;;;AAWA,IAAM,UAAA,GAAa;AAAA,EACjB,EAAE,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,WAAA,EAAY;AAAA,EACnC,EAAE,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,eAAA,EAAgB;AAAA,EACvC,EAAE,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,eAAA,EAAW;AAAA,EAClC,EAAE,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,sBAAA;AACzB,CAAA;AAEA,IAAM,OAAA,GAAU;AAAA,EACd,EAAE,KAAA,EAAO,OAAA,EAAS,KAAA,EAAO,uBAAA,EAAqB;AAAA,EAC9C,EAAE,KAAA,EAAO,OAAA,EAAS,KAAA,EAAO,cAAA,EAAe;AAAA,EACxC,EAAE,KAAA,EAAO,OAAA,EAAS,KAAA,EAAO,YAAA;AAC3B,CAAA;AASO,SAAS,oBAAA,CAAqB,EAAE,QAAA,EAAU,QAAA,EAAS,EAA8B;AACtF,EAAA,MAAM,QAAA,GAAW,iBAAiB,QAAA,EAAU;AAAA,IAC1C,QAAA,EAAU,UAAU,IAAA,IAAQ,KAAA;AAAA,IAC5B,MAAA,EAAQ,UAAU,MAAA,IAAU,OAAA;AAAA,IAC5B,cAAA,EAAgB,IAAA;AAAA,IAChB,UAAA,EAAY,KAAA;AAAA,IACZ,cAAA,EAAgB,IAAA;AAAA,IAChB,cAAA,EAAgB;AAAA,GACjB,CAAA;AACD,EAAA,MAAM,EAAE,KAAA,EAAO,GAAA,EAAI,GAAI,QAAA;AAEvB,EAAA,uBACE,IAAA,CAAC,aAAA,EAAA,EAAe,GAAG,QAAA,EACjB,QAAA,EAAA;AAAA,oBAAA,IAAA,CAAC,aAAA,EAAA,EAAc,KAAA,EAAM,MAAA,EAAO,WAAA,EAAY,sCAAA,EACtC,QAAA,EAAA;AAAA,sBAAA,GAAA;AAAA,QAAC,SAAA;AAAA,QAAA;AAAA,UACC,KAAA,EAAM,OAAA;AAAA,UACN,WAAA,EAAY,4CAAA;AAAA,UACZ,KAAA,EAAO,MAAM,QAAA,IAAY,KAAA;AAAA,UACzB,OAAA,EAAS,UAAA;AAAA,UACT,UAAU,CAAC,CAAA,KAAM,IAAI,EAAE,QAAA,EAAU,GAAG;AAAA;AAAA,OACtC;AAAA,sBACA,GAAA;AAAA,QAAC,SAAA;AAAA,QAAA;AAAA,UACC,KAAA,EAAM,kBAAA;AAAA,UACN,WAAA,EAAY,oDAAA;AAAA,UACZ,KAAA,EAAO,MAAM,MAAA,IAAU,OAAA;AAAA,UACvB,OAAA,EAAS,OAAA;AAAA,UACT,UAAU,CAAC,CAAA,KAAM,IAAI,EAAE,MAAA,EAAQ,GAAG;AAAA;AAAA;AACpC,KAAA,EACF,CAAA;AAAA,oBAEA,IAAA,CAAC,aAAA,EAAA,EAAc,KAAA,EAAM,aAAA,EAAW,aAAY,iDAAA,EAC1C,QAAA,EAAA;AAAA,sBAAA,GAAA;AAAA,QAAC,SAAA;AAAA,QAAA;AAAA,UACC,KAAA,EAAM,4BAAA;AAAA,UACN,WAAA,EAAY,sCAAA;AAAA,UACZ,OAAA,EAAS,MAAM,cAAA,IAAkB,IAAA;AAAA,UACjC,UAAU,CAAC,CAAA,KAAM,IAAI,EAAE,cAAA,EAAgB,GAAG;AAAA;AAAA,OAC5C;AAAA,sBACA,GAAA;AAAA,QAAC,SAAA;AAAA,QAAA;AAAA,UACC,KAAA,EAAM,YAAA;AAAA,UACN,WAAA,EAAY,gDAAA;AAAA,UACZ,OAAA,EAAS,MAAM,UAAA,IAAc,KAAA;AAAA,UAC7B,UAAU,CAAC,CAAA,KAAM,IAAI,EAAE,UAAA,EAAY,GAAG;AAAA;AAAA;AACxC,KAAA,EACF,CAAA;AAAA,oBAQA,IAAA,CAAC,aAAA,EAAA,EAAc,KAAA,EAAM,oBAAA,EAAe,aAAY,4BAAA,EAC9C,QAAA,EAAA;AAAA,sBAAA,GAAA;AAAA,QAAC,SAAA;AAAA,QAAA;AAAA,UACC,KAAA,EAAM,uBAAA;AAAA,UACN,WAAA,EAAY,wCAAA;AAAA,UACZ,OAAA,EAAS,MAAM,cAAA,IAAkB,IAAA;AAAA,UACjC,UAAU,CAAC,CAAA,KAAM,IAAI,EAAE,cAAA,EAAgB,GAAG;AAAA;AAAA,OAC5C;AAAA,sBACA,GAAA;AAAA,QAAC,SAAA;AAAA,QAAA;AAAA,UACC,KAAA,EAAM,yBAAA;AAAA,UACN,WAAA,EAAY,+CAAA;AAAA,UACZ,OAAA,EAAS,MAAM,cAAA,IAAkB,KAAA;AAAA,UACjC,UAAU,CAAC,CAAA,KAAM,IAAI,EAAE,cAAA,EAAgB,GAAG;AAAA;AAAA;AAC5C,KAAA,EACF;AAAA,GAAA,EACF,CAAA;AAEJ","file":"StoreGeneralSettings-DEZ2CMVG.js","sourcesContent":["import React from 'react'\nimport { SettingsGroup, SelectRow, ToggleRow } from '@fayz-ai/admin'\nimport type { ShopProviderResolver } from '../data/shared'\nimport { useStoreSettings } from './useStoreSettings'\nimport { SettingsState } from './SettingsState'\n\nexport interface StoreGeneralSettingsProps {\n currency?: { code?: string; locale?: string; symbol?: string }\n provider?: ShopProviderResolver\n}\n\nconst CURRENCIES = [\n { value: 'BRL', label: 'Real (R$)' },\n { value: 'USD', label: 'US Dollar ($)' },\n { value: 'EUR', label: 'Euro (€)' },\n { value: 'GBP', label: 'British Pound (£)' },\n]\n\nconst LOCALES = [\n { value: 'pt-BR', label: 'Português (Brasil)' },\n { value: 'en-US', label: 'English (US)' },\n { value: 'es-ES', label: 'Español' },\n]\n\n/**\n * Loja — moeda, formatação e as regras de catálogo.\n *\n * O `currency` que o app passa na criação do plugin é o VALOR INICIAL mostrado,\n * não o valor salvo: enquanto o lojista não escolhe, a vitrine segue com o que o\n * app declarou, e é isso que a coluna nula significa. Escolher grava.\n */\nexport function StoreGeneralSettings({ currency, provider }: StoreGeneralSettingsProps) {\n const settings = useStoreSettings(provider, {\n currency: currency?.code ?? 'BRL',\n locale: currency?.locale ?? 'pt-BR',\n showOutOfStock: true,\n requireSku: false,\n notifyNewOrder: true,\n notifyLowStock: false,\n })\n const { value, set } = settings\n\n return (\n <SettingsState {...settings}>\n <SettingsGroup title=\"Loja\" description=\"Moeda e formatação da vitrine.\">\n <SelectRow\n label=\"Moeda\"\n description=\"Moeda padrão para preços e checkout.\"\n value={value.currency ?? 'BRL'}\n options={CURRENCIES}\n onChange={(v) => set({ currency: v })}\n />\n <SelectRow\n label=\"Idioma / formato\"\n description=\"Formatação de números, preços e datas.\"\n value={value.locale ?? 'pt-BR'}\n options={LOCALES}\n onChange={(v) => set({ locale: v })}\n />\n </SettingsGroup>\n\n <SettingsGroup title=\"Catálogo\" description=\"Como os produtos aparecem e são gerenciados.\">\n <ToggleRow\n label=\"Mostrar produtos esgotados\"\n description=\"Exibir itens sem estoque na vitrine.\"\n checked={value.showOutOfStock ?? true}\n onChange={(v) => set({ showOutOfStock: v })}\n />\n <ToggleRow\n label=\"Exigir SKU\"\n description=\"Tornar o SKU obrigatório ao criar produtos.\"\n checked={value.requireSku ?? false}\n onChange={(v) => set({ requireSku: v })}\n />\n </SettingsGroup>\n\n {/* «Controlar estoque» saiu daqui. Era um interruptor local que não\n governava nada, e a decisão real — quem é dono do número, nosso livro\n ou um ERP — já existe como `stock_ownership` e é escrita pelo conector\n que assume o estoque. Dois controles para a mesma coisa é o caminho\n mais curto para eles discordarem. */}\n\n <SettingsGroup title=\"Notificações\" description=\"Avisos por e-mail da loja.\">\n <ToggleRow\n label=\"E-mail de novo pedido\"\n description=\"Notificar a equipe a cada novo pedido.\"\n checked={value.notifyNewOrder ?? true}\n onChange={(v) => set({ notifyNewOrder: v })}\n />\n <ToggleRow\n label=\"Alerta de estoque baixo\"\n description=\"Avisar quando produtos atingirem o mínimo.\"\n checked={value.notifyLowStock ?? false}\n onChange={(v) => set({ notifyLowStock: v })}\n />\n </SettingsGroup>\n </SettingsState>\n )\n}\n"]}
@@ -0,0 +1,23 @@
1
+ import { errorMessage as errorMessage$1 } from '@fayz-ai/core';
2
+
3
+ // src/settings/error-message.ts
4
+ var rawMessage = (error) => errorMessage$1(error, "erro desconhecido");
5
+ var RPC_REFUSAL = [
6
+ [/nothing left to fulfill/i, "N\xE3o h\xE1 itens pendentes neste pedido \u2014 tudo j\xE1 foi enviado."],
7
+ [/not a member of this store/i, "Sua conta n\xE3o tem permiss\xE3o para despachar pedidos desta loja."],
8
+ [/order not found/i, "Pedido n\xE3o encontrado."],
9
+ [/fulfillment not found/i, "Envio n\xE3o encontrado \u2014 recarregue a p\xE1gina."],
10
+ [/fulfillment was cancelled/i, "Este envio foi cancelado. Registre um novo envio."],
11
+ [/location does not belong to this store/i, "O local de estoque escolhido n\xE3o \xE9 desta loja."],
12
+ [/not pending/i, "N\xE3o h\xE1 cobran\xE7a em aberto para registrar neste pedido."],
13
+ [/not authorized to confirm payment/i, "Sua conta n\xE3o tem permiss\xE3o para registrar o pagamento deste pedido."]
14
+ ];
15
+ function errorMessage(error) {
16
+ const raw = rawMessage(error);
17
+ for (const [pattern, friendly] of RPC_REFUSAL) if (pattern.test(raw)) return friendly;
18
+ return raw;
19
+ }
20
+
21
+ export { errorMessage };
22
+ //# sourceMappingURL=chunk-2MXOKJQO.js.map
23
+ //# sourceMappingURL=chunk-2MXOKJQO.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/settings/error-message.ts"],"names":["coreMessage"],"mappings":";;;AAgBA,IAAM,UAAA,GAAa,CAAC,KAAA,KAAmBA,cAAA,CAAY,OAAO,mBAAmB,CAAA;AAE7E,IAAM,WAAA,GAAuC;AAAA,EAC3C,CAAC,4BAA4B,0EAA4D,CAAA;AAAA,EACzF,CAAC,+BAA+B,sEAAgE,CAAA;AAAA,EAChG,CAAC,oBAAoB,2BAAwB,CAAA;AAAA,EAC7C,CAAC,0BAA0B,wDAA6C,CAAA;AAAA,EACxE,CAAC,8BAA8B,mDAAmD,CAAA;AAAA,EAClF,CAAC,2CAA2C,sDAAgD,CAAA;AAAA,EAC5F,CAAC,gBAAgB,iEAAwD,CAAA;AAAA,EACzE,CAAC,sCAAsC,4EAAsE;AAC/G,CAAA;AACO,SAAS,aAAa,KAAA,EAAwB;AACnD,EAAA,MAAM,GAAA,GAAM,WAAW,KAAK,CAAA;AAC5B,EAAA,KAAA,MAAW,CAAC,OAAA,EAAS,QAAQ,CAAA,IAAK,WAAA,MAAiB,OAAA,CAAQ,IAAA,CAAK,GAAG,CAAA,EAAG,OAAO,QAAA;AAC7E,EAAA,OAAO,GAAA;AACT","file":"chunk-2MXOKJQO.js","sourcesContent":["/**\n * The refusals the dispatch RPCs raise, in the language the merchant reads.\n *\n * These are `RAISE EXCEPTION` strings, so they arrive as English prose prefixed\n * with the function name — \"shop_create_fulfillment: nothing left to fulfill\"\n * is accurate and useless to a shop owner. Matched on the tail so the prefix\n * never has to be repeated here.\n */\n\n// The generic half of this now lives in @fayz-ai/core (it was met here first,\n// on the settings screens' first real load against the pool, and every other\n// package had the broken ternary). What stays here is the domain half above:\n// turning an RPC refusal into a sentence a merchant can act on.\nimport { errorMessage as coreMessage } from '@fayz-ai/core'\n\n/** The merchant reads this one, so the last resort is in their language. */\nconst rawMessage = (error: unknown) => coreMessage(error, 'erro desconhecido')\n\nconst RPC_REFUSAL: Array<[RegExp, string]> = [\n [/nothing left to fulfill/i, 'Não há itens pendentes neste pedido — tudo já foi enviado.'],\n [/not a member of this store/i, 'Sua conta não tem permissão para despachar pedidos desta loja.'],\n [/order not found/i, 'Pedido não encontrado.'],\n [/fulfillment not found/i, 'Envio não encontrado — recarregue a página.'],\n [/fulfillment was cancelled/i, 'Este envio foi cancelado. Registre um novo envio.'],\n [/location does not belong to this store/i, 'O local de estoque escolhido não é desta loja.'],\n [/not pending/i, 'Não há cobrança em aberto para registrar neste pedido.'],\n [/not authorized to confirm payment/i, 'Sua conta não tem permissão para registrar o pagamento deste pedido.'],\n]\nexport function errorMessage(error: unknown): string {\n const raw = rawMessage(error)\n for (const [pattern, friendly] of RPC_REFUSAL) if (pattern.test(raw)) return friendly\n return raw\n}\n"]}
@@ -0,0 +1,51 @@
1
+ import { Button } from '@fayz-ai/ui';
2
+ import { jsx, jsxs } from 'react/jsx-runtime';
3
+
4
+ // src/settings/ChoiceCards.tsx
5
+ function ChoiceCards({
6
+ label,
7
+ choices,
8
+ value,
9
+ onChange,
10
+ disabled
11
+ }) {
12
+ return /* @__PURE__ */ jsx("div", { className: "space-y-2 py-3", role: "radiogroup", "aria-label": label, children: choices.map((choice) => {
13
+ const chosen = value === choice.value;
14
+ const Icon = choice.Icon;
15
+ return /* @__PURE__ */ jsxs(
16
+ Button,
17
+ {
18
+ variant: "bare",
19
+ size: "bare",
20
+ type: "button",
21
+ role: "radio",
22
+ "aria-checked": chosen,
23
+ disabled,
24
+ onClick: () => onChange(choice.value),
25
+ 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`,
26
+ children: [
27
+ /* @__PURE__ */ jsx(
28
+ "span",
29
+ {
30
+ "aria-hidden": true,
31
+ className: `mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded-full border ${chosen ? "border-primary" : "border-muted-foreground/40"}`,
32
+ children: chosen && /* @__PURE__ */ jsx("span", { className: "h-2 w-2 rounded-full bg-primary" })
33
+ }
34
+ ),
35
+ /* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1", children: [
36
+ /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2 text-sm font-medium", children: [
37
+ Icon && /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
38
+ choice.label
39
+ ] }),
40
+ /* @__PURE__ */ jsx("span", { className: "mt-0.5 block text-xs text-muted-foreground", children: choice.description })
41
+ ] })
42
+ ]
43
+ },
44
+ choice.value
45
+ );
46
+ }) });
47
+ }
48
+
49
+ export { ChoiceCards };
50
+ //# sourceMappingURL=chunk-4JM32Z7J.js.map
51
+ //# sourceMappingURL=chunk-4JM32Z7J.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/settings/ChoiceCards.tsx"],"names":[],"mappings":";;;;AAuBO,SAAS,WAAA,CAA8B;AAAA,EAC5C,KAAA;AAAA,EAAO,OAAA;AAAA,EAAS,KAAA;AAAA,EAAO,QAAA;AAAA,EAAU;AACnC,CAAA,EAAwB;AACtB,EAAA,uBACE,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,gBAAA,EAAiB,IAAA,EAAK,YAAA,EAAa,YAAA,EAAY,KAAA,EAC3D,QAAA,EAAA,OAAA,CAAQ,GAAA,CAAI,CAAC,MAAA,KAAW;AACvB,IAAA,MAAM,MAAA,GAAS,UAAU,MAAA,CAAO,KAAA;AAChC,IAAA,MAAM,OAAO,MAAA,CAAO,IAAA;AACpB,IAAA,uBACE,IAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QAAO,OAAA,EAAQ,MAAA;AAAA,QAAO,IAAA,EAAK,MAAA;AAAA,QAE1B,IAAA,EAAK,QAAA;AAAA,QACL,IAAA,EAAK,OAAA;AAAA,QACL,cAAA,EAAc,MAAA;AAAA,QACd,QAAA;AAAA,QACA,OAAA,EAAS,MAAM,QAAA,CAAS,MAAA,CAAO,KAAK,CAAA;AAAA,QACpC,SAAA,EAAW,CAAA,4HAAA,EACT,MAAA,GAAS,6BAAA,GAAgC,iCAC3C,CAAA,oBAAA,CAAA;AAAA,QAEA,QAAA,EAAA;AAAA,0BAAA,GAAA;AAAA,YAAC,MAAA;AAAA,YAAA;AAAA,cACC,aAAA,EAAW,IAAA;AAAA,cACX,SAAA,EAAW,CAAA,6EAAA,EACT,MAAA,GAAS,gBAAA,GAAmB,4BAC9B,CAAA,CAAA;AAAA,cAEC,QAAA,EAAA,MAAA,oBAAU,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,iCAAA,EAAkC;AAAA;AAAA,WAC/D;AAAA,0BACA,IAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,gBAAA,EACd,QAAA,EAAA;AAAA,4BAAA,IAAA,CAAC,MAAA,EAAA,EAAK,WAAU,6CAAA,EACb,QAAA,EAAA;AAAA,cAAA,IAAA,oBAAQ,GAAA,CAAC,IAAA,EAAA,EAAK,SAAA,EAAU,wCAAA,EAAyC,CAAA;AAAA,cACjE,MAAA,CAAO;AAAA,aAAA,EACV,CAAA;AAAA,4BACA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,4CAAA,EAA8C,iBAAO,WAAA,EAAY;AAAA,WAAA,EACnF;AAAA;AAAA,OAAA;AAAA,MAxBK,MAAA,CAAO;AAAA,KAyBd;AAAA,EAEJ,CAAC,CAAA,EACH,CAAA;AAEJ","file":"chunk-4JM32Z7J.js","sourcesContent":["import React from 'react'\nimport { Button } from '@fayz-ai/ui'\n\nexport interface Choice<T extends string> {\n value: T\n label: string\n description: string\n /** Optional lucide icon component, rendered before the label. */\n Icon?: React.ComponentType<{ className?: string }>\n}\n\nexport interface ChoiceCardsProps<T extends string> {\n label: string\n choices: ReadonlyArray<Choice<T>>\n value: T | undefined\n onChange: (value: T) => void\n disabled?: boolean\n}\n\n/**\n * Mutually exclusive policies with a paragraph each — a radio, not a dropdown:\n * choosing between two of these needs both on screen at once.\n */\nexport function ChoiceCards<T extends string>({\n label, choices, value, onChange, disabled,\n}: ChoiceCardsProps<T>) {\n return (\n <div className=\"space-y-2 py-3\" role=\"radiogroup\" aria-label={label}>\n {choices.map((choice) => {\n const chosen = value === choice.value\n const Icon = choice.Icon\n return (\n <Button variant=\"bare\" size=\"bare\"\n key={choice.value}\n type=\"button\"\n role=\"radio\"\n aria-checked={chosen}\n disabled={disabled}\n onClick={() => onChange(choice.value)}\n className={`font-normal justify-start whitespace-normal flex w-full items-start gap-3 rounded-lg border p-3 text-left transition-colors ${\n chosen ? 'border-primary bg-primary/5' : 'border-border hover:bg-muted/40'\n } disabled:opacity-60`}\n >\n <span\n aria-hidden\n className={`mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded-full border ${\n chosen ? 'border-primary' : 'border-muted-foreground/40'\n }`}\n >\n {chosen && <span className=\"h-2 w-2 rounded-full bg-primary\" />}\n </span>\n <span className=\"min-w-0 flex-1\">\n <span className=\"flex items-center gap-2 text-sm font-medium\">\n {Icon && <Icon className=\"h-4 w-4 shrink-0 text-muted-foreground\" />}\n {choice.label}\n </span>\n <span className=\"mt-0.5 block text-xs text-muted-foreground\">{choice.description}</span>\n </span>\n </Button>\n )\n })}\n </div>\n )\n}\n"]}
@@ -0,0 +1,132 @@
1
+ import { errorMessage } from './chunk-2MXOKJQO.js';
2
+ import { useState, useEffect } from 'react';
3
+ import { Skeleton, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, Button, Badge } from '@fayz-ai/ui';
4
+ import { jsxs, jsx } from 'react/jsx-runtime';
5
+
6
+ var NO_CATEGORY = "__none__";
7
+ var STATUS_LABEL = {
8
+ active: { label: "\xC0 venda na loja", variant: "success" },
9
+ draft: { label: "Rascunho", variant: "secondary" },
10
+ archived: { label: "Fora da loja", variant: "outline" }
11
+ };
12
+ function ProductListingTab({ item, getProvider }) {
13
+ const catalog = item ?? {};
14
+ const catalogId = catalog.id;
15
+ const [listing, setListing] = useState(void 0);
16
+ const [categories, setCategories] = useState([]);
17
+ const [categoryId, setCategoryId] = useState(NO_CATEGORY);
18
+ const [busy, setBusy] = useState(false);
19
+ const [error, setError] = useState(null);
20
+ useEffect(() => {
21
+ if (!catalogId) {
22
+ setListing(null);
23
+ return;
24
+ }
25
+ let alive = true;
26
+ setListing(void 0);
27
+ const provider = getProvider();
28
+ const lookup = provider.getProductByCatalogId ? provider.getProductByCatalogId(catalogId) : Promise.resolve(null);
29
+ Promise.all([lookup, provider.listCategories().catch(() => [])]).then(([found, cats]) => {
30
+ if (!alive) return;
31
+ setListing(found);
32
+ setCategories(cats);
33
+ setCategoryId(found?.categoryId ?? NO_CATEGORY);
34
+ }).catch((err) => {
35
+ if (alive) {
36
+ setListing(null);
37
+ setError(errorMessage(err));
38
+ }
39
+ });
40
+ return () => {
41
+ alive = false;
42
+ };
43
+ }, [catalogId]);
44
+ async function publish() {
45
+ if (!catalogId || !catalog.name) return;
46
+ setBusy(true);
47
+ setError(null);
48
+ try {
49
+ const created = await getProvider().createProduct({
50
+ catalogProductId: catalogId,
51
+ name: catalog.name,
52
+ description: catalog.description ?? void 0,
53
+ sku: catalog.sku ?? void 0,
54
+ price: Number(catalog.salePrice ?? catalog.price ?? 0),
55
+ // An inactive record goes in as a draft: listed, not sold, until the
56
+ // record's Ativo switch is turned on.
57
+ status: catalog.isActive === false ? "draft" : "active",
58
+ categoryId: categoryId === NO_CATEGORY ? void 0 : categoryId
59
+ });
60
+ setListing(created);
61
+ } catch (err) {
62
+ setError(errorMessage(err));
63
+ } finally {
64
+ setBusy(false);
65
+ }
66
+ }
67
+ async function changeCategory(next) {
68
+ if (!listing) return;
69
+ const previous = categoryId;
70
+ setCategoryId(next);
71
+ setError(null);
72
+ try {
73
+ const updated = await getProvider().updateProduct(listing.id, { categoryId: next === NO_CATEGORY ? null : next });
74
+ setListing(updated);
75
+ } catch (err) {
76
+ setCategoryId(previous);
77
+ setError(errorMessage(err));
78
+ }
79
+ }
80
+ if (listing === void 0) {
81
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-3", "aria-busy": "true", children: [
82
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-48" }),
83
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-24 w-full" })
84
+ ] });
85
+ }
86
+ const categoryPicker = /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
87
+ /* @__PURE__ */ jsx("p", { className: "text-xs font-medium text-muted-foreground", children: "Categoria na loja" }),
88
+ /* @__PURE__ */ jsxs(Select, { value: categoryId, onValueChange: (v) => {
89
+ if (listing) void changeCategory(v);
90
+ else setCategoryId(v);
91
+ }, children: [
92
+ /* @__PURE__ */ jsx(SelectTrigger, { className: "w-72", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Sem categoria" }) }),
93
+ /* @__PURE__ */ jsxs(SelectContent, { children: [
94
+ /* @__PURE__ */ jsx(SelectItem, { value: NO_CATEGORY, children: "Sem categoria" }),
95
+ categories.map((c) => /* @__PURE__ */ jsx(SelectItem, { value: c.id, children: c.name }, c.id))
96
+ ] })
97
+ ] })
98
+ ] });
99
+ if (!listing) {
100
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
101
+ /* @__PURE__ */ jsxs("div", { children: [
102
+ /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold", children: "Loja e delivery" }),
103
+ /* @__PURE__ */ jsxs("p", { className: "mt-0.5 text-xs text-muted-foreground", children: [
104
+ "Este produto ainda n\xE3o est\xE1 na loja. Ao colocar, ele aparece no site e no delivery com o nome, o pre\xE7o e a descri\xE7\xE3o deste cadastro",
105
+ catalog.isActive === false ? " \u2014 como rascunho, at\xE9 o produto ser ativado" : "",
106
+ "."
107
+ ] })
108
+ ] }),
109
+ categoryPicker,
110
+ error && /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: error }),
111
+ /* @__PURE__ */ jsx(Button, { onClick: () => {
112
+ void publish();
113
+ }, disabled: busy || !catalog.name, children: busy ? "Colocando\u2026" : "Colocar na loja" })
114
+ ] });
115
+ }
116
+ const status = STATUS_LABEL[listing.status] ?? { label: listing.status, variant: "outline" };
117
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
118
+ /* @__PURE__ */ jsxs("div", { children: [
119
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
120
+ /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold", children: "Loja e delivery" }),
121
+ /* @__PURE__ */ jsx(Badge, { variant: status.variant, children: status.label })
122
+ ] }),
123
+ /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-xs text-muted-foreground", children: "Nome, pre\xE7o e descri\xE7\xE3o v\xEAm deste cadastro. Para tirar o produto da loja, desative-o no cadastro; ativ\xE1-lo de novo o devolve \xE0 venda. Fotos ficam na aba Conte\xFAdo." })
124
+ ] }),
125
+ categoryPicker,
126
+ error && /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: error })
127
+ ] });
128
+ }
129
+
130
+ export { ProductListingTab };
131
+ //# sourceMappingURL=chunk-53Y6VLAW.js.map
132
+ //# sourceMappingURL=chunk-53Y6VLAW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/views/ProductListingTab.tsx"],"names":[],"mappings":"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","file":"chunk-53Y6VLAW.js","sourcesContent":["import React, { useEffect, useState } from 'react'\nimport { Badge, Button, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Skeleton } from '@fayz-ai/ui'\nimport type { Category, Product, ShopProvider } from '@fayz-ai/shop'\nimport { errorMessage } from '../settings/error-message'\n\nconst NO_CATEGORY = '__none__'\n\n/** What the tab reads off the stock's product record. */\ninterface CatalogItem {\n id?: string\n name?: string\n description?: string | null\n sku?: string | null\n salePrice?: number | null\n price?: number | null\n isActive?: boolean\n}\n\nconst STATUS_LABEL: Record<string, { label: string; variant: 'success' | 'secondary' | 'outline' }> = {\n active: { label: 'À venda na loja', variant: 'success' },\n draft: { label: 'Rascunho', variant: 'secondary' },\n archived: { label: 'Fora da loja', variant: 'outline' },\n}\n\n/**\n * Loja — whether a CATALOGUE product is sold in the store, and the one thing\n * the listing owns that the record does not: its category in the store menu.\n *\n * Mounted on the product record of whichever plugin owns the catalogue (stock,\n * in the Control app), where the shop's own Produtos screen is off. Without it\n * a product created in the stock had no way into the store: the listing row\n * (`plg_shop_products`) was only ever born from the shop's screen.\n *\n * Name, price, SKU and description are NOT edited here: the database mirrors\n * them from the record both ways, and so does the status — the record's Ativo\n * switch is what takes a product out of the store and puts it back.\n */\nexport function ProductListingTab({ item, getProvider }: {\n item: unknown\n getProvider: () => ShopProvider\n}) {\n const catalog = (item ?? {}) as CatalogItem\n const catalogId = catalog.id\n const [listing, setListing] = useState<Product | null | undefined>(undefined)\n const [categories, setCategories] = useState<Category[]>([])\n const [categoryId, setCategoryId] = useState<string>(NO_CATEGORY)\n const [busy, setBusy] = useState(false)\n const [error, setError] = useState<string | null>(null)\n\n useEffect(() => {\n if (!catalogId) { setListing(null); return }\n let alive = true\n setListing(undefined)\n const provider = getProvider()\n const lookup = provider.getProductByCatalogId\n ? provider.getProductByCatalogId(catalogId)\n : Promise.resolve(null)\n Promise.all([lookup, provider.listCategories().catch(() => [] as Category[])])\n .then(([found, cats]) => {\n if (!alive) return\n setListing(found)\n setCategories(cats)\n setCategoryId(found?.categoryId ?? NO_CATEGORY)\n })\n .catch((err: unknown) => { if (alive) { setListing(null); setError(errorMessage(err)) } })\n return () => { alive = false }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [catalogId])\n\n async function publish() {\n if (!catalogId || !catalog.name) return\n setBusy(true)\n setError(null)\n try {\n const created = await getProvider().createProduct({\n catalogProductId: catalogId,\n name: catalog.name,\n description: catalog.description ?? undefined,\n sku: catalog.sku ?? undefined,\n price: Number(catalog.salePrice ?? catalog.price ?? 0),\n // An inactive record goes in as a draft: listed, not sold, until the\n // record's Ativo switch is turned on.\n status: catalog.isActive === false ? 'draft' : 'active',\n categoryId: categoryId === NO_CATEGORY ? undefined : categoryId,\n })\n setListing(created)\n } catch (err) {\n setError(errorMessage(err))\n } finally {\n setBusy(false)\n }\n }\n\n async function changeCategory(next: string) {\n if (!listing) return\n const previous = categoryId\n setCategoryId(next)\n setError(null)\n try {\n const updated = await getProvider().updateProduct(listing.id, { categoryId: next === NO_CATEGORY ? null : next })\n setListing(updated)\n } catch (err) {\n setCategoryId(previous)\n setError(errorMessage(err))\n }\n }\n\n if (listing === undefined) {\n return (\n <div className=\"space-y-3\" aria-busy=\"true\">\n <Skeleton className=\"h-5 w-48\" />\n <Skeleton className=\"h-24 w-full\" />\n </div>\n )\n }\n\n const categoryPicker = (\n <div className=\"space-y-1.5\">\n <p className=\"text-xs font-medium text-muted-foreground\">Categoria na loja</p>\n <Select value={categoryId} onValueChange={(v) => { if (listing) void changeCategory(v); else setCategoryId(v) }}>\n <SelectTrigger className=\"w-72\"><SelectValue placeholder=\"Sem categoria\" /></SelectTrigger>\n <SelectContent>\n <SelectItem value={NO_CATEGORY}>Sem categoria</SelectItem>\n {categories.map((c) => <SelectItem key={c.id} value={c.id}>{c.name}</SelectItem>)}\n </SelectContent>\n </Select>\n </div>\n )\n\n if (!listing) {\n return (\n <div className=\"space-y-4\">\n <div>\n <h3 className=\"text-sm font-semibold\">Loja e delivery</h3>\n <p className=\"mt-0.5 text-xs text-muted-foreground\">\n Este produto ainda não está na loja. Ao colocar, ele aparece no site e no delivery com o nome, o preço e a\n descrição deste cadastro{catalog.isActive === false ? ' — como rascunho, até o produto ser ativado' : ''}.\n </p>\n </div>\n {categoryPicker}\n {error && <p className=\"text-sm text-destructive\">{error}</p>}\n <Button onClick={() => { void publish() }} disabled={busy || !catalog.name}>\n {busy ? 'Colocando…' : 'Colocar na loja'}\n </Button>\n </div>\n )\n }\n\n const status = STATUS_LABEL[listing.status] ?? { label: listing.status, variant: 'outline' as const }\n return (\n <div className=\"space-y-4\">\n <div>\n <div className=\"flex items-center gap-2\">\n <h3 className=\"text-sm font-semibold\">Loja e delivery</h3>\n <Badge variant={status.variant}>{status.label}</Badge>\n </div>\n <p className=\"mt-0.5 text-xs text-muted-foreground\">\n Nome, preço e descrição vêm deste cadastro. Para tirar o produto da loja, desative-o no cadastro; ativá-lo de\n novo o devolve à venda. Fotos ficam na aba Conteúdo.\n </p>\n </div>\n {categoryPicker}\n {error && <p className=\"text-sm text-destructive\">{error}</p>}\n </div>\n )\n}\n"]}
@@ -0,0 +1,24 @@
1
+ import { currentAppPath } from '@fayz-ai/core';
2
+
3
+ // src/data/registry-routes.ts
4
+ var SHIPPING_SETTINGS_TAB = "shop-shipping";
5
+ var SHIPPING_SETTINGS_ROUTE = `/settings/${SHIPPING_SETTINGS_TAB}`;
6
+ var PROPERTIES = "_properties";
7
+ function shippingRegistryPath(registryId) {
8
+ return `${SHIPPING_SETTINGS_ROUTE}/${PROPERTIES}/${registryId}`;
9
+ }
10
+ function shippingRecordPath(registryId, recordId, mode = "edit") {
11
+ const base = `${shippingRegistryPath(registryId)}/${recordId}`;
12
+ return mode === "edit" ? `${base}/edit` : base;
13
+ }
14
+ function shippingRegistryIdFromHash(hash) {
15
+ const raw = hash ?? currentAppPath();
16
+ const path = raw.startsWith("#") ? raw.slice(1) : raw;
17
+ const marker = `${SHIPPING_SETTINGS_ROUTE}/${PROPERTIES}/`;
18
+ if (!path.startsWith(marker)) return null;
19
+ return path.slice(marker.length).split("/")[0] || null;
20
+ }
21
+
22
+ export { shippingRecordPath, shippingRegistryIdFromHash, shippingRegistryPath };
23
+ //# sourceMappingURL=chunk-6V2VAUWP.js.map
24
+ //# sourceMappingURL=chunk-6V2VAUWP.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/data/registry-routes.ts"],"names":[],"mappings":";;;AAEO,IAAM,qBAAA,GAAwB,eAAA;AAE9B,IAAM,uBAAA,GAA0B,aAAa,qBAAqB,CAAA,CAAA;AAGzE,IAAM,UAAA,GAAa,aAAA;AAEZ,SAAS,qBAAqB,UAAA,EAA4B;AAC/D,EAAA,OAAO,CAAA,EAAG,uBAAuB,CAAA,CAAA,EAAI,UAAU,IAAI,UAAU,CAAA,CAAA;AAC/D;AASO,SAAS,kBAAA,CAAmB,UAAA,EAAoB,QAAA,EAAkB,IAAA,GAAwB,MAAA,EAAgB;AAC/G,EAAA,MAAM,OAAO,CAAA,EAAG,oBAAA,CAAqB,UAAU,CAAC,IAAI,QAAQ,CAAA,CAAA;AAC5D,EAAA,OAAO,IAAA,KAAS,MAAA,GAAS,CAAA,EAAG,IAAI,CAAA,KAAA,CAAA,GAAU,IAAA;AAC5C;AASO,SAAS,2BAA2B,IAAA,EAA8B;AACvE,EAAA,MAAM,GAAA,GAAM,QAAQ,cAAA,EAAe;AACnC,EAAA,MAAM,IAAA,GAAO,IAAI,UAAA,CAAW,GAAG,IAAI,GAAA,CAAI,KAAA,CAAM,CAAC,CAAA,GAAI,GAAA;AAClD,EAAA,MAAM,MAAA,GAAS,CAAA,EAAG,uBAAuB,CAAA,CAAA,EAAI,UAAU,CAAA,CAAA,CAAA;AACvD,EAAA,IAAI,CAAC,IAAA,CAAK,UAAA,CAAW,MAAM,GAAG,OAAO,IAAA;AACrC,EAAA,OAAO,IAAA,CAAK,MAAM,MAAA,CAAO,MAAM,EAAE,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,CAAA,IAAK,IAAA;AACpD","file":"chunk-6V2VAUWP.js","sourcesContent":["import { currentAppPath } from '@fayz-ai/core'\n/** The Entrega settings tab id, as the manifest declares it. */\nexport const SHIPPING_SETTINGS_TAB = 'shop-shipping'\n\nexport const SHIPPING_SETTINGS_ROUTE = `/settings/${SHIPPING_SETTINGS_TAB}`\n\n/** The shell's own prefix for a registry inside a plugin settings tab. */\nconst PROPERTIES = '_properties'\n\nexport function shippingRegistryPath(registryId: string): string {\n return `${SHIPPING_SETTINGS_ROUTE}/${PROPERTIES}/${registryId}`\n}\n\n/**\n * Straight to the form of ONE record.\n *\n * A summary row that names a place and then lands on the list of places makes\n * the reader find it again, open it, and click \"editar\" — three steps to reach\n * what the row was already pointing at.\n */\nexport function shippingRecordPath(registryId: string, recordId: string, mode: 'view' | 'edit' = 'edit'): string {\n const base = `${shippingRegistryPath(registryId)}/${recordId}`\n return mode === 'edit' ? `${base}/edit` : base\n}\n\n/**\n * The registry the URL is asking for, or null for the tab's summary.\n *\n * Returns the raw id rather than validating against a list — the registry lookup\n * is the only list, and a second one here is what drifted when `zonas` was\n * renamed.\n */\nexport function shippingRegistryIdFromHash(hash?: string): string | null {\n const raw = hash ?? currentAppPath()\n const path = raw.startsWith('#') ? raw.slice(1) : raw\n const marker = `${SHIPPING_SETTINGS_ROUTE}/${PROPERTIES}/`\n if (!path.startsWith(marker)) return null\n return path.slice(marker.length).split('/')[0] || null\n}\n"]}
@@ -0,0 +1,59 @@
1
+ import { Skeleton } from '@fayz-ai/ui';
2
+ import { AlertTriangle, Loader2, Check } from 'lucide-react';
3
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
4
+
5
+ // src/settings/SettingsState.tsx
6
+ function SettingsState({
7
+ loading,
8
+ saving,
9
+ error,
10
+ loadError,
11
+ supported,
12
+ children
13
+ }) {
14
+ if (!supported) {
15
+ return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-amber-500/30 bg-amber-500/5 p-4 text-sm", children: [
16
+ /* @__PURE__ */ jsxs("p", { className: "flex items-center gap-2 font-medium text-amber-700 dark:text-amber-500", children: [
17
+ /* @__PURE__ */ jsx(AlertTriangle, { className: "h-4 w-4 shrink-0" }),
18
+ "Este app n\xE3o guarda as configura\xE7\xF5es da loja"
19
+ ] }),
20
+ /* @__PURE__ */ jsxs("p", { className: "mt-1 text-muted-foreground", children: [
21
+ "O provedor de loja montado aqui n\xE3o implementa ",
22
+ /* @__PURE__ */ jsx("code", { children: "getStoreSettings" }),
23
+ ". As op\xE7\xF5es abaixo n\xE3o seriam salvas, ent\xE3o n\xE3o s\xE3o mostradas."
24
+ ] })
25
+ ] });
26
+ }
27
+ if (loading) {
28
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
29
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-28 w-full rounded-lg" }),
30
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-40 w-full rounded-lg" })
31
+ ] });
32
+ }
33
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
34
+ loadError && /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-destructive/30 bg-destructive/5 p-3 text-sm", children: [
35
+ /* @__PURE__ */ jsxs("p", { className: "flex items-center gap-2 font-medium text-destructive", children: [
36
+ /* @__PURE__ */ jsx(AlertTriangle, { className: "h-4 w-4 shrink-0" }),
37
+ "N\xE3o foi poss\xEDvel carregar as configura\xE7\xF5es da loja"
38
+ ] }),
39
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-muted-foreground", children: "O que aparece abaixo s\xE3o os valores padr\xE3o, n\xE3o as suas escolhas. Recarregue a p\xE1gina antes de alterar algo \u2014 salvar agora sobrescreveria configura\xE7\xF5es que n\xE3o conseguimos ler." }),
40
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: loadError })
41
+ ] }),
42
+ children,
43
+ /* @__PURE__ */ jsx("div", { className: "flex min-h-5 items-center gap-1.5 px-1 text-xs text-muted-foreground", children: error ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1.5 text-destructive", children: [
44
+ /* @__PURE__ */ jsx(AlertTriangle, { className: "h-3.5 w-3.5 shrink-0" }),
45
+ "N\xE3o foi poss\xEDvel salvar: ",
46
+ error
47
+ ] }) : saving ? /* @__PURE__ */ jsxs(Fragment, { children: [
48
+ /* @__PURE__ */ jsx(Loader2, { className: "h-3.5 w-3.5 shrink-0 animate-spin" }),
49
+ "Salvando\u2026"
50
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
51
+ /* @__PURE__ */ jsx(Check, { className: "h-3.5 w-3.5 shrink-0" }),
52
+ "As altera\xE7\xF5es s\xE3o salvas automaticamente."
53
+ ] }) })
54
+ ] });
55
+ }
56
+
57
+ export { SettingsState };
58
+ //# sourceMappingURL=chunk-FQQMEM26.js.map
59
+ //# sourceMappingURL=chunk-FQQMEM26.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/settings/SettingsState.tsx"],"names":[],"mappings":";;;;;AAkBO,SAAS,aAAA,CAAc;AAAA,EAC5B,OAAA;AAAA,EACA,MAAA;AAAA,EACA,KAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAAA,EAUG;AACD,EAAA,IAAI,CAAC,SAAA,EAAW;AACd,IAAA,uBACE,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,kEAAA,EACb,QAAA,EAAA;AAAA,sBAAA,IAAA,CAAC,GAAA,EAAA,EAAE,WAAU,wEAAA,EACX,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,aAAA,EAAA,EAAc,WAAU,kBAAA,EAAmB,CAAA;AAAA,QAAE;AAAA,OAAA,EAEhD,CAAA;AAAA,sBACA,IAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,4BAAA,EAA6B,QAAA,EAAA;AAAA,QAAA,oDAAA;AAAA,wBACO,GAAA,CAAC,UAAK,QAAA,EAAA,kBAAA,EAAgB,CAAA;AAAA,QAAO;AAAA,OAAA,EAE9E;AAAA,KAAA,EACF,CAAA;AAAA,EAEJ;AAEA,EAAA,IAAI,OAAA,EAAS;AACX,IAAA,uBACE,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,WAAA,EACb,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,QAAA,EAAA,EAAS,WAAU,wBAAA,EAAyB,CAAA;AAAA,sBAC7C,GAAA,CAAC,QAAA,EAAA,EAAS,SAAA,EAAU,wBAAA,EAAyB;AAAA,KAAA,EAC/C,CAAA;AAAA,EAEJ;AAEA,EAAA,uBACE,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,WAAA,EACZ,QAAA,EAAA;AAAA,IAAA,SAAA,oBACC,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,sEAAA,EACb,QAAA,EAAA;AAAA,sBAAA,IAAA,CAAC,GAAA,EAAA,EAAE,WAAU,sDAAA,EACX,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,aAAA,EAAA,EAAc,WAAU,kBAAA,EAAmB,CAAA;AAAA,QAAE;AAAA,OAAA,EAEhD,CAAA;AAAA,sBACA,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,4BAAA,EAA6B,QAAA,EAAA,4MAAA,EAG1C,CAAA;AAAA,sBACA,GAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,oCAAA,EAAsC,QAAA,EAAA,SAAA,EAAU;AAAA,KAAA,EAC/D,CAAA;AAAA,IAED,QAAA;AAAA,oBACD,GAAA,CAAC,SAAI,SAAA,EAAU,sEAAA,EACZ,kCACC,IAAA,CAAC,MAAA,EAAA,EAAK,WAAU,4CAAA,EACd,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,aAAA,EAAA,EAAc,WAAU,sBAAA,EAAuB,CAAA;AAAA,MAAE,iCAAA;AAAA,MACxB;AAAA,KAAA,EAC5B,CAAA,GACE,yBACF,IAAA,CAAA,QAAA,EAAA,EACE,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,OAAA,EAAA,EAAQ,WAAU,mCAAA,EAAoC,CAAA;AAAA,MAAE;AAAA,KAAA,EAE3D,oBAEA,IAAA,CAAA,QAAA,EAAA,EACE,QAAA,EAAA;AAAA,sBAAA,GAAA,CAAC,KAAA,EAAA,EAAM,WAAU,sBAAA,EAAuB,CAAA;AAAA,MAAE;AAAA,KAAA,EAE5C,CAAA,EAEJ;AAAA,GAAA,EACF,CAAA;AAEJ","file":"chunk-FQQMEM26.js","sourcesContent":["import React from 'react'\nimport { Skeleton } from '@fayz-ai/ui'\nimport { AlertTriangle, Check, Loader2 } from 'lucide-react'\n\n/**\n * The three things every Commerce settings screen has to say, said once.\n *\n * Loading, saving and refused are not decoration on a settings screen that\n * writes to a server: without them a merchant cannot tell \"salvo\" from \"não\n * chegou\", and the whole reason these screens exist is that the previous ones\n * silently kept everything in React state. The saving/saved line is what\n * replaces the Save button the auto-save design removes.\n *\n * `supported: false` is its own case, and deliberately loud: it means the\n * mounted shop provider has no store-settings methods at all, so every control\n * below would be a toggle wired to nothing — which is exactly the bug this wave\n * fixes and must not be reintroduced silently by a bespoke provider.\n */\nexport function SettingsState({\n loading,\n saving,\n error,\n loadError,\n supported,\n children,\n}: {\n loading: boolean\n saving: boolean\n error: string | null\n /** The READ failed. Opposite copy from `error`, and shown ABOVE the controls\n * rather than below: what is on screen is defaults, not the store's settings,\n * and that has to be read before anything is clicked. */\n loadError?: string | null\n supported: boolean\n children: React.ReactNode\n}) {\n if (!supported) {\n return (\n <div className=\"rounded-lg border border-amber-500/30 bg-amber-500/5 p-4 text-sm\">\n <p className=\"flex items-center gap-2 font-medium text-amber-700 dark:text-amber-500\">\n <AlertTriangle className=\"h-4 w-4 shrink-0\" />\n Este app não guarda as configurações da loja\n </p>\n <p className=\"mt-1 text-muted-foreground\">\n O provedor de loja montado aqui não implementa <code>getStoreSettings</code>. As opções\n abaixo não seriam salvas, então não são mostradas.\n </p>\n </div>\n )\n }\n\n if (loading) {\n return (\n <div className=\"space-y-4\">\n <Skeleton className=\"h-28 w-full rounded-lg\" />\n <Skeleton className=\"h-40 w-full rounded-lg\" />\n </div>\n )\n }\n\n return (\n <div className=\"space-y-4\">\n {loadError && (\n <div className=\"rounded-lg border border-destructive/30 bg-destructive/5 p-3 text-sm\">\n <p className=\"flex items-center gap-2 font-medium text-destructive\">\n <AlertTriangle className=\"h-4 w-4 shrink-0\" />\n Não foi possível carregar as configurações da loja\n </p>\n <p className=\"mt-1 text-muted-foreground\">\n O que aparece abaixo são os valores padrão, não as suas escolhas. Recarregue a página\n antes de alterar algo — salvar agora sobrescreveria configurações que não conseguimos ler.\n </p>\n <p className=\"mt-1 text-xs text-muted-foreground\">{loadError}</p>\n </div>\n )}\n {children}\n <div className=\"flex min-h-5 items-center gap-1.5 px-1 text-xs text-muted-foreground\">\n {error ? (\n <span className=\"flex items-center gap-1.5 text-destructive\">\n <AlertTriangle className=\"h-3.5 w-3.5 shrink-0\" />\n Não foi possível salvar: {error}\n </span>\n ) : saving ? (\n <>\n <Loader2 className=\"h-3.5 w-3.5 shrink-0 animate-spin\" />\n Salvando…\n </>\n ) : (\n <>\n <Check className=\"h-3.5 w-3.5 shrink-0\" />\n As alterações são salvas automaticamente.\n </>\n )}\n </div>\n </div>\n )\n}\n"]}