@ecomiq/storefront 2.1.4 → 3.0.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 (310) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +377 -76
  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,312 @@
1
+ import { useStorefrontText } from "./storefront-language-DrMjVbmk.js";
2
+ import { useFetcher, useLocation, useNavigation, useSearchParams, useSubmit } from "react-router";
3
+ import { useEffect, useRef, useState } from "react";
4
+ // src/catalog-hooks.ts
5
+ const SEARCH_DELAY_MS = 180;
6
+ const SEARCH_MIN_LENGTH = 2;
7
+ const RELEVANCE = "relevance";
8
+ const SORT_OPTIONS = [
9
+ {
10
+ value: RELEVANCE,
11
+ label: "Relevancia"
12
+ },
13
+ {
14
+ value: "newest",
15
+ label: "Más nuevos"
16
+ },
17
+ {
18
+ value: "price_asc",
19
+ label: "Precio: menor a mayor"
20
+ },
21
+ {
22
+ value: "price_desc",
23
+ label: "Precio: mayor a menor"
24
+ },
25
+ {
26
+ value: "name_asc",
27
+ label: "Nombre: A–Z"
28
+ }
29
+ ];
30
+ const FILTER_LABELS = /* @__PURE__ */ new Map([
31
+ ["availability", "Disponibilidad"],
32
+ ["price", "Precio"],
33
+ ["category", "Categoría"],
34
+ ["brand", "Marca"],
35
+ ["collection", "Colección"],
36
+ ["productType", "Tipo"],
37
+ ["tag", "Etiqueta"],
38
+ ["seller", "Vendedor"]
39
+ ]);
40
+ const FILTER_VALUE_LABELS = /* @__PURE__ */ new Map([
41
+ ["in_stock", "Disponible"],
42
+ ["out_of_stock", "Agotado"],
43
+ ["product", "Producto"],
44
+ ["bundle", "Pack"],
45
+ ["service", "Servicio"],
46
+ ["digital", "Digital"],
47
+ ["gift_card", "Tarjeta de regalo"]
48
+ ]);
49
+ function filterLabel(filter, labels, translate = (source) => source) {
50
+ const label = labels?.filters?.get(filter.id) ?? FILTER_LABELS.get(filter.id);
51
+ return label === void 0 ? filter.label : translate(label);
52
+ }
53
+ function filterValueLabel(value, label, labels, translate = (source) => source) {
54
+ const known = labels?.values?.get(value) ?? FILTER_VALUE_LABELS.get(value);
55
+ return known === void 0 ? label ?? value : translate(known);
56
+ }
57
+ function isSingleChoiceFilter(filter) {
58
+ return filter.id === "availability" || filter.id.startsWith("option:");
59
+ }
60
+ function selectedFacetCount(filters) {
61
+ return filters.reduce((sum, filter) => sum + filter.values.filter((value) => value.selected).length, 0);
62
+ }
63
+ function activeFilterCount(filters, params) {
64
+ let count = selectedFacetCount(filters);
65
+ if (params.get("minPrice")) count += 1;
66
+ if (params.get("maxPrice")) count += 1;
67
+ return count;
68
+ }
69
+ function clearedFiltersHref(params) {
70
+ const next = new URLSearchParams();
71
+ for (const name of ["q", "sort"]) {
72
+ const current = params.get(name);
73
+ if (current) next.set(name, current);
74
+ }
75
+ return `?${next.toString()}`;
76
+ }
77
+ function activeFilterChips(filters, params, text = {}) {
78
+ const chips = [];
79
+ for (const filter of filters) for (const facet of filter.values) if (facet.selected) chips.push({
80
+ key: filter.id,
81
+ value: facet.value,
82
+ text: `${filterLabel(filter, text.labels, text.translate)}: ${filterValueLabel(facet.value, facet.label, text.labels, text.translate)}`
83
+ });
84
+ const minPrice = params.get("minPrice");
85
+ const maxPrice = params.get("maxPrice");
86
+ const price = text.price ?? ((amount) => amount);
87
+ if (minPrice) chips.push({
88
+ key: "minPrice",
89
+ value: minPrice,
90
+ text: text.translate?.("Desde {value0}", { value0: price(minPrice) }) ?? `Desde ${price(minPrice)}`
91
+ });
92
+ if (maxPrice) chips.push({
93
+ key: "maxPrice",
94
+ value: maxPrice,
95
+ text: text.translate?.("Hasta {value0}", { value0: price(maxPrice) }) ?? `Hasta ${price(maxPrice)}`
96
+ });
97
+ return chips.map((chip) => {
98
+ const next = new URLSearchParams();
99
+ for (const [name, current] of params.entries()) if (name !== "page" && !(name === chip.key && current === chip.value)) next.append(name, current);
100
+ return {
101
+ ...chip,
102
+ href: `?${next.toString()}`
103
+ };
104
+ });
105
+ }
106
+ function pageItems(page, pages) {
107
+ const wanted = /* @__PURE__ */ new Set([
108
+ 1,
109
+ pages,
110
+ page - 1,
111
+ page,
112
+ page + 1
113
+ ]);
114
+ const items = [];
115
+ for (let current = 1; current <= pages; current += 1) {
116
+ if (!wanted.has(current)) continue;
117
+ const previous = items[items.length - 1];
118
+ if (typeof previous === "number" && current - previous > 1) items.push("gap");
119
+ items.push(current);
120
+ }
121
+ return items;
122
+ }
123
+ function useCatalogNavigation() {
124
+ const [params] = useSearchParams();
125
+ const location = useLocation();
126
+ const navigation = useNavigation();
127
+ const submit = useSubmit();
128
+ const pending = useRef(null);
129
+ useEffect(() => {
130
+ if (navigation.state === "idle") pending.current = null;
131
+ }, [location.key, navigation.state]);
132
+ const navigate = (change) => {
133
+ const sameCatalog = navigation.location?.pathname === location.pathname;
134
+ const previous = pending.current;
135
+ const intended = previous?.locationKey === location.key && previous.navigationKey === navigation.location?.key ? previous.params : new URLSearchParams(sameCatalog ? navigation.location.search : params);
136
+ const next = new URLSearchParams(intended);
137
+ next.delete("page");
138
+ change(next);
139
+ if (next.toString() === intended.toString()) return;
140
+ pending.current = {
141
+ locationKey: location.key,
142
+ navigationKey: navigation.location?.key,
143
+ params: next
144
+ };
145
+ submit(next, {
146
+ method: "get",
147
+ preventScrollReset: true
148
+ });
149
+ };
150
+ return {
151
+ params,
152
+ navigate
153
+ };
154
+ }
155
+ function useFacets() {
156
+ const { params, navigate } = useCatalogNavigation();
157
+ const toggle = (filterId, value, checked) => navigate((next) => {
158
+ const kept = next.getAll(filterId).filter((current) => current !== value);
159
+ next.delete(filterId);
160
+ for (const current of kept) next.append(filterId, current);
161
+ if (checked) next.append(filterId, value);
162
+ });
163
+ const choose = (filterId, value) => navigate((next) => {
164
+ next.delete(filterId);
165
+ if (value) next.set(filterId, value);
166
+ });
167
+ const setPrice = (from, to, low, high) => navigate((next) => {
168
+ if (from !== void 0 && from > low) next.set("minPrice", String(from));
169
+ else next.delete("minPrice");
170
+ if (to !== void 0 && to < high) next.set("maxPrice", String(to));
171
+ else next.delete("maxPrice");
172
+ });
173
+ return {
174
+ params,
175
+ navigate,
176
+ toggle,
177
+ choose,
178
+ setPrice,
179
+ clearedHref: clearedFiltersHref(params)
180
+ };
181
+ }
182
+ function useSort(labels = {}) {
183
+ const t = useStorefrontText();
184
+ const { params, navigate } = useCatalogNavigation();
185
+ const value = params.get("sort") ?? RELEVANCE;
186
+ const change = (next) => navigate((query) => {
187
+ if (next === RELEVANCE) query.delete("sort");
188
+ else query.set("sort", next);
189
+ });
190
+ const options = SORT_OPTIONS.map((option) => ({
191
+ value: option.value,
192
+ label: t(labels[option.value] ?? option.label)
193
+ }));
194
+ return {
195
+ value,
196
+ label: (options.find((option) => option.value === value) ?? options[0]).label,
197
+ options,
198
+ change
199
+ };
200
+ }
201
+ function usePagination(page, pages) {
202
+ const [params] = useSearchParams();
203
+ const href = (target) => {
204
+ const next = new URLSearchParams(params);
205
+ next.set("page", String(target));
206
+ return `?${next.toString()}`;
207
+ };
208
+ return {
209
+ items: pageItems(page, pages),
210
+ href,
211
+ hasPrevious: page > 1,
212
+ hasNext: page < pages
213
+ };
214
+ }
215
+ function useSearchSuggestions(initial = "") {
216
+ const [q, setQ] = useState(initial);
217
+ const fetcher = useFetcher();
218
+ const trimmed = q.trim();
219
+ const searching = trimmed.length >= SEARCH_MIN_LENGTH;
220
+ useEffect(() => {
221
+ if (!searching) return;
222
+ const timer = setTimeout(() => fetcher.load(`/search/suggest?q=${encodeURIComponent(trimmed)}`), SEARCH_DELAY_MS);
223
+ return () => clearTimeout(timer);
224
+ }, [trimmed]);
225
+ let products = [];
226
+ if (searching) products = fetcher.data?.products ?? [];
227
+ const missing = searching && fetcher.state === "idle" && fetcher.data !== void 0 && products.length === 0;
228
+ return {
229
+ q,
230
+ setQ,
231
+ trimmed,
232
+ searching,
233
+ products,
234
+ missing,
235
+ loading: fetcher.state !== "idle",
236
+ loaded: fetcher.data !== void 0,
237
+ current: fetcher.data?.q === trimmed
238
+ };
239
+ }
240
+ function matchPlace(items, name) {
241
+ const wanted = name?.trim().toLowerCase();
242
+ if (!wanted) return null;
243
+ return items.find((item) => item.name.toLowerCase() === wanted) ?? null;
244
+ }
245
+ function placeValue(place) {
246
+ return place ? `${place.code}|${place.name}` : "";
247
+ }
248
+ function placeByValue(items, value) {
249
+ return items.find((item) => placeValue(item) === value) ?? null;
250
+ }
251
+ function useGeoCascade(defaults) {
252
+ const [country, setCountryState] = useState(defaults.country ?? "");
253
+ const [department, setDepartmentState] = useState(null);
254
+ const [province, setProvinceState] = useState(null);
255
+ const [district, setDistrict] = useState(null);
256
+ const geo = useFetcher();
257
+ useEffect(() => {
258
+ const query = new URLSearchParams({ country });
259
+ if (department) query.set("department", department.code);
260
+ if (province) query.set("province", province.code);
261
+ geo.load(`/geo?${query.toString()}`);
262
+ }, [
263
+ country,
264
+ department?.code,
265
+ province?.code
266
+ ]);
267
+ const data = geo.data ?? {
268
+ departments: [],
269
+ provinces: [],
270
+ districts: []
271
+ };
272
+ useEffect(() => {
273
+ if (department === null) setDepartmentState(matchPlace(data.departments, defaults.department));
274
+ }, [data.departments]);
275
+ useEffect(() => {
276
+ if (province === null) setProvinceState(matchPlace(data.provinces, defaults.province));
277
+ }, [data.provinces]);
278
+ useEffect(() => {
279
+ if (district === null) setDistrict(matchPlace(data.districts, defaults.district));
280
+ }, [data.districts]);
281
+ const setCountry = (next) => {
282
+ setCountryState(next);
283
+ setDepartmentState(null);
284
+ setProvinceState(null);
285
+ setDistrict(null);
286
+ };
287
+ const setDepartment = (next) => {
288
+ setDepartmentState(next);
289
+ setProvinceState(null);
290
+ setDistrict(null);
291
+ };
292
+ const setProvince = (next) => {
293
+ setProvinceState(next);
294
+ setDistrict(null);
295
+ };
296
+ return {
297
+ country,
298
+ setCountry,
299
+ department,
300
+ setDepartment,
301
+ province,
302
+ setProvince,
303
+ district,
304
+ setDistrict,
305
+ setDepartmentValue: (value) => setDepartment(placeByValue(data.departments, value)),
306
+ setProvinceValue: (value) => setProvince(placeByValue(data.provinces, value)),
307
+ setDistrictValue: (value) => setDistrict(placeByValue(data.districts, value)),
308
+ places: data,
309
+ structured: data.departments.length > 0
310
+ };
311
+ }
312
+ export { SORT_OPTIONS, activeFilterChips, activeFilterCount, clearedFiltersHref, filterLabel, filterValueLabel, isSingleChoiceFilter, pageItems, placeValue, selectedFacetCount, useFacets, useGeoCascade, usePagination, useSearchSuggestions, useSort };
@@ -0,0 +1,111 @@
1
+ import { GeoPlace } from "./public-pages.js";
2
+ import { SearchFilter } from "@ecomiq/core";
3
+ export declare const SORT_OPTIONS: readonly [{
4
+ readonly value: "relevance";
5
+ readonly label: "Relevancia";
6
+ }, {
7
+ readonly value: "newest";
8
+ readonly label: "Más nuevos";
9
+ }, {
10
+ readonly value: "price_asc";
11
+ readonly label: "Precio: menor a mayor";
12
+ }, {
13
+ readonly value: "price_desc";
14
+ readonly label: "Precio: mayor a menor";
15
+ }, {
16
+ readonly value: "name_asc";
17
+ readonly label: "Nombre: A–Z";
18
+ }];
19
+ export type PageItem = number | "gap";
20
+ export type SortValue = (typeof SORT_OPTIONS)[number]["value"];
21
+ export type SortLabels = Partial<Record<SortValue, string>>;
22
+ export type FilterLabels = {
23
+ filters?: Map<string, string>;
24
+ values?: Map<string, string>;
25
+ };
26
+ type FilterTranslate = (source: string, values?: Readonly<Record<string, string>>) => string;
27
+ export type FilterChipText = {
28
+ labels?: FilterLabels;
29
+ price?: (amount: string) => string;
30
+ translate?: FilterTranslate;
31
+ };
32
+ export declare function filterLabel(filter: SearchFilter, labels?: FilterLabels, translate?: FilterTranslate): string;
33
+ export declare function filterValueLabel(value: string, label: string | null | undefined, labels?: FilterLabels, translate?: FilterTranslate): string;
34
+ export declare function isSingleChoiceFilter(filter: SearchFilter): boolean;
35
+ export declare function selectedFacetCount(filters: SearchFilter[]): number;
36
+ export declare function activeFilterCount(filters: SearchFilter[], params: URLSearchParams): number;
37
+ export declare function clearedFiltersHref(params: URLSearchParams): string;
38
+ export type ActiveFilterChip = {
39
+ key: string;
40
+ value: string;
41
+ text: string;
42
+ href: string;
43
+ };
44
+ export declare function activeFilterChips(filters: SearchFilter[], params: URLSearchParams, text?: FilterChipText): ActiveFilterChip[];
45
+ export declare function pageItems(page: number, pages: number): PageItem[];
46
+ export declare function useFacets(): {
47
+ params: URLSearchParams;
48
+ navigate: (change: (next: URLSearchParams) => void) => void;
49
+ toggle: (filterId: string, value: string, checked: boolean) => void;
50
+ choose: (filterId: string, value: string) => void;
51
+ setPrice: (from: number | undefined, to: number | undefined, low: number, high: number) => void;
52
+ clearedHref: string;
53
+ };
54
+ export declare function useSort(labels?: SortLabels): {
55
+ value: string;
56
+ label: string;
57
+ options: {
58
+ value: "name_asc" | "newest" | "price_asc" | "price_desc" | "relevance";
59
+ label: string;
60
+ }[];
61
+ change: (next: string) => void;
62
+ };
63
+ export declare function usePagination(page: number, pages: number): {
64
+ items: PageItem[];
65
+ href: (target: number) => string;
66
+ hasPrevious: boolean;
67
+ hasNext: boolean;
68
+ };
69
+ export declare function useSearchSuggestions(initial?: string): {
70
+ q: string;
71
+ setQ: import("react").Dispatch<import("react").SetStateAction<string>>;
72
+ trimmed: string;
73
+ searching: boolean;
74
+ products: never[] | {
75
+ id: string;
76
+ name: string;
77
+ slug: string;
78
+ url: string;
79
+ imageUrl: string;
80
+ }[];
81
+ missing: boolean;
82
+ loading: boolean;
83
+ loaded: boolean;
84
+ current: boolean;
85
+ };
86
+ export declare function placeValue(place: GeoPlace | null): string;
87
+ export declare function useGeoCascade(defaults: {
88
+ country?: string | null;
89
+ department?: string | null;
90
+ province?: string | null;
91
+ district?: string | null;
92
+ }): {
93
+ country: string;
94
+ setCountry: (next: string) => void;
95
+ department: GeoPlace | null;
96
+ setDepartment: (next: GeoPlace | null) => void;
97
+ province: GeoPlace | null;
98
+ setProvince: (next: GeoPlace | null) => void;
99
+ district: GeoPlace | null;
100
+ setDistrict: import("react").Dispatch<import("react").SetStateAction<GeoPlace | null>>;
101
+ setDepartmentValue: (value: string) => void;
102
+ setProvinceValue: (value: string) => void;
103
+ setDistrictValue: (value: string) => void;
104
+ places: {
105
+ departments: GeoPlace[];
106
+ provinces: GeoPlace[];
107
+ districts: GeoPlace[];
108
+ };
109
+ structured: boolean;
110
+ };
111
+ export {};
@@ -0,0 +1,5 @@
1
+ import { ShouldRevalidateFunctionArgs } from "react-router";
2
+ import { ProductsParamsInput } from "@ecomiq/core";
3
+ /** Menus, customer and cart data do not depend on filters in the current catalog. */
4
+ export declare function shouldRevalidateCatalogRoot(args: ShouldRevalidateFunctionArgs): boolean;
5
+ export declare function readCatalog(url: URL, base?: ProductsParamsInput): ProductsParamsInput;