@ecomiq/storefront 2.1.4 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (310) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +150 -103
  3. package/dist/account-Dx4e3syi.js +258 -0
  4. package/dist/account-forms-AVk71ko7.js +39 -0
  5. package/dist/account-forms.d.ts +13 -0
  6. package/dist/account.d.ts +240 -0
  7. package/dist/address-defaults-BqjRhS82.js +14 -0
  8. package/dist/address-defaults.d.ts +11 -0
  9. package/dist/analytics/analytics-CG1Qagwl.js +148 -0
  10. package/dist/analytics/analytics.d.ts +1 -0
  11. package/dist/analytics/config-DJr-GRhs.js +62 -0
  12. package/dist/analytics/config.d.ts +22 -0
  13. package/dist/analytics/consent-B13rBpBs.js +57 -0
  14. package/dist/analytics/consent-banner-9QvRRy8v.js +239 -0
  15. package/dist/analytics/consent-banner.d.ts +20 -0
  16. package/dist/analytics/cookies-pLozllyB.js +100 -0
  17. package/dist/analytics/cookies.d.ts +6 -0
  18. package/dist/analytics/destinations-iECrlLIr.js +144 -0
  19. package/dist/analytics/events-Dt81tIp1.js +102 -0
  20. package/dist/analytics/events.d.ts +51 -0
  21. package/dist/analytics/tracker-p4yaoOyk.js +51 -0
  22. package/dist/api-cache-DsuIn5hX.js +159 -0
  23. package/dist/bank-accounts-DlEczQQ5.js +81 -0
  24. package/dist/bank-accounts.d.ts +4 -0
  25. package/dist/captcha-DAqaIx8m.js +117 -0
  26. package/dist/captcha.d.ts +34 -0
  27. package/dist/cart-D7DxZ2lD.js +30 -0
  28. package/dist/cart-actions-Bsub_FFG.js +116 -0
  29. package/dist/cart-actions.d.ts +15 -0
  30. package/dist/cart-drawer-B7PPsR69.js +22 -0
  31. package/dist/cart-drawer.d.ts +9 -0
  32. package/dist/cart-form-y9P1r_EX.js +81 -0
  33. package/dist/cart-form.d.ts +24 -0
  34. package/dist/cart-summary-ur2VWKr-.js +89 -0
  35. package/dist/cart-summary.d.ts +31 -0
  36. package/dist/cart.d.ts +4 -0
  37. package/dist/catalog-7gJ-l5hW.js +67 -0
  38. package/dist/catalog-hooks-B7ZP4wYY.js +312 -0
  39. package/dist/catalog-hooks.d.ts +111 -0
  40. package/dist/catalog.d.ts +5 -0
  41. package/dist/checkout-DVWSXANi.js +474 -0
  42. package/dist/checkout-form-CbOIdENC.js +131 -0
  43. package/dist/checkout-form.d.ts +20 -0
  44. package/dist/checkout.d.ts +86 -0
  45. package/dist/complaint-book-BvwLvfx0.js +117 -0
  46. package/dist/complaint-book.d.ts +62 -0
  47. package/dist/culqi-authentication-BGr20vAJ.js +204 -0
  48. package/dist/culqi-authentication.d.ts +15 -0
  49. package/dist/culqi-checkout-CTXpKgp_.js +55 -0
  50. package/dist/culqi-three-ds-HP3mfrvV.js +33 -0
  51. package/dist/culqi-three-ds.d.ts +29 -0
  52. package/dist/customer-avatar-CJXSDroK.js +12 -0
  53. package/dist/customer-avatar.d.ts +5 -0
  54. package/dist/customer-cookies-DHOgFAMV.js +45 -0
  55. package/dist/customer-csrf-C1oDX-Py.js +17 -0
  56. package/dist/customer-csrf.d.ts +3 -0
  57. package/dist/customer-document-fields-C1K-_DAD.js +70 -0
  58. package/dist/customer-document-fields.d.ts +9 -0
  59. package/dist/customer-login-form-C7AC6vXd.js +144 -0
  60. package/dist/customer-login-form.d.ts +17 -0
  61. package/dist/customer-registration-form-BEm_NEfP.js +93 -0
  62. package/dist/customer-registration-form.d.ts +8 -0
  63. package/dist/document-url-CGsAl5Tf.js +9 -0
  64. package/dist/documents-T1mzc_j8.js +38 -0
  65. package/dist/documents.d.ts +16 -0
  66. package/dist/entries/account.d.ts +11 -0
  67. package/dist/entries/account.js +10 -0
  68. package/dist/entries/analytics.d.ts +6 -0
  69. package/dist/entries/analytics.js +5 -0
  70. package/dist/entries/cart.d.ts +8 -0
  71. package/dist/entries/cart.js +7 -0
  72. package/dist/entries/checkout.d.ts +12 -0
  73. package/dist/entries/checkout.js +11 -0
  74. package/dist/entries/order.d.ts +11 -0
  75. package/dist/entries/order.js +11 -0
  76. package/dist/favicon-YpyhVJ9H.js +28 -0
  77. package/dist/favicon.d.ts +4 -0
  78. package/dist/form-BtQcbXlJ.js +18 -0
  79. package/dist/form-contracts-BNpHaTGJ.js +166 -0
  80. package/dist/form-contracts.d.ts +42 -0
  81. package/dist/form.d.ts +3 -0
  82. package/dist/hidden-CCWtOWKR.js +3 -0
  83. package/dist/hidden.d.ts +4 -0
  84. package/dist/index.d.ts +50 -0
  85. package/dist/index.js +50 -0
  86. package/dist/invoice-fields-BG0HjL6T.js +103 -0
  87. package/dist/invoice-fields.d.ts +39 -0
  88. package/dist/links-kFxBZfdb.js +96 -0
  89. package/dist/links.d.ts +21 -0
  90. package/dist/mercadopago-checkout-DC7RXa8k.js +27 -0
  91. package/dist/mercadopago-dialog-UTQev0MG.js +180 -0
  92. package/dist/mercadopago-dialog.d.ts +21 -0
  93. package/dist/money-DtGOtDri.js +32 -0
  94. package/dist/money.d.ts +1 -0
  95. package/dist/optimistic-cart-BveVOHuh.js +53 -0
  96. package/dist/optimistic-cart.d.ts +16 -0
  97. package/dist/order-display-DTt5WBbc.js +112 -0
  98. package/dist/order-display.d.ts +20 -0
  99. package/dist/order-draft-DxV1Uhm3.js +38 -0
  100. package/dist/order-draft.d.ts +16 -0
  101. package/dist/order-pages-Dm6l5m0m.js +38 -0
  102. package/dist/order-pages.d.ts +12 -0
  103. package/dist/order-payment-continuation-D_d5PGA4.js +212 -0
  104. package/dist/order-payment-continuation.d.ts +10 -0
  105. package/dist/order-payment-in-review-x4gdLFHZ.js +65 -0
  106. package/dist/order-payment-in-review.d.ts +5 -0
  107. package/dist/order-status-BJXLJwxq.js +162 -0
  108. package/dist/order-status.d.ts +89 -0
  109. package/dist/order-view-9IlBg5AF.js +62 -0
  110. package/dist/order-view.d.ts +12 -0
  111. package/dist/page-action-Ctkf4xC6.js +7 -0
  112. package/dist/page-seo-a5FJl8x5.js +262 -0
  113. package/dist/page-seo.d.ts +34 -0
  114. package/dist/pages-Ca_Gt6mq.js +150 -0
  115. package/dist/pages.d.ts +45 -0
  116. package/dist/payment-dialog-frame-B-Q_xQ94.js +57 -0
  117. package/dist/payment-logo-BoPaGJc_.js +46 -0
  118. package/dist/payment-logo-svgs-By9lDTLK.js +20 -0
  119. package/dist/payment-logo.d.ts +11 -0
  120. package/dist/payment-logos-BYvdwYyJ.js +23 -0
  121. package/dist/payment-methods-B8ocTgFZ.js +73 -0
  122. package/dist/payment-methods.d.ts +58 -0
  123. package/dist/payment-return-5cjypwIw.js +7 -0
  124. package/dist/place-CmW4hBWY.js +13 -0
  125. package/dist/place.d.ts +4 -0
  126. package/dist/preview-BiIBif3C.js +427 -0
  127. package/dist/preview-address-Cf0sJ-9p.js +21 -0
  128. package/dist/preview-cart-Dg2CVktS.js +376 -0
  129. package/dist/product-preview-BspMAecJ.js +51 -0
  130. package/dist/product-preview.d.ts +5 -0
  131. package/dist/product-variants-BNDHvs1y.js +46 -0
  132. package/dist/product-variants.d.ts +12 -0
  133. package/dist/public-pages-XtwlaLwt.js +194 -0
  134. package/dist/public-pages.d.ts +67 -0
  135. package/dist/registration-CpDcv8ql.js +91 -0
  136. package/dist/registration.d.ts +12 -0
  137. package/dist/request-security-CRsRMgwj.js +76 -0
  138. package/dist/rich-text-M-Ju8RL4.js +9 -0
  139. package/dist/rich-text.d.ts +5 -0
  140. package/dist/route-text-DcJw2SsK.js +9 -0
  141. package/dist/route-text.d.ts +4 -0
  142. package/dist/section-preview-CmsMl3yu.js +83 -0
  143. package/dist/section-preview.d.ts +12 -0
  144. package/dist/sections/account-addresses.d.ts +18 -0
  145. package/dist/sections/account-addresses.js +375 -0
  146. package/dist/sections/account-order.d.ts +12 -0
  147. package/dist/sections/account-order.js +592 -0
  148. package/dist/sections/account-orders.d.ts +8 -0
  149. package/dist/sections/account-orders.js +359 -0
  150. package/dist/sections/account-profile.d.ts +16 -0
  151. package/dist/sections/account-profile.js +123 -0
  152. package/dist/sections/checkout.d.ts +24 -0
  153. package/dist/sections/checkout.js +963 -0
  154. package/dist/sections/complaint-book.d.ts +8 -0
  155. package/dist/sections/complaint-book.js +538 -0
  156. package/dist/sections/design-system.d.ts +1 -0
  157. package/dist/sections/design-system.js +310 -0
  158. package/dist/sections/draft-invoice.d.ts +20 -0
  159. package/dist/sections/draft-invoice.js +158 -0
  160. package/dist/sections/order-tracking.d.ts +19 -0
  161. package/dist/sections/order-tracking.js +141 -0
  162. package/dist/sections-CNUMWTF_.js +77 -0
  163. package/dist/sections.d.ts +19 -0
  164. package/dist/seo-GpDRhAAA.js +78 -0
  165. package/dist/session-CKvmFJyg.js +379 -0
  166. package/dist/session.d.ts +24 -0
  167. package/dist/settings-B0NO2A6Y.js +78 -0
  168. package/dist/settings.d.ts +51 -0
  169. package/dist/source-marker-DhqSkW7n.js +4 -0
  170. package/dist/sources-B-3JFJfb.js +46 -0
  171. package/dist/sources.d.ts +7 -0
  172. package/dist/store-8Q-_LFrQ.js +152 -0
  173. package/dist/store-contact--hY6CoFb.js +19 -0
  174. package/dist/store-contact.d.ts +6 -0
  175. package/dist/store.d.ts +17 -0
  176. package/dist/storefront-language-DrMjVbmk.js +29 -0
  177. package/dist/storefront-language.d.ts +14 -0
  178. package/dist/storefront-text-D25ae1qf.js +11 -0
  179. package/dist/storefront-text-en-ljjjSS4q.js +1030 -0
  180. package/dist/storefront-text-pt-BtHaJLcp.js +1030 -0
  181. package/dist/storefront-text.d.ts +4 -0
  182. package/dist/stripe-dialog-Ev9s3Z62.js +396 -0
  183. package/dist/stripe-dialog.d.ts +30 -0
  184. package/dist/telemetry-HuZXWBPi.js +114 -0
  185. package/dist/telemetry.d.ts +10 -0
  186. package/dist/templates-CAqoNyTW.js +40 -0
  187. package/dist/templates.d.ts +15 -0
  188. package/dist/urls-CpGQPxvf.js +71 -0
  189. package/dist/urls.d.ts +18 -0
  190. package/dist/use-checkout-CZcxXJXi.js +42 -0
  191. package/dist/use-checkout-payment-9R-zacrJ.js +80 -0
  192. package/dist/use-checkout-payment.d.ts +18 -0
  193. package/dist/use-checkout.d.ts +36 -0
  194. package/dist/use-culqi-checkout-CrjLAipU.js +109 -0
  195. package/dist/use-order-payment-BKIz_IO0.js +45 -0
  196. package/dist/use-order-payment.d.ts +18 -0
  197. package/dist/use-payment-token-CErx-tN-.js +105 -0
  198. package/dist/vite-payment-logos-kziu7wKb.js +27 -0
  199. package/dist/vite-payment-logos.d.ts +24 -0
  200. package/dist/vite-public-assets-DW2fgtVb.js +209 -0
  201. package/dist/vite-public-assets.d.ts +29 -0
  202. package/dist/vite-sections-DTBr0-Kg.js +464 -0
  203. package/dist/vite-sections.d.ts +21 -0
  204. package/dist/vite-theme-ui-BMO-CDi3.js +41 -0
  205. package/dist/vite-theme-ui.d.ts +10 -0
  206. package/dist/vite.d.ts +36 -0
  207. package/dist/vite.js +127 -0
  208. package/dist/voucher-payment-CVFDZ1L8.js +66 -0
  209. package/dist/worker-CNi-gzCu.js +86 -0
  210. package/dist/worker.d.ts +27 -0
  211. package/package.json +100 -76
  212. package/src/sections/account-addresses.tsx +215 -0
  213. package/src/sections/account-order.tsx +424 -0
  214. package/src/sections/account-orders.tsx +259 -0
  215. package/src/sections/account-profile.tsx +70 -0
  216. package/src/sections/checkout.tsx +586 -0
  217. package/src/sections/complaint-book.tsx +325 -0
  218. package/src/sections/design-system.tsx +146 -0
  219. package/src/sections/draft-invoice.tsx +105 -0
  220. package/src/sections/order-tracking.tsx +81 -0
  221. package/src/vite-client.d.ts +4 -0
  222. package/bin/ecomiq.mjs +0 -179
  223. package/public/design-bridge.js +0 -318
  224. package/src/api-proxy.ts +0 -194
  225. package/src/auth/create-storefront-auth.ts +0 -94
  226. package/src/auth/ecomiq-oauth-password-client.ts +0 -26
  227. package/src/auth/ecomiq-oauth-password-constants.ts +0 -24
  228. package/src/auth/ecomiq-oauth-password-plugin.ts +0 -294
  229. package/src/auth/ecomiq-oauth-password-types.ts +0 -24
  230. package/src/auth/ecomiq-storefront-sign-in.ts +0 -44
  231. package/src/auth/env.ts +0 -7
  232. package/src/auth/secure-cookies.ts +0 -23
  233. package/src/auth/storefront-auth-base-url.ts +0 -117
  234. package/src/auth/storefront-auth.ts +0 -7
  235. package/src/cart-session.ts +0 -239
  236. package/src/client.ts +0 -48
  237. package/src/codegen.mjs +0 -801
  238. package/src/components/account/customer-addresses-panel.tsx +0 -678
  239. package/src/components/account/customer-order-detail-panel.tsx +0 -285
  240. package/src/components/account/customer-orders-panel.tsx +0 -192
  241. package/src/components/account/customer-profile-panel.tsx +0 -379
  242. package/src/components/checkout/cart-sync.ts +0 -143
  243. package/src/components/checkout/checkout-contact-section.tsx +0 -76
  244. package/src/components/checkout/checkout-external-update-banner.tsx +0 -15
  245. package/src/components/checkout/checkout-form-controls.tsx +0 -139
  246. package/src/components/checkout/checkout-line-items.tsx +0 -43
  247. package/src/components/checkout/checkout-order-summary.tsx +0 -165
  248. package/src/components/checkout/checkout-payment-section.tsx +0 -212
  249. package/src/components/checkout/checkout-session-view.tsx +0 -564
  250. package/src/components/checkout/checkout-shipping-address-section.tsx +0 -400
  251. package/src/components/checkout/checkout-shipping-section.tsx +0 -98
  252. package/src/components/checkout/checkout-states.tsx +0 -73
  253. package/src/components/checkout/checkout-step-card.tsx +0 -101
  254. package/src/components/checkout/checkout-steps.ts +0 -111
  255. package/src/components/checkout/form-schema.ts +0 -281
  256. package/src/components/checkout/format.ts +0 -15
  257. package/src/components/checkout/index.ts +0 -5
  258. package/src/components/checkout/map-customer-to-checkout.ts +0 -188
  259. package/src/components/checkout/types.ts +0 -41
  260. package/src/components/checkout/use-checkout-customer-prefill.ts +0 -409
  261. package/src/components/checkout/use-checkout-geo.ts +0 -50
  262. package/src/components/checkout/use-checkout-session.ts +0 -640
  263. package/src/components/hero.tsx +0 -291
  264. package/src/config.d.ts +0 -94
  265. package/src/config.mjs +0 -146
  266. package/src/format-money.ts +0 -31
  267. package/src/health.ts +0 -90
  268. package/src/hooks/index.ts +0 -9
  269. package/src/hooks/recently-viewed.ts +0 -125
  270. package/src/index.ts +0 -349
  271. package/src/link.tsx +0 -2
  272. package/src/pages/account/account-page-skeleton.tsx +0 -69
  273. package/src/pages/account/account-page-view.tsx +0 -270
  274. package/src/pages/account/account-shell.tsx +0 -101
  275. package/src/pages/account/parse-account-route.ts +0 -36
  276. package/src/pages/account.tsx +0 -16
  277. package/src/pages/api.$.ts +0 -20
  278. package/src/pages/api.auth.$.ts +0 -16
  279. package/src/pages/checkout.$checkoutId.tsx +0 -60
  280. package/src/pages/checkout.tsx +0 -31
  281. package/src/pages/pages.$pageSlug.tsx +0 -74
  282. package/src/pages/thank-you.tsx +0 -53
  283. package/src/providers/auth.tsx +0 -96
  284. package/src/providers/cart.tsx +0 -275
  285. package/src/providers/ecomiq.ts +0 -137
  286. package/src/providers/index.ts +0 -26
  287. package/src/proxy-api.ts +0 -20
  288. package/src/public-config.ts +0 -24
  289. package/src/review-submission.ts +0 -89
  290. package/src/runtime/context.ts +0 -2
  291. package/src/runtime/default-layout.tsx +0 -64
  292. package/src/runtime/head.ts +0 -149
  293. package/src/runtime/page.tsx +0 -143
  294. package/src/runtime/postcss-browser-stub.mjs +0 -5
  295. package/src/server-config-store.ts +0 -35
  296. package/src/server.ts +0 -286
  297. package/src/styles.css +0 -76
  298. package/src/ui/badge.tsx +0 -32
  299. package/src/ui/button.tsx +0 -31
  300. package/src/ui/card.tsx +0 -31
  301. package/src/ui/carousel.tsx +0 -218
  302. package/src/ui/cn.ts +0 -6
  303. package/src/ui/index.ts +0 -8
  304. package/src/ui/separator.tsx +0 -6
  305. package/src/ui/skeleton.tsx +0 -6
  306. package/src/ui/storefront-error.tsx +0 -49
  307. package/src/utils.ts +0 -36
  308. package/src/vite-inline.mjs +0 -263
  309. package/templates/__root.tsx +0 -83
  310. package/templates/router.tsx +0 -19
@@ -0,0 +1,376 @@
1
+ import { previewAddress } from "./preview-address-Cf0sJ-9p.js";
2
+ // src/preview-cart.ts
3
+ const PREVIEW_CART_TOKEN = "ecomiq-editor-preview-cart";
4
+ const BUYER = {
5
+ email: "ana.torres@example.com",
6
+ firstName: "Ana",
7
+ lastName: "Torres",
8
+ phone: "000000000",
9
+ identificationCountryCode: null,
10
+ identificationType: null,
11
+ identificationNumber: null,
12
+ entityTaxId: null,
13
+ entityName: null,
14
+ invoiceType: "ticket"
15
+ };
16
+ const RATES = [
17
+ {
18
+ shippingMethodId: "preview-regular",
19
+ name: "Envío regular",
20
+ displayName: "Envío regular",
21
+ target: "automatic",
22
+ price: 12,
23
+ description: "Llega en 3 a 5 días",
24
+ estimatedDeliveryDays: 4,
25
+ rateId: "preview-regular"
26
+ },
27
+ {
28
+ shippingMethodId: "preview-express",
29
+ name: "Envío express",
30
+ displayName: "Envío express",
31
+ target: "automatic",
32
+ price: 25,
33
+ description: "Llega mañana",
34
+ estimatedDeliveryDays: 1,
35
+ rateId: "preview-express"
36
+ },
37
+ {
38
+ shippingMethodId: "preview-pickup",
39
+ name: "Retiro en tienda",
40
+ displayName: "Retiro en tienda",
41
+ target: "pickupPoint",
42
+ price: 0,
43
+ description: "Listo en 24 horas",
44
+ estimatedDeliveryDays: 1,
45
+ rateId: "preview-pickup"
46
+ }
47
+ ];
48
+ const SAMPLE_METHODS = [{
49
+ code: "card",
50
+ name: "Tarjeta de crédito o débito",
51
+ description: null,
52
+ kind: "card",
53
+ isActive: true,
54
+ isDefault: true,
55
+ isManual: false,
56
+ sortOrder: 0,
57
+ providerId: null,
58
+ checkoutMode: null,
59
+ brands: ["visa", "mastercard"],
60
+ bankAccounts: [],
61
+ publicConfiguration: {}
62
+ }, {
63
+ code: "transfer",
64
+ name: "Transferencia bancaria",
65
+ description: "Te enviamos los datos al confirmar",
66
+ kind: "offline",
67
+ isActive: true,
68
+ isDefault: false,
69
+ isManual: true,
70
+ sortOrder: 1,
71
+ providerId: null,
72
+ checkoutMode: null,
73
+ brands: [],
74
+ bankAccounts: [],
75
+ publicConfiguration: {}
76
+ }];
77
+ const state = {
78
+ items: null,
79
+ codes: [],
80
+ rate: "preview-regular",
81
+ method: null,
82
+ buyer: BUYER,
83
+ address: null
84
+ };
85
+ const variants = /* @__PURE__ */ new Map();
86
+ function line(id, product, quantity) {
87
+ return {
88
+ id,
89
+ productId: product.id,
90
+ title: product.name,
91
+ variantLabel: null,
92
+ productHandle: product.slug,
93
+ productUrl: product.url,
94
+ thumbnail: product.imageUrl || null,
95
+ quantity,
96
+ variantId: null,
97
+ variantSku: null,
98
+ unitPrice: product.price,
99
+ compareAtUnitPrice: product.compareAtPrice,
100
+ bundleItems: [],
101
+ requiresShipping: true,
102
+ sellerId: null,
103
+ sellerName: null,
104
+ orderBumpId: null
105
+ };
106
+ }
107
+ function rememberProduct(product) {
108
+ for (const variant of product.variants) {
109
+ if (variant.id === null) continue;
110
+ const label = variant.options.map((option) => option.value).join(" / ");
111
+ variants.set(variant.id, {
112
+ ...line(`preview-line-${variant.id}`, {
113
+ ...product,
114
+ imageUrl: variant.images[0]?.url ?? product.imageUrl,
115
+ price: variant.price,
116
+ compareAtPrice: variant.compareAtPrice
117
+ }, 1),
118
+ variantId: variant.id,
119
+ variantSku: variant.sku || null,
120
+ variantLabel: label || null,
121
+ requiresShipping: variant.requiresShipping,
122
+ sellerId: product.seller?.id ?? null,
123
+ sellerName: product.seller?.name ?? null
124
+ });
125
+ }
126
+ }
127
+ async function items(client) {
128
+ if (state.items !== null) return state.items;
129
+ const products = (await client.getProducts({
130
+ pageSize: 4,
131
+ inStock: true
132
+ }).catch(() => null))?.products ?? [];
133
+ if (products.length === 0) {
134
+ state.items = [line("preview-line-sample", {
135
+ id: "preview-product",
136
+ name: "Producto de ejemplo",
137
+ slug: "",
138
+ url: null,
139
+ imageUrl: "",
140
+ price: 89,
141
+ compareAtPrice: null
142
+ }, 1)];
143
+ return state.items;
144
+ }
145
+ state.items = products.slice(0, 2).map((product, index) => ({
146
+ ...line(`preview-line-${product.id}`, product, index + 1),
147
+ sellerId: product.seller?.id ?? null,
148
+ sellerName: product.seller?.name ?? null
149
+ }));
150
+ return state.items;
151
+ }
152
+ function shippingMethod() {
153
+ const rate = RATES.find((candidate) => candidate.shippingMethodId === state.rate) ?? RATES[0];
154
+ return {
155
+ id: `preview-shipping-${rate.shippingMethodId}`,
156
+ shippingMethodId: rate.shippingMethodId,
157
+ rateId: rate.rateId ?? null,
158
+ name: rate.name ?? "Envío",
159
+ description: rate.description ?? null,
160
+ type: rate.target === "pickupPoint" ? "pickup" : "regular",
161
+ target: rate.target,
162
+ targetId: null,
163
+ fulfillmentLocationId: null,
164
+ total: rate.price,
165
+ estimatedDays: rate.estimatedDeliveryDays ?? null,
166
+ scheduledDate: null,
167
+ scheduledTime: null,
168
+ serviceCode: null,
169
+ sellerId: null,
170
+ shippingProfileId: null
171
+ };
172
+ }
173
+ async function snapshot(client) {
174
+ const [settings, lines] = await Promise.all([client.getSettings(), items(client)]);
175
+ const address = state.address ?? await previewAddress(settings.store);
176
+ const subtotal = lines.reduce((sum, item) => sum + item.unitPrice * item.quantity, 0);
177
+ const discount = state.codes.length > 0 ? Math.round(subtotal * .1 * 100) / 100 : 0;
178
+ const shipping = lines.some((item) => item.requiresShipping) ? shippingMethod() : null;
179
+ const shippingTotal = shipping?.total ?? 0;
180
+ return {
181
+ id: "preview-cart",
182
+ token: PREVIEW_CART_TOKEN,
183
+ cartNumber: "1043",
184
+ email: state.buyer.email,
185
+ phone: state.buyer.phone,
186
+ firstName: state.buyer.firstName,
187
+ lastName: state.buyer.lastName,
188
+ currencyCode: settings.store.currency,
189
+ status: "inProgress",
190
+ completedAt: null,
191
+ shippingAddress: address,
192
+ billingAddress: address,
193
+ promotionCodes: state.codes,
194
+ items: lines,
195
+ shippingMethods: shipping ? [shipping] : [],
196
+ paymentMethodCode: state.method,
197
+ totals: {
198
+ subtotal,
199
+ discountTotal: discount,
200
+ shippingOriginalTotal: shippingTotal,
201
+ shippingTotal,
202
+ taxTotal: 0,
203
+ warrantyTotal: 0,
204
+ total: subtotal - discount + shippingTotal
205
+ },
206
+ invoiceType: state.buyer.invoiceType,
207
+ identificationCountryCode: state.buyer.identificationCountryCode,
208
+ identificationType: state.buyer.identificationType,
209
+ identificationNumber: state.buyer.identificationNumber,
210
+ entityTaxId: state.buyer.entityTaxId,
211
+ entityName: state.buyer.entityName
212
+ };
213
+ }
214
+ async function paymentMethods(client) {
215
+ const configured = await client.getPaymentMethods().catch(() => []);
216
+ if (configured.length === 0) return SAMPLE_METHODS;
217
+ return configured.map((method, index) => ({
218
+ code: method.code,
219
+ name: method.name,
220
+ description: null,
221
+ kind: method.kind,
222
+ isActive: true,
223
+ isDefault: index === 0,
224
+ isManual: method.kind === "offline",
225
+ sortOrder: method.sortOrder,
226
+ providerId: null,
227
+ checkoutMode: null,
228
+ brands: method.brands,
229
+ bankAccounts: [],
230
+ publicConfiguration: {}
231
+ }));
232
+ }
233
+ async function add(client, variantId, quantity) {
234
+ const lines = await items(client);
235
+ const existing = lines.find((item) => item.variantId === variantId);
236
+ if (existing) {
237
+ state.items = lines.map((item) => item === existing ? {
238
+ ...item,
239
+ quantity: item.quantity + quantity
240
+ } : item);
241
+ return snapshot(client);
242
+ }
243
+ const known = variants.get(variantId);
244
+ if (known) state.items = [...lines, {
245
+ ...known,
246
+ quantity
247
+ }];
248
+ return snapshot(client);
249
+ }
250
+ async function setQuantity(client, id, quantity) {
251
+ const lines = await items(client);
252
+ if (quantity <= 0) state.items = lines.filter((item) => item.id !== id);
253
+ else state.items = lines.map((item) => item.id === id ? {
254
+ ...item,
255
+ quantity
256
+ } : item);
257
+ return snapshot(client);
258
+ }
259
+ function shippingOptions() {
260
+ return { groups: [{
261
+ sellerId: null,
262
+ sellerName: null,
263
+ shippingProfileId: null,
264
+ rates: RATES
265
+ }] };
266
+ }
267
+ function ours(params) {
268
+ return params.cartToken === PREVIEW_CART_TOKEN;
269
+ }
270
+ function previewCart(client) {
271
+ return {
272
+ getProductBySlug: async (slug, options) => {
273
+ const product = await client.getProductBySlug(slug, options);
274
+ rememberProduct(product);
275
+ return product;
276
+ },
277
+ createCart: () => snapshot(client),
278
+ getCart: (params) => ours(params) ? snapshot(client) : client.getCart(params),
279
+ addCartItem: (params) => ours(params) ? add(client, params.variantId, params.quantity) : client.addCartItem(params),
280
+ updateCartItemQuantity: (params) => ours(params) ? setQuantity(client, params.cartItemId, params.quantity) : client.updateCartItemQuantity(params),
281
+ removeCartItem: (params) => ours(params) ? setQuantity(client, params.cartItemId, 0) : client.removeCartItem(params),
282
+ getCartCheckout: async (params) => {
283
+ if (!ours(params)) return client.getCartCheckout(params);
284
+ const [cart, methods] = await Promise.all([snapshot(client), paymentMethods(client)]);
285
+ return {
286
+ cart,
287
+ paymentMethods: { methods: methods.map((method) => ({
288
+ ...method,
289
+ discountAmount: null
290
+ })) },
291
+ orderBumps: []
292
+ };
293
+ },
294
+ getShippingOptions: (params) => ours(params) ? Promise.resolve(shippingOptions()) : client.getShippingOptions(params),
295
+ putCartShippingMethod: (params) => {
296
+ if (!ours(params)) return client.putCartShippingMethod(params);
297
+ state.rate = params.shippingMethodId;
298
+ return snapshot(client);
299
+ },
300
+ putCartPaymentMethod: (params) => {
301
+ if (!ours(params)) return client.putCartPaymentMethod(params);
302
+ state.method = params.paymentMethodCode;
303
+ return snapshot(client);
304
+ },
305
+ patchCartBuyer: (params) => {
306
+ if (!ours(params)) return client.patchCartBuyer(params);
307
+ state.buyer = {
308
+ email: params.email,
309
+ firstName: params.firstName,
310
+ lastName: params.lastName,
311
+ phone: params.phone,
312
+ identificationCountryCode: params.identificationCountryCode ?? null,
313
+ identificationType: params.identificationType ?? null,
314
+ identificationNumber: params.identificationNumber ?? null,
315
+ entityTaxId: params.entityTaxId ?? null,
316
+ entityName: params.entityName ?? null,
317
+ invoiceType: params.invoiceType ?? state.buyer.invoiceType
318
+ };
319
+ return snapshot(client);
320
+ },
321
+ patchCartAddresses: async (params) => {
322
+ if (!ours(params)) return client.patchCartAddresses(params);
323
+ const address = params.shippingAddress;
324
+ if (address) state.address = {
325
+ name: address.name,
326
+ address1: address.address1,
327
+ city: address.city,
328
+ countryCode: address.countryCode,
329
+ company: null,
330
+ address2: address.address2 ?? null,
331
+ department: address.department ?? null,
332
+ province: address.province ?? null,
333
+ postalCode: address.postalCode ?? null,
334
+ district: address.district ?? null,
335
+ phone: address.phone ?? null,
336
+ latitude: null,
337
+ longitude: null
338
+ };
339
+ return snapshot(client);
340
+ },
341
+ addCartPromotionCode: (params) => {
342
+ if (!ours(params)) return client.addCartPromotionCode(params);
343
+ if (!state.codes.includes(params.code)) state.codes = [...state.codes, params.code];
344
+ return snapshot(client);
345
+ },
346
+ removeCartPromotionCode: (params) => {
347
+ if (!ours(params)) return client.removeCartPromotionCode(params);
348
+ state.codes = state.codes.filter((code) => code !== params.code);
349
+ return snapshot(client);
350
+ },
351
+ uploadPaymentReceipt: (params) => ours(params) ? Promise.resolve({
352
+ id: "preview-receipt",
353
+ url: ""
354
+ }) : client.uploadPaymentReceipt(params),
355
+ checkoutCart: async (params) => {
356
+ if (!ours(params)) return client.checkoutCart(params);
357
+ const cart = await snapshot(client);
358
+ state.items = null;
359
+ state.codes = [];
360
+ state.method = null;
361
+ return {
362
+ orderId: "preview-order-1",
363
+ orderNumber: "1",
364
+ orderStatusUrl: "/orders/preview-order-1",
365
+ orderGroup: "preview-order-group",
366
+ orderIds: ["preview-order-1"],
367
+ payment: null,
368
+ cart: {
369
+ ...cart,
370
+ status: "completed"
371
+ }
372
+ };
373
+ }
374
+ };
375
+ }
376
+ export { PREVIEW_CART_TOKEN, paymentMethods, previewCart, rememberProduct };
@@ -0,0 +1,51 @@
1
+ // src/product-preview.ts
2
+ const BAR_ID = "ecomiq-product-preview";
3
+ const BAR = `<div id="${BAR_ID}" role="region" aria-label="Vista previa"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M2 12s3.6-7 10-7 10 7 10 7-3.6 7-10 7S2 12 2 12Z"/><circle cx="12" cy="12" r="3"/></svg><strong>Vista previa</strong><span>Este producto no está publicado. Solo tú lo ves.</span><button type="button">Ocultar barra</button></div><style>${[
4
+ `#${BAR_ID}{position:fixed;left:0;right:0;bottom:0;z-index:2147483647;box-sizing:border-box;display:flex;align-items:center;gap:10px;height:46px;margin:0;padding:0 16px;background:#1f1f1f;color:#fff;font:14px/1.2 system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;text-align:left}`,
5
+ `#${BAR_ID} svg{display:block;flex:none}`,
6
+ `#${BAR_ID} strong{flex:none;font-weight:600}`,
7
+ `#${BAR_ID} span{flex:1;min-width:0;overflow:hidden;color:#a3a3a3;white-space:nowrap;text-overflow:ellipsis}`,
8
+ `#${BAR_ID} button{flex:none;margin:0;padding:6px 12px;border:1px solid #4d4d4d;border-radius:6px;background:transparent;color:#fff;font:inherit;cursor:pointer}`,
9
+ `#${BAR_ID} button:hover{background:#2e2e2e}`,
10
+ `body:has(#${BAR_ID}){padding-bottom:46px}`
11
+ ].join("")}</style><script>${`(()=>{const bar=document.getElementById("${BAR_ID}");if(!bar)return;const path=location.pathname;const timer=setInterval(()=>{if(location.pathname!==path)hide()},500);function hide(){clearInterval(timer);bar.remove()}bar.querySelector("button").addEventListener("click",hide)})()`}<\/script>`;
12
+ function productPreviewFrom(request) {
13
+ const key = new URL(request.url).searchParams.get("preview_key");
14
+ if (!key) return void 0;
15
+ return {
16
+ key,
17
+ shown: false
18
+ };
19
+ }
20
+ function productPreviewClient(client, preview) {
21
+ return {
22
+ ...client,
23
+ resolveUrl: async (path) => {
24
+ const resolved = await client.resolveUrl(path, { previewKey: preview.key });
25
+ if (resolved?.kind === "product" && resolved.product.isPreview) preview.shown = true;
26
+ return resolved;
27
+ },
28
+ getProductBySlug: async (slug) => {
29
+ const product = await client.getProductBySlug(slug, { previewKey: preview.key });
30
+ if (product.isPreview) preview.shown = true;
31
+ return product;
32
+ }
33
+ };
34
+ }
35
+ async function productPreviewResponse(response) {
36
+ const headers = new Headers(response.headers);
37
+ headers.set("Cache-Control", "private, no-store");
38
+ headers.set("X-Robots-Tag", "noindex");
39
+ const init = {
40
+ status: response.status,
41
+ statusText: response.statusText,
42
+ headers
43
+ };
44
+ if (!headers.get("Content-Type")?.includes("text/html")) return new Response(response.body, init);
45
+ headers.delete("Content-Length");
46
+ const html = await response.text();
47
+ const end = html.lastIndexOf("</body>");
48
+ if (end === -1) return new Response(html + BAR, init);
49
+ return new Response(html.slice(0, end) + BAR + html.slice(end), init);
50
+ }
51
+ export { productPreviewClient, productPreviewFrom, productPreviewResponse };
@@ -0,0 +1,5 @@
1
+ import { StorefrontClient } from "@ecomiq/core";
2
+ export type ProductPreview = {
3
+ key: string;
4
+ shown: boolean;
5
+ };
@@ -0,0 +1,46 @@
1
+ // src/product-variants.ts
2
+ function isVariantAvailable(variant) {
3
+ return variant.isAvailable !== false;
4
+ }
5
+ function variantOptions(variants) {
6
+ const groups = /* @__PURE__ */ new Map();
7
+ for (const variant of variants) for (const option of variant.options) {
8
+ const group = groups.get(option.key) ?? {
9
+ name: option.name,
10
+ values: []
11
+ };
12
+ if (!group.values.includes(option.value)) group.values.push(option.value);
13
+ groups.set(option.key, group);
14
+ }
15
+ return [...groups.entries()].map(([key, group]) => ({
16
+ key,
17
+ ...group
18
+ }));
19
+ }
20
+ function pickVariant(variants, current, key, value) {
21
+ const wanted = current.options.map((option) => {
22
+ if (option.key === key) return {
23
+ ...option,
24
+ value
25
+ };
26
+ return option;
27
+ });
28
+ const exact = variants.find((variant) => wanted.every((option) => variant.options.some((candidate) => candidate.key === option.key && candidate.value === option.value)));
29
+ if (exact) return exact;
30
+ return variants.find((variant) => variant.options.some((option) => option.key === key && option.value === value)) ?? null;
31
+ }
32
+ function variantSwatches(variants, key, values) {
33
+ const images = /* @__PURE__ */ new Map();
34
+ for (const value of values) {
35
+ const image = variants.find((variant) => variant.options.some((option) => option.key === key && option.value === value) && variant.images.some((image) => image.type === "image"))?.images.filter((candidate) => candidate.type === "image").sort((a, b) => a.order - b.order)[0];
36
+ if (image === void 0) return null;
37
+ images.set(value, image.url);
38
+ }
39
+ if (new Set(images.values()).size < values.length) return null;
40
+ return images;
41
+ }
42
+ function discountPercent(value, compareAt) {
43
+ if (compareAt == null || compareAt <= value || compareAt <= 0) return 0;
44
+ return Math.round((compareAt - value) / compareAt * 100);
45
+ }
46
+ export { discountPercent, isVariantAvailable, pickVariant, variantOptions, variantSwatches };
@@ -0,0 +1,12 @@
1
+ import { ProductDetail } from "@ecomiq/core";
2
+ export type ProductVariant = ProductDetail["variants"][number];
3
+ export type VariantOption = {
4
+ key: string;
5
+ name: string;
6
+ values: string[];
7
+ };
8
+ export declare function isVariantAvailable(variant: ProductVariant): boolean;
9
+ export declare function variantOptions(variants: ProductVariant[]): VariantOption[];
10
+ export declare function pickVariant(variants: ProductVariant[], current: ProductVariant, key: string, value: string): ProductVariant | null;
11
+ export declare function variantSwatches(variants: ProductVariant[], key: string, values: string[]): Map<string, string> | null;
12
+ export declare function discountPercent(value: number, compareAt: number | null | undefined): number;
@@ -0,0 +1,194 @@
1
+ import { text } from "./form-BtQcbXlJ.js";
2
+ import { customer, customerHeaders } from "./session-CKvmFJyg.js";
3
+ import { found, store, storeHeaders } from "./store-8Q-_LFrQ.js";
4
+ import { data, redirect } from "react-router";
5
+ import { ApiError, getOrderReviewContext, getOrderTracking, sanitizeHtml } from "@ecomiq/core";
6
+ import { z } from "zod";
7
+ // src/public-pages.ts
8
+ const SUGGESTION_MIN_LENGTH = 2;
9
+ const SUGGESTION_MAX_LENGTH = 80;
10
+ const SUGGESTION_LIMIT = 6;
11
+ const PageContent = z.object({
12
+ title: z.string().optional(),
13
+ html: z.string().optional(),
14
+ seo: z.object({
15
+ title: z.string().nullish(),
16
+ description: z.string().nullish()
17
+ }).optional()
18
+ });
19
+ function places(items) {
20
+ return items.map((item) => ({
21
+ code: item.code,
22
+ name: item.name
23
+ }));
24
+ }
25
+ async function loadGeo(request, context) {
26
+ const client = store(context);
27
+ const params = new URL(request.url).searchParams;
28
+ const { store: settings } = await client.getSettings();
29
+ const countryCode = settings.countryCode;
30
+ const department = params.get("department");
31
+ const province = params.get("province");
32
+ const none = [];
33
+ const [departments, provinces, districts] = await Promise.all([
34
+ client.getDepartments({ countryCode }).catch(() => none),
35
+ department ? client.getProvinces({
36
+ countryCode,
37
+ departmentCode: department
38
+ }).catch(() => none) : none,
39
+ province ? client.getDistricts({
40
+ countryCode,
41
+ provinceCode: province
42
+ }).catch(() => none) : none
43
+ ]);
44
+ return {
45
+ departments: places(departments),
46
+ provinces: places(provinces),
47
+ districts: places(districts)
48
+ };
49
+ }
50
+ async function loadSearchSuggestions(request, context) {
51
+ const q = new URL(request.url).searchParams.get("q")?.trim() ?? "";
52
+ if (q.length < SUGGESTION_MIN_LENGTH) return {
53
+ q,
54
+ products: []
55
+ };
56
+ return {
57
+ q,
58
+ products: await store(context).autocompleteProducts({
59
+ search: q.slice(0, SUGGESTION_MAX_LENGTH),
60
+ limit: SUGGESTION_LIMIT
61
+ }).catch(() => [])
62
+ };
63
+ }
64
+ async function loadTracking(request, context, code) {
65
+ const typed = new URL(request.url).searchParams.get("code")?.trim();
66
+ if (typed) throw redirect(`/track/${encodeURIComponent(typed)}`);
67
+ const client = store(context);
68
+ const settings = await client.getSettings();
69
+ const place = {
70
+ language: `${settings.store.language}-${settings.store.countryCode}`,
71
+ timeZone: settings.store.timeZone
72
+ };
73
+ if (!code) return {
74
+ code: "",
75
+ tracking: null,
76
+ missing: false,
77
+ ...place
78
+ };
79
+ const tracking = await getOrderTracking(client, code, await storeHeaders(client)).catch(() => null);
80
+ return {
81
+ code,
82
+ tracking,
83
+ missing: tracking === null,
84
+ ...place
85
+ };
86
+ }
87
+ async function loadReview(context, token) {
88
+ const client = store(context);
89
+ return { review: await found(getOrderReviewContext(client, token, await storeHeaders(client)), (status) => status < 500) };
90
+ }
91
+ async function reviewAction(request, context, token) {
92
+ const client = store(context);
93
+ const form = await request.formData();
94
+ const review = await found(getOrderReviewContext(client, token, await storeHeaders(client)), (status) => status < 500);
95
+ const rating = Number(text(form, "rating"));
96
+ const content = text(form, "content");
97
+ const name = text(form, "name");
98
+ if (!Number.isInteger(rating) || rating < 1 || rating > 5 || !content || !name) return data({
99
+ ok: false,
100
+ error: "Elige una calificación y cuéntanos tu experiencia."
101
+ }, { status: 400 });
102
+ try {
103
+ await client.createProductReview({
104
+ productId: text(form, "productId"),
105
+ rating,
106
+ content,
107
+ title: text(form, "title") || void 0,
108
+ reviewerName: name,
109
+ reviewerEmail: review.email ?? "",
110
+ orderId: review.orderId,
111
+ reviewToken: token
112
+ });
113
+ return {
114
+ ok: true,
115
+ error: null
116
+ };
117
+ } catch (error) {
118
+ if (error instanceof ApiError && error.status === 409) return data({
119
+ ok: false,
120
+ error: "Ya opinaste sobre este producto."
121
+ }, { status: 400 });
122
+ return data({
123
+ ok: false,
124
+ error: "No pudimos guardar tu opinión."
125
+ }, { status: 400 });
126
+ }
127
+ }
128
+ async function productReviewAction(request, context) {
129
+ const current = await customer(request, context);
130
+ if (current === null) return data({
131
+ ok: false,
132
+ error: "Inicia sesión para dejar tu opinión."
133
+ }, { status: 401 });
134
+ const form = await request.formData();
135
+ const rating = Number(text(form, "rating"));
136
+ const content = text(form, "content");
137
+ const name = text(form, "name");
138
+ if (!Number.isInteger(rating) || rating < 1 || rating > 5 || !content || !name) return data({
139
+ ok: false,
140
+ error: "Elige una calificación, escribe tu nombre y cuéntanos tu experiencia."
141
+ }, { status: 400 });
142
+ try {
143
+ await store(context).createCustomerProductReview({
144
+ productId: text(form, "productId"),
145
+ rating,
146
+ content,
147
+ title: text(form, "title") || void 0,
148
+ reviewerName: name
149
+ }, customerHeaders(current));
150
+ return {
151
+ ok: true,
152
+ error: null
153
+ };
154
+ } catch (error) {
155
+ if (error instanceof ApiError && error.status === 409) return data({
156
+ ok: false,
157
+ error: "Ya opinaste sobre este producto."
158
+ }, { status: 400 });
159
+ if (error instanceof ApiError && error.code === "Customers.ProfileRequired") return data({
160
+ ok: false,
161
+ error: "Completa tu perfil para dejar tu opinión."
162
+ }, { status: 400 });
163
+ return data({
164
+ ok: false,
165
+ error: "No pudimos guardar tu opinión."
166
+ }, { status: 400 });
167
+ }
168
+ }
169
+ async function readPage(context, handle) {
170
+ const page = await store(context).getPageBySlug(handle).catch((error) => {
171
+ if (error instanceof ApiError && error.status === 404) return null;
172
+ throw error;
173
+ });
174
+ if (page === null) return null;
175
+ return pageData(page);
176
+ }
177
+ async function loadPage(context, handle) {
178
+ return pageData(await found(store(context).getPageBySlug(handle)));
179
+ }
180
+ function pageData(page) {
181
+ const parsed = PageContent.safeParse(page.settings);
182
+ let content = {};
183
+ if (parsed.success) content = parsed.data;
184
+ return {
185
+ title: content.title ?? page.name,
186
+ html: sanitizeHtml(content.html ?? ""),
187
+ layout: page.layout,
188
+ seo: {
189
+ title: content.seo?.title ?? content.title ?? page.name,
190
+ description: content.seo?.description ?? ""
191
+ }
192
+ };
193
+ }
194
+ export { loadGeo, loadPage, loadReview, loadSearchSuggestions, loadTracking, productReviewAction, readPage, reviewAction };