@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
@@ -1,111 +0,0 @@
1
- export const CHECKOUT_STEPS = ['contact', 'delivery', 'payment'] as const
2
-
3
- export type CheckoutStepId = (typeof CHECKOUT_STEPS)[number]
4
-
5
- export type CheckoutStepFlow = {
6
- active: CheckoutStepId
7
- completed: Record<CheckoutStepId, boolean>
8
- }
9
-
10
- export function createCheckoutStepFlow(
11
- active: CheckoutStepId = 'contact',
12
- ): CheckoutStepFlow {
13
- return {
14
- active,
15
- completed: {
16
- contact: false,
17
- delivery: false,
18
- payment: false,
19
- },
20
- }
21
- }
22
-
23
- export function checkoutStepIndex(step: CheckoutStepId): number {
24
- return CHECKOUT_STEPS.indexOf(step)
25
- }
26
-
27
- export function isCheckoutStepLocked(
28
- flow: CheckoutStepFlow,
29
- step: CheckoutStepId,
30
- ): boolean {
31
- return checkoutStepIndex(step) > checkoutStepIndex(flow.active)
32
- }
33
-
34
- export function isCheckoutStepActive(
35
- flow: CheckoutStepFlow,
36
- step: CheckoutStepId,
37
- ): boolean {
38
- return flow.active === step
39
- }
40
-
41
- export function isCheckoutStepComplete(
42
- flow: CheckoutStepFlow,
43
- step: CheckoutStepId,
44
- ): boolean {
45
- return flow.completed[step] && flow.active !== step
46
- }
47
-
48
- /** Completa el paso activo y avanza al siguiente (si existe). */
49
- export function completeCheckoutStep(
50
- flow: CheckoutStepFlow,
51
- step: CheckoutStepId,
52
- ): CheckoutStepFlow {
53
- if (flow.active !== step) return flow
54
- const idx = checkoutStepIndex(step)
55
- const next = CHECKOUT_STEPS[idx + 1]
56
- return {
57
- active: next ?? step,
58
- completed: {
59
- ...flow.completed,
60
- [step]: true,
61
- },
62
- }
63
- }
64
-
65
- /**
66
- * Reabre un paso ya completado para editarlo e invalida todos los posteriores.
67
- */
68
- export function editCheckoutStep(
69
- flow: CheckoutStepFlow,
70
- step: CheckoutStepId,
71
- ): CheckoutStepFlow {
72
- const idx = checkoutStepIndex(step)
73
- if (idx < 0) return flow
74
- if (checkoutStepIndex(flow.active) < idx && !flow.completed[step]) {
75
- return flow
76
- }
77
-
78
- const completed = { ...flow.completed }
79
- for (const id of CHECKOUT_STEPS) {
80
- if (checkoutStepIndex(id) >= idx) completed[id] = false
81
- }
82
-
83
- return {
84
- active: step,
85
- completed,
86
- }
87
- }
88
-
89
- /**
90
- * Marca contact + delivery como completos y deja el pago activo.
91
- * Usado al prefill automático de un usuario logueado con dirección válida.
92
- */
93
- export function jumpCheckoutToPayment(): CheckoutStepFlow {
94
- return {
95
- active: 'payment',
96
- completed: {
97
- contact: true,
98
- delivery: true,
99
- payment: false,
100
- },
101
- }
102
- }
103
-
104
- export function checkoutStepStatus(
105
- flow: CheckoutStepFlow,
106
- step: CheckoutStepId,
107
- ): 'active' | 'complete' | 'locked' {
108
- if (isCheckoutStepActive(flow, step)) return 'active'
109
- if (isCheckoutStepComplete(flow, step)) return 'complete'
110
- return 'locked'
111
- }
@@ -1,281 +0,0 @@
1
- import { z } from 'zod'
2
- import type { CheckoutContactForm } from './types'
3
-
4
- export const CHECKOUT_FIELD_IDS = [
5
- 'email',
6
- 'firstName',
7
- 'lastName',
8
- 'countryCode',
9
- 'address',
10
- 'department',
11
- 'province-geo',
12
- 'district',
13
- 'city',
14
- 'province-region',
15
- 'phone',
16
- 'checkout-shipping-method',
17
- 'checkout-payment-method',
18
- ] as const
19
-
20
- export type CheckoutFieldId = (typeof CHECKOUT_FIELD_IDS)[number]
21
-
22
- export const CHECKOUT_FIELD_FOCUS_ORDER: CheckoutFieldId[] = [
23
- 'email',
24
- 'firstName',
25
- 'lastName',
26
- 'countryCode',
27
- 'address',
28
- 'department',
29
- 'province-geo',
30
- 'district',
31
- 'city',
32
- 'province-region',
33
- 'phone',
34
- 'checkout-shipping-method',
35
- 'checkout-payment-method',
36
- ]
37
-
38
- const zodPathToFieldId: Record<string, CheckoutFieldId> = {
39
- email: 'email',
40
- firstName: 'firstName',
41
- lastName: 'lastName',
42
- countryCode: 'countryCode',
43
- address: 'address',
44
- phone: 'phone',
45
- departmentCode: 'department',
46
- provinceCode: 'province-geo',
47
- districtCode: 'district',
48
- city: 'city',
49
- province: 'province-region',
50
- selectedShippingKey: 'checkout-shipping-method',
51
- selectedPaymentCode: 'checkout-payment-method',
52
- }
53
-
54
- export type CheckoutFormValidationContext = {
55
- contact: CheckoutContactForm
56
- selectedShippingKey: string | null
57
- shippingOptionsCount: number
58
- selectedPaymentCode: string | null
59
- paymentMethodsCount: number
60
- }
61
-
62
- function phoneDigitsForCurrency(currency: string) {
63
- return currency.toUpperCase() === 'PEN' ? 9 : 10
64
- }
65
-
66
- const contactStepObject = z.object({
67
- email: z
68
- .string()
69
- .trim()
70
- .min(1, 'El email es requerido')
71
- .email('Ingresa un email válido'),
72
- })
73
-
74
- function deliveryStepObject(currency: string) {
75
- const phoneDigits = phoneDigitsForCurrency(currency)
76
- return z.object({
77
- firstName: z
78
- .string()
79
- .trim()
80
- .min(1, 'El nombre es requerido')
81
- .min(2, 'El nombre debe tener al menos 2 caracteres'),
82
- lastName: z
83
- .string()
84
- .trim()
85
- .min(1, 'El apellido es requerido')
86
- .min(2, 'El apellido debe tener al menos 2 caracteres'),
87
- countryCode: z.string().trim().min(2, 'Selecciona un país').max(2),
88
- address: z
89
- .string()
90
- .trim()
91
- .min(1, 'La dirección es requerida')
92
- .min(5, 'La dirección debe tener al menos 5 caracteres'),
93
- phone: z
94
- .string()
95
- .trim()
96
- .min(1, 'El teléfono es requerido')
97
- .regex(/^\d+$/, 'El teléfono solo debe contener números')
98
- .length(phoneDigits, `El teléfono debe tener ${phoneDigits} dígitos`),
99
- departmentCode: z.string(),
100
- provinceCode: z.string(),
101
- districtCode: z.string(),
102
- city: z.string(),
103
- province: z.string(),
104
- selectedShippingKey: z.string().nullable(),
105
- shippingOptionsCount: z.number().int().nonnegative(),
106
- })
107
- }
108
-
109
- const paymentStepObject = z.object({
110
- selectedPaymentCode: z.string().nullable(),
111
- paymentMethodsCount: z.number().int().nonnegative(),
112
- })
113
-
114
- function refineDelivery(
115
- data: z.infer<ReturnType<typeof deliveryStepObject>>,
116
- ctx: z.RefinementCtx,
117
- ) {
118
- const country = data.countryCode.toUpperCase()
119
-
120
- if (country === 'PE') {
121
- if (!data.departmentCode.trim()) {
122
- ctx.addIssue({
123
- code: z.ZodIssueCode.custom,
124
- path: ['departmentCode'],
125
- message: 'Selecciona un departamento',
126
- })
127
- }
128
- if (!data.provinceCode.trim()) {
129
- ctx.addIssue({
130
- code: z.ZodIssueCode.custom,
131
- path: ['provinceCode'],
132
- message: 'Selecciona una provincia',
133
- })
134
- }
135
- if (!data.districtCode.trim()) {
136
- ctx.addIssue({
137
- code: z.ZodIssueCode.custom,
138
- path: ['districtCode'],
139
- message: 'Selecciona un distrito',
140
- })
141
- }
142
- } else {
143
- if (!data.city.trim()) {
144
- ctx.addIssue({
145
- code: z.ZodIssueCode.custom,
146
- path: ['city'],
147
- message: 'La ciudad es requerida',
148
- })
149
- }
150
- if (!data.province.trim()) {
151
- ctx.addIssue({
152
- code: z.ZodIssueCode.custom,
153
- path: ['province'],
154
- message: 'La región es requerida',
155
- })
156
- }
157
- }
158
-
159
- if (data.shippingOptionsCount > 0 && !data.selectedShippingKey?.trim()) {
160
- ctx.addIssue({
161
- code: z.ZodIssueCode.custom,
162
- path: ['selectedShippingKey'],
163
- message: 'Selecciona un método de envío',
164
- })
165
- }
166
- }
167
-
168
- function refinePayment(
169
- data: z.infer<typeof paymentStepObject>,
170
- ctx: z.RefinementCtx,
171
- ) {
172
- if (data.paymentMethodsCount > 0 && !data.selectedPaymentCode?.trim()) {
173
- ctx.addIssue({
174
- code: z.ZodIssueCode.custom,
175
- path: ['selectedPaymentCode'],
176
- message: 'Selecciona un método de pago',
177
- })
178
- }
179
- }
180
-
181
- export function buildCheckoutContactStepSchema() {
182
- return contactStepObject
183
- }
184
-
185
- export function buildCheckoutDeliveryStepSchema(currency: string) {
186
- return deliveryStepObject(currency).superRefine(refineDelivery)
187
- }
188
-
189
- export function buildCheckoutPaymentStepSchema() {
190
- return paymentStepObject.superRefine(refinePayment)
191
- }
192
-
193
- export function buildCheckoutFormValidationSchema(currency: string) {
194
- const delivery = deliveryStepObject(currency)
195
-
196
- return contactStepObject
197
- .merge(delivery)
198
- .merge(paymentStepObject)
199
- .superRefine((data, ctx) => {
200
- refineDelivery(data, ctx)
201
- refinePayment(data, ctx)
202
- })
203
- }
204
-
205
- export function checkoutValidationInputFromContext(
206
- ctx: CheckoutFormValidationContext,
207
- ) {
208
- const { contact } = ctx
209
- return {
210
- email: contact.email,
211
- firstName: contact.firstName,
212
- lastName: contact.lastName,
213
- countryCode: contact.countryCode,
214
- address: contact.address,
215
- phone: contact.phone,
216
- departmentCode: contact.departmentCode,
217
- provinceCode: contact.provinceCode,
218
- districtCode: contact.districtCode,
219
- city: contact.city,
220
- province: contact.province,
221
- selectedShippingKey: ctx.selectedShippingKey,
222
- shippingOptionsCount: ctx.shippingOptionsCount,
223
- selectedPaymentCode: ctx.selectedPaymentCode,
224
- paymentMethodsCount: ctx.paymentMethodsCount,
225
- }
226
- }
227
-
228
- export function mapZodIssuesToFieldErrors(
229
- error: z.ZodError,
230
- ): Partial<Record<CheckoutFieldId, string>> {
231
- const out: Partial<Record<CheckoutFieldId, string>> = {}
232
- for (const issue of error.issues) {
233
- const key = issue.path[0]
234
- if (typeof key !== 'string') continue
235
- const fieldId = zodPathToFieldId[key]
236
- if (!fieldId || out[fieldId]) continue
237
- out[fieldId] = issue.message
238
- }
239
- return out
240
- }
241
-
242
- export function firstInvalidFieldId(
243
- errors: Partial<Record<CheckoutFieldId, string>>,
244
- ): CheckoutFieldId | null {
245
- for (const id of CHECKOUT_FIELD_FOCUS_ORDER) {
246
- if (errors[id]) return id
247
- }
248
- return null
249
- }
250
-
251
- export function focusCheckoutField(fieldId: CheckoutFieldId): void {
252
- if (typeof document === 'undefined') return
253
- const el = document.getElementById(fieldId)
254
- if (el) {
255
- el.focus({ preventScroll: false })
256
- el.scrollIntoView({ behavior: 'smooth', block: 'center' })
257
- return
258
- }
259
- if (fieldId === 'checkout-shipping-method') {
260
- const selected =
261
- document.querySelector<HTMLButtonElement>('button[data-checkout-shipping][aria-pressed="true"]') ??
262
- document.querySelector<HTMLButtonElement>('#checkout-shipping-method button')
263
- selected?.focus()
264
- selected?.scrollIntoView({ behavior: 'smooth', block: 'center' })
265
- return
266
- }
267
- if (fieldId === 'checkout-payment-method') {
268
- const radio = document.querySelector<HTMLInputElement>('input[name="payment"]')
269
- radio?.focus()
270
- radio?.scrollIntoView({ behavior: 'smooth', block: 'center' })
271
- }
272
- }
273
-
274
- /** Mapea el primer campo inválido al paso del flujo secuencial. */
275
- export function checkoutStepForField(
276
- fieldId: CheckoutFieldId,
277
- ): 'contact' | 'delivery' | 'payment' {
278
- if (fieldId === 'email') return 'contact'
279
- if (fieldId === 'checkout-payment-method') return 'payment'
280
- return 'delivery'
281
- }
@@ -1,15 +0,0 @@
1
- import type { CartCheckoutResponse } from '@ecomiq/core'
2
-
3
- export { formatMoney } from '../../format-money'
4
-
5
- export function thankYouUrl(cartToken: string, transactionId?: string) {
6
- const q = new URLSearchParams({ cartToken })
7
- if (transactionId) q.set('transactionId', transactionId)
8
- return `/thank-you?${q.toString()}`
9
- }
10
-
11
- export function paymentRedirectUrl(result: CartCheckoutResponse): string | null {
12
- const actionUrl = result.payment?.action?.url
13
- if (typeof actionUrl === 'string' && actionUrl.trim()) return actionUrl
14
- return null
15
- }
@@ -1,5 +0,0 @@
1
- /**
2
- * Superficie interna del checkout. La página solo necesita `CheckoutSessionView`;
3
- * el resto se importa por path directo en tests o módulos hermanos.
4
- */
5
- export { CheckoutSessionView } from './checkout-session-view'
@@ -1,188 +0,0 @@
1
- import type {
2
- CustomerAddressUpsertInput,
3
- CustomerProfile,
4
- CustomerSavedAddress,
5
- } from '@ecomiq/core'
6
- import type { CheckoutContactForm } from './types'
7
-
8
- export function findGeoCodeByName(
9
- items: { code: string; name: string }[],
10
- name: string,
11
- ): string {
12
- const target = name.trim().toLowerCase()
13
- if (!target) return ''
14
- return (
15
- items.find((item) => item.name.trim().toLowerCase() === target)?.code ?? ''
16
- )
17
- }
18
-
19
- /** Normaliza teléfono a dígitos nacionales (PE: 9). */
20
- export function normalizeCheckoutPhone(
21
- phone: string,
22
- countryCode: string,
23
- ): string {
24
- let digits = phone.replace(/\D/g, '')
25
- const country = countryCode.toUpperCase()
26
- if (country === 'PE' && digits.startsWith('51') && digits.length > 9) {
27
- digits = digits.slice(-9)
28
- }
29
- if (country === 'PE' && digits.length > 9) {
30
- digits = digits.slice(-9)
31
- }
32
- return digits
33
- }
34
-
35
- export function customerAddressToCheckoutPatch(
36
- address: CustomerSavedAddress,
37
- profile?: CustomerProfile | null,
38
- ): Partial<CheckoutContactForm> {
39
- const countryCode = (
40
- address.countryIsoCode ||
41
- profile?.countryIsoCode ||
42
- 'PE'
43
- ).toUpperCase()
44
- const phoneRaw =
45
- address.cellPhone || address.phone || profile?.phone || ''
46
- const addressLine = [address.addressLine, address.addressNumber]
47
- .map((part) => part.trim())
48
- .filter(Boolean)
49
- .join(' ')
50
-
51
- return {
52
- firstName: profile?.firstName?.trim() || undefined,
53
- lastName: profile?.lastName?.trim() || undefined,
54
- email: profile?.email?.trim() || undefined,
55
- phone: phoneRaw
56
- ? normalizeCheckoutPhone(phoneRaw, countryCode)
57
- : undefined,
58
- countryCode,
59
- address: addressLine || undefined,
60
- address2: address.reference?.trim() || undefined,
61
- postalCode: address.postalCode?.trim() || undefined,
62
- departmentName: address.department?.trim() || undefined,
63
- provinceName: address.province?.trim() || undefined,
64
- province: address.province?.trim() || undefined,
65
- districtName: address.district?.trim() || undefined,
66
- city: address.district?.trim() || undefined,
67
- // Los códigos se resuelven luego vía geo INEI.
68
- departmentCode: '',
69
- provinceCode: '',
70
- districtCode: '',
71
- }
72
- }
73
-
74
- export function customerProfileToCheckoutPatch(
75
- profile: CustomerProfile,
76
- ): Partial<CheckoutContactForm> {
77
- const countryCode = (profile.countryIsoCode || 'PE').toUpperCase()
78
- return {
79
- email: profile.email?.trim() || undefined,
80
- firstName: profile.firstName?.trim() || undefined,
81
- lastName: profile.lastName?.trim() || undefined,
82
- phone: profile.phone
83
- ? normalizeCheckoutPhone(profile.phone, countryCode)
84
- : undefined,
85
- countryCode,
86
- }
87
- }
88
-
89
- /**
90
- * Rellena solo campos vacíos del formulario (el carrito/hidratación tienen prioridad).
91
- */
92
- export function mergeCheckoutContactPrefill(
93
- current: CheckoutContactForm,
94
- prefill: Partial<CheckoutContactForm>,
95
- ): CheckoutContactForm {
96
- const next = { ...current }
97
- for (const key of Object.keys(prefill) as (keyof CheckoutContactForm)[]) {
98
- const value = prefill[key]
99
- if (value == null || String(value).trim() === '') continue
100
- if (String(current[key] ?? '').trim()) continue
101
- next[key] = value
102
- }
103
- return next
104
- }
105
-
106
- /** Aplica una dirección guardada pisando campos de entrega (elige el usuario). */
107
- export function applySavedAddressToContact(
108
- current: CheckoutContactForm,
109
- address: CustomerSavedAddress,
110
- profile?: CustomerProfile | null,
111
- ): CheckoutContactForm {
112
- const patch = customerAddressToCheckoutPatch(address, profile)
113
- return {
114
- ...current,
115
- countryCode: patch.countryCode || current.countryCode,
116
- address: patch.address || '',
117
- address2: patch.address2 ?? '',
118
- postalCode: patch.postalCode || '',
119
- departmentName: patch.departmentName || '',
120
- provinceName: patch.provinceName || '',
121
- province: patch.province || '',
122
- districtName: patch.districtName || '',
123
- city: patch.city || '',
124
- phone: patch.phone || current.phone,
125
- firstName: current.firstName.trim() || patch.firstName || '',
126
- lastName: current.lastName.trim() || patch.lastName || '',
127
- email: current.email.trim() || patch.email || '',
128
- departmentCode: '',
129
- provinceCode: '',
130
- districtCode: '',
131
- }
132
- }
133
-
134
- export function pickDefaultCustomerAddress(
135
- addresses: CustomerSavedAddress[],
136
- ): CustomerSavedAddress | null {
137
- if (!addresses.length) return null
138
- return addresses.find((a) => a.isDefault) ?? addresses[0] ?? null
139
- }
140
-
141
- /** Separa calle y número; si no hay número claro usa `S/N`. */
142
- export function splitStreetAddress(address: string): {
143
- addressLine: string
144
- addressNumber: string
145
- } {
146
- const trimmed = address.trim()
147
- if (!trimmed) return { addressLine: 'Dirección', addressNumber: 'S/N' }
148
- const match = trimmed.match(/^(.*)\s+(\S+)$/)
149
- if (match?.[1]?.trim() && match[2]) {
150
- return { addressLine: match[1].trim(), addressNumber: match[2] }
151
- }
152
- return { addressLine: trimmed, addressNumber: 'S/N' }
153
- }
154
-
155
- /** Checkout → payload de `POST customer/addresses`. */
156
- export function checkoutContactToCustomerAddressUpsert(
157
- contact: CheckoutContactForm,
158
- options: {
159
- addressKey?: string
160
- isDefault?: boolean
161
- } = {},
162
- ): CustomerAddressUpsertInput {
163
- const countryIsoCode = (contact.countryCode || 'PE').toUpperCase()
164
- const { addressLine, addressNumber } = splitStreetAddress(contact.address)
165
- const department =
166
- contact.departmentName.trim() || contact.province.trim() || '—'
167
- const province =
168
- contact.provinceName.trim() || contact.province.trim() || '—'
169
- const district = contact.districtName.trim() || contact.city.trim() || '—'
170
- const phone = contact.phone.trim()
171
-
172
- return {
173
- addressKey: (options.addressKey?.trim() || 'Casa').slice(0, 48),
174
- countryIsoCode,
175
- addressLine,
176
- addressNumber,
177
- department,
178
- province,
179
- district,
180
- phone,
181
- cellPhone: phone,
182
- postalCode: contact.postalCode.trim() || '00000',
183
- reference: contact.address2.trim(),
184
- latitude: null,
185
- longitude: null,
186
- isDefault: Boolean(options.isDefault),
187
- }
188
- }
@@ -1,41 +0,0 @@
1
- export type CheckoutContactForm = {
2
- email: string
3
- firstName: string
4
- lastName: string
5
- company: string
6
- address: string
7
- address2: string
8
- /** Distrito (nombre); en PE se sincroniza con districtName. */
9
- city: string
10
- /** Provincia/región (nombre). */
11
- province: string
12
- postalCode: string
13
- phone: string
14
- countryCode: string
15
- departmentCode: string
16
- departmentName: string
17
- provinceCode: string
18
- provinceName: string
19
- districtCode: string
20
- districtName: string
21
- }
22
-
23
- export const emptyCheckoutContact = (countryCode = 'PE'): CheckoutContactForm => ({
24
- email: '',
25
- firstName: '',
26
- lastName: '',
27
- company: '',
28
- address: '',
29
- address2: '',
30
- city: '',
31
- province: '',
32
- postalCode: '',
33
- phone: '',
34
- countryCode,
35
- departmentCode: '',
36
- departmentName: '',
37
- provinceCode: '',
38
- provinceName: '',
39
- districtCode: '',
40
- districtName: '',
41
- })