@ecomiq/storefront 2.1.3 → 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 (317) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +150 -123
  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 -81
  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/cloud-runtime-client.ts +0 -378
  238. package/src/codegen.mjs +0 -789
  239. package/src/components/account/customer-addresses-panel.tsx +0 -678
  240. package/src/components/account/customer-order-detail-panel.tsx +0 -285
  241. package/src/components/account/customer-orders-panel.tsx +0 -192
  242. package/src/components/account/customer-profile-panel.tsx +0 -379
  243. package/src/components/checkout/cart-sync.ts +0 -143
  244. package/src/components/checkout/checkout-contact-section.tsx +0 -76
  245. package/src/components/checkout/checkout-external-update-banner.tsx +0 -15
  246. package/src/components/checkout/checkout-form-controls.tsx +0 -139
  247. package/src/components/checkout/checkout-line-items.tsx +0 -43
  248. package/src/components/checkout/checkout-order-summary.tsx +0 -165
  249. package/src/components/checkout/checkout-payment-section.tsx +0 -212
  250. package/src/components/checkout/checkout-session-view.tsx +0 -564
  251. package/src/components/checkout/checkout-shipping-address-section.tsx +0 -400
  252. package/src/components/checkout/checkout-shipping-section.tsx +0 -98
  253. package/src/components/checkout/checkout-states.tsx +0 -73
  254. package/src/components/checkout/checkout-step-card.tsx +0 -101
  255. package/src/components/checkout/checkout-steps.ts +0 -111
  256. package/src/components/checkout/form-schema.ts +0 -281
  257. package/src/components/checkout/format.ts +0 -15
  258. package/src/components/checkout/index.ts +0 -5
  259. package/src/components/checkout/map-customer-to-checkout.ts +0 -188
  260. package/src/components/checkout/types.ts +0 -41
  261. package/src/components/checkout/use-checkout-customer-prefill.ts +0 -409
  262. package/src/components/checkout/use-checkout-geo.ts +0 -50
  263. package/src/components/checkout/use-checkout-session.ts +0 -640
  264. package/src/components/hero.tsx +0 -291
  265. package/src/config.d.ts +0 -94
  266. package/src/config.mjs +0 -146
  267. package/src/format-money.ts +0 -31
  268. package/src/health.ts +0 -90
  269. package/src/hooks/index.ts +0 -9
  270. package/src/hooks/recently-viewed.ts +0 -125
  271. package/src/index.ts +0 -354
  272. package/src/link.tsx +0 -2
  273. package/src/pages/account/account-page-skeleton.tsx +0 -69
  274. package/src/pages/account/account-page-view.tsx +0 -270
  275. package/src/pages/account/account-shell.tsx +0 -101
  276. package/src/pages/account/parse-account-route.ts +0 -36
  277. package/src/pages/account.tsx +0 -16
  278. package/src/pages/api.$.ts +0 -20
  279. package/src/pages/api.auth.$.ts +0 -16
  280. package/src/pages/checkout.$checkoutId.tsx +0 -60
  281. package/src/pages/checkout.tsx +0 -31
  282. package/src/pages/pages.$pageSlug.tsx +0 -111
  283. package/src/pages/thank-you.tsx +0 -53
  284. package/src/providers/auth.tsx +0 -96
  285. package/src/providers/cart.tsx +0 -275
  286. package/src/providers/ecomiq.ts +0 -137
  287. package/src/providers/index.ts +0 -26
  288. package/src/proxy-api.ts +0 -20
  289. package/src/public-config.ts +0 -24
  290. package/src/review-submission.ts +0 -89
  291. package/src/runtime/context.ts +0 -2
  292. package/src/runtime/default-layout.tsx +0 -64
  293. package/src/runtime/head.ts +0 -149
  294. package/src/runtime/page.tsx +0 -143
  295. package/src/runtime/postcss-browser-stub.mjs +0 -5
  296. package/src/server-config-store.ts +0 -35
  297. package/src/server.ts +0 -301
  298. package/src/storefront-definition/contract.ts +0 -1
  299. package/src/storefront-definition/data.ts +0 -188
  300. package/src/storefront-definition/index.ts +0 -2
  301. package/src/storefront-definition/renderer.tsx +0 -1481
  302. package/src/storefront-layout.ts +0 -59
  303. package/src/storefront-runtime.ts +0 -173
  304. package/src/styles.css +0 -97
  305. package/src/ui/badge.tsx +0 -32
  306. package/src/ui/button.tsx +0 -31
  307. package/src/ui/card.tsx +0 -31
  308. package/src/ui/carousel.tsx +0 -218
  309. package/src/ui/cn.ts +0 -6
  310. package/src/ui/index.ts +0 -8
  311. package/src/ui/separator.tsx +0 -6
  312. package/src/ui/skeleton.tsx +0 -6
  313. package/src/ui/storefront-error.tsx +0 -49
  314. package/src/utils.ts +0 -36
  315. package/src/vite-inline.mjs +0 -263
  316. package/templates/__root.tsx +0 -83
  317. package/templates/router.tsx +0 -19
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ecomiq
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,133 +1,160 @@
1
- # @ecomiq/storefront
1
+ # Login de clientes
2
2
 
3
- Micro framework SSR de Ecomiq para storefronts. Páginas, datos y deploy sin
4
- configurar TanStack Start, Vite ni Cloudflare a mano.
3
+ La tienda elige el modo de acceso en Admin, en **Configuración → Compra → Cuentas de clientes**. El SDK consulta esa configuración: `hosted` redirige a Identity y `storefront` muestra el formulario del tema. Ambos modos usan las mismas cuentas y sesión de cliente.
5
4
 
6
- ## Instalación
7
-
8
- ```bash
9
- npm install @ecomiq/storefront
10
- # o
11
- yarn add @ecomiq/storefront
12
- # o
13
- pnpm add @ecomiq/storefront
14
- ```
15
-
16
- Peer deps: `react` y `react-dom` ^19.
17
-
18
- ## Uso
19
-
20
- ```js
21
- // ecomiq.config.js
22
- import { defineConfig } from '@ecomiq/storefront/config'
23
-
24
- export default defineConfig({
25
- domain: 'mi-tienda',
26
- // Server-only. Obligatorio en producción para usar una publicación de Cloud.
27
- cloud: { baseUrl: 'https://cloud.internal.example' },
28
- })
29
- ```
5
+ La ruta `/account/login` integra dos helpers:
30
6
 
31
7
  ```tsx
32
- // pages/index.tsx
33
- import { definePage, serverApi } from '@ecomiq/storefront'
8
+ import { CustomerLoginForm, startCustomerLogin, submitCustomerLogin } from "@ecomiq/storefront";
9
+ import type { Route } from "./+types/login";
34
10
 
35
- export default definePage({
36
- loader: () => serverApi.getProducts({ page: 1, pageSize: 12 }),
37
- component: ({ data }) => <pre>{JSON.stringify(data.products, null, 2)}</pre>,
38
- })
39
- ```
40
-
41
- CLI:
42
-
43
- ```bash
44
- npx ecomiq dev
45
- npx ecomiq build
46
- npx ecomiq deploy
47
- ```
48
-
49
- Si actualizas el package y `.ecomiq` quedó de una versión anterior:
50
-
51
- ```bash
52
- npx ecomiq clean
53
- npx ecomiq dev
54
- ```
55
-
56
- ### Runtime de desarrollo
57
-
58
- `ecomiq dev` usa **Node** por defecto. Para emular Workers en local:
59
-
60
- ```js
61
- dev: { port: 3000, runtime: 'workerd' },
62
- ```
63
-
64
- `ecomiq build` / `deploy` siempre empaquetan para Cloudflare Workers.
65
-
66
- Durante `ecomiq dev`, si `cloud.baseUrl` se omite, el framework conecta a
67
- `http://127.0.0.1:8020`. En producción no se inventa un hostname: si falta la
68
- URL o Cloud no tiene una publicación activa, el template conserva su home
69
- clásica.
70
-
71
- Ver el monorepo [ecomiq-storefront](https://github.com/ecomiq/ecomiq-storefront) para la app de referencia y más documentación.
72
-
73
- ## Storefront declarativo
74
-
75
- `StorefrontDefinition v1` permite construir y versionar una tienda sin generar
76
- código React arbitrario. El contrato valida tema, navegación, footer y ocho
77
- tipos de sección: `hero`, `product-grid`, `collection-grid`, `promo-banner`,
78
- `image-text`, `rich-text`, `testimonials` y `newsletter`.
11
+ export function loader({ request, context }: Route.LoaderArgs) {
12
+ return startCustomerLogin(request, context);
13
+ }
79
14
 
80
- ```tsx
81
- import {
82
- StorefrontDefinitionRenderer,
83
- createDefaultStorefrontDefinition,
84
- } from '@ecomiq/storefront'
85
-
86
- const definition = createDefaultStorefrontDefinition({
87
- storeName: 'Casa Lumbre',
88
- description: 'Cerámica producida localmente.',
89
- })
90
-
91
- export function Home() {
92
- return (
93
- <StorefrontDefinitionRenderer
94
- definition={definition}
95
- locale="es-PE"
96
- currency="PEN"
97
- data={{
98
- productsBySectionId: {
99
- 'featured-products': [],
100
- },
101
- collectionsBySectionId: {
102
- 'featured-collections': [],
103
- },
104
- }}
105
- />
106
- )
15
+ export function action({ request, context }: Route.ActionArgs) {
16
+ return submitCustomerLogin(request, context);
107
17
  }
108
18
  ```
109
19
 
110
- Los sistemas que solo necesitan validar o modificar el contrato pueden importar
111
- el subpath sin cargar el renderer:
112
-
113
- ```ts
114
- import {
115
- StorefrontDefinitionSchema,
116
- StorefrontDefinitionPatchSchema,
117
- applyStorefrontDefinitionPatch,
118
- type StorefrontDefinitionInput,
119
- type StorefrontDefinitionPatchInput,
120
- } from '@ecomiq/storefront/definition'
121
- ```
20
+ El componente de la ruta puede usar `CustomerLoginForm` con `data={actionData ?? loaderData}`. Su prop `classNames` define `form`, `field`, `label`, `input`, `button`, `secondary`, `error` y `hint`; la página, tipografía, colores y controles conservan el diseño del tema. Los 13 temas incluidos tienen esta integración.
21
+
22
+ También se puede crear una interfaz propia con `<Form method="post">` de React Router, manteniendo esos helpers y este contrato:
122
23
 
123
- Cada definición lleva `version` y `revision`. Los patches son puros, exigen
124
- `expectedRevision` y conservan el ID de una sección al reemplazarla. Soportan
125
- `section.add`, `section.replace`, `section.remove`, `section.reorder`,
126
- `theme.replace`, `navigation.replace` y `footer.replace`.
127
-
128
- El template productivo consulta server-side
129
- `GET /v1/runtime/storefronts/:storeSlug`, revalida la publicación mediante
130
- ETag y resuelve los `product-grid.source` y `collection-grid.source` contra el
131
- API storefront. La publicación declarativa reemplaza solo el contenido de la
132
- home; el layout comercial y las rutas de catálogo, producto, carrito, checkout
133
- y cuenta siguen siendo las del framework.
24
+ | `intent` | Campos del formulario |
25
+ | --- | --- |
26
+ | `send` | `email` y token CAPTCHA si está habilitado |
27
+ | `verify` | `code` de seis dígitos; en el paso `secondFactor`, `secondFactor` de autenticación o recuperación |
28
+ | `resend` | Token CAPTCHA si está habilitado; respeta `retryAt` |
29
+ | `reset` | Ninguno; vuelve al ingreso del correo |
30
+
31
+ Los datos públicos incluyen `step`, `email`, `captcha`, `retryAt` y `error`. La transacción OAuth, PKCE y las claves de verificación permanecen en una cookie firmada HttpOnly; el formulario propio no debe enviar esos valores.
32
+
33
+ CAPTCHA es independiente del modo y opcional por tienda: `off`, Turnstile o Google reCAPTCHA v2. `CustomerLoginForm` carga y reinicia el proveedor configurado. Una UI propia debe enviar `cf-turnstile-response` o `g-recaptcha-response`; Turnstile usa la acción `customer_login_code`.
34
+
35
+ ## Datos del registro
36
+
37
+ La tienda configura nombre, apellido, teléfono y fecha de nacimiento como `hidden`, `optional` o `required`. Después del código, ambos modos de login crean la sesión y consultan `GET /v1/customer/registration`. Si falta completar el alta, redirigen a `/account/register?next=...`; el destino se limita a una ruta interna segura.
38
+
39
+ La ruta de registro usa `loadCustomerRegistration` en su loader, `submitCustomerRegistration` en su action y `CustomerRegistrationForm` con las mismas clases personalizables del login. Los datos del formulario incluyen `registration`, `storeName`, `next`, `today` (fecha local de la tienda) y `error`. También puede implementarse una UI propia que envíe `firstName`, `lastName`, `phone` y `dateOfBirth` (ISO `YYYY-MM-DD`) con `<CustomerCsrfField />`.
40
+
41
+ `intent=complete` guarda los campos visibles; `intent=skip` permite omitir todos los opcionales cuando no hay obligatorios. Ambos llaman `POST /v1/customer/registration`. El backend valida los requisitos vigentes y recuerda que el cliente completó este paso. Los clientes existentes sólo vuelven si faltan datos que ahora son obligatorios.
42
+
43
+ Las rutas de cuenta usan `requireCustomer`; checkout permite invitados y llama `requireCustomerRegistration(request, context, current)` cuando hay sesión. La propia ruta de registro usa `customer` para no redirigirse a sí misma. La API también exige completar el registro antes de las operaciones protegidas.
44
+
45
+ ## Desarrollo y temas publicados
46
+
47
+ En local, `ECOMIQ_AUTH_URL=http://localhost:8000` configura el transporte del BFF hacia Identity sin cambiar la autoridad OAuth pública ni desactivar la validación TLS. Aspire ya proporciona esta dirección al deployer local, que la propaga a los sitios instalados. Los ejemplos `.dev.vars.example` de cada tema la incluyen.
48
+
49
+ Los temas publicados son artifacts compilados. Para habilitar el modo dentro de la tienda en un tema existente, hay que **recompilar y publicar una versión que incluya los loaders, actions y formularios de login y registro**. Cambiar solamente la configuración de la tienda no modifica artifacts anteriores.
50
+
51
+ ## Enlaces de catálogo
52
+
53
+ Los temas incluidos mantienen los enlaces a productos y categorías al cambiar
54
+ su patrón, slug o URL personalizada. Los menús se resuelven en la configuración
55
+ cacheada del servidor. Para botones y otros enlaces editables, el plugin
56
+ `catalogLinks()` de `@ecomiq/storefront/vite` genera `virtual:ecomiq-links`
57
+ durante la compilación; no analiza código durante las visitas.
58
+
59
+ El loader raíz pasa ese manifiesto a `readStorefrontLinks(client, manifestLinks)`
60
+ y devuelve el resultado como `storefrontLinks`. `StorefrontLink` y
61
+ `StorefrontAnchor` consumen ese mapa sin hacer peticiones. El SDK deduplica los
62
+ destinos, agrupa hasta 100 por petición y comparte los resultados durante
63
+ 30 segundos. Los cambios se reflejan al renovar esa caché.
64
+
65
+ El loader también devuelve `publishedPages`, con las rutas
66
+ ``settings.cms.pages.map((page) => `/pages/${page.slug}`)`` del snapshot público.
67
+ Ambos componentes ocultan los enlaces locales `/pages/...` que aún no tienen
68
+ publicación. Al publicar la página, el siguiente snapshot recupera su enlace;
69
+ no se consulta la API por cada enlace ni se modifica la configuración guardada.
70
+
71
+ El selector del editor conserva la identidad con
72
+ `setting.link("/products/cuaderno", "Comprar", { type: "product", id: "42" })`.
73
+ Con referencia devuelve un `CatalogLink`; sin referencia conserva el texto de
74
+ la URL. Ambos se pueden pasar a `StorefrontLink` y `StorefrontAnchor`, que
75
+ mantienen separados los destinos aunque otro producto reutilice la URL antigua.
76
+ También se reconocen los enlaces anteriores que resuelve el historial del
77
+ catálogo. Los enlaces externos, las rutas ajenas al catálogo y los parámetros
78
+ o anclas se conservan. En código personalizado, usar los componentes anteriores
79
+ para los enlaces editables; las tarjetas que ya reciben `product.url` o
80
+ `category.url` pueden utilizar directamente esos valores.
81
+
82
+ La instalación inicial de este soporte requiere actualizar y publicar el tema.
83
+ Los cambios posteriores de URLs de catálogo no requieren publicar otra vez.
84
+
85
+ ## Logos de medios de pago
86
+
87
+ `PaymentLogo` pinta un `<img>` de 38×24 que apunta a
88
+ `/assets/payment-logos/<código>.svg`; el JavaScript de la tienda solo lleva los
89
+ nombres. El plugin `paymentLogos()` de `@ecomiq/storefront/vite` escribe esos
90
+ SVG en el build del navegador y los sirve en desarrollo.
91
+
92
+ ## Medición y consentimiento
93
+
94
+ `@ecomiq/storefront/analytics` carga GA4, Google Tag Manager, Meta Pixel y el
95
+ código propio que la tienda configura en Admin (Tienda online → Ajustes →
96
+ Medición y píxeles), y solo después de que el cliente los acepta. Cada
97
+ herramienta pide su finalidad: GA4, «Medición»; Meta Pixel, «Publicidad»;
98
+ Google Tag Manager y el código propio, las dos (pueden llevar cualquier
99
+ etiqueta).
100
+
101
+ El loader raíz devuelve `analytics: readAnalytics(context, settings, cart)`;
102
+ es `null` sin IDs ni código propio, y en el lienzo. El `Layout` pinta
103
+ `<Analytics />` y `<ConsentBanner />`. El aviso no trae estilos: el tema le pasa
104
+ `className` y `classNames` (`text`, `link`, `configure`, `options`, `option`,
105
+ `actions`, `accept`, `reject`; sin `configure` usa la clase de `link`).
106
+ Nombra los proveedores que la tienda usa, avisa que los datos pueden tratarse
107
+ fuera del país y enlaza `/pages/privacidad` si existe. «Rechazar» y «Aceptar»
108
+ van en la primera capa; «Configurar» muestra una casilla sin marcar por
109
+ finalidad y «Guardar». Se pinta solo en el navegador.
110
+
111
+ La decisión se guarda 12 meses en `__Host-ecomiq-consent` como
112
+ `<elección>|<versión>|<fecha ISO>` (`analytics.marketing|2.gm.4|2026-10-12T15:30:00.000Z`,
113
+ `none|…`). La versión junta la del aviso, las herramientas activas y la versión
114
+ publicada de la página de privacidad: si cambia, el aviso vuelve a preguntar y
115
+ nada se carga hasta la nueva decisión. Una cookie sin versión no cuenta como
116
+ decisión. Las cookies del SDK usan el prefijo `__Host-` y `Secure`, así que otra
117
+ tienda del mismo dominio no puede escribirlas.
118
+ `window.ecomiq.consent.get()` devuelve `{ analytics, marketing, version, date }`
119
+ o `null`; `window.ecomiq.consent.set({ analytics, marketing })` y el evento
120
+ `ecomiq:consent` sirven a otros scripts.
121
+
122
+ Para cambiar o retirar la decisión, el pie del tema pinta `<ConsentLink />`
123
+ («Cookies», con las clases de los enlaces vecinos): vuelve a abrir el aviso y
124
+ no pinta nada cuando la tienda no mide. Retirar una finalidad borra sus cookies
125
+ (`_ga*`, `_gid`, `_gat*`, `_fbp`, `_fbc`, `_gcl_*`), avisa a Google y Meta y
126
+ recarga la página si alguna herramienta ya estaba cargada.
127
+
128
+ Los loaders del SDK agregan `analytics` a sus datos (`productPage`,
129
+ `resolvePage`, `collectionPage`, `loadCheckout`, `loadOrderStatus`) y la ruta
130
+ `/products` usa `catalogAnalytics(q, result.products)`; las rutas devuelven esa
131
+ clave tal cual. `<Analytics />` envía `page_view`, `view_item`,
132
+ `view_item_list`, `search`, `add_to_cart` y `remove_from_cart` (comparando el
133
+ carrito de la raíz), `begin_checkout` una vez por carrito y `purchase`, que lee
134
+ la cookie `__Host-ecomiq-purchase` de 10 minutos que deja el pago cuando hay
135
+ consentimiento.
136
+
137
+ ## Secciones por defecto
138
+
139
+ `@ecomiq/storefront/sections/<id>` trae secciones de página listas:
140
+ `order-tracking` («Seguimiento», `<OrderTracking loaderData={…} />` con el
141
+ loader `loadTracking`), `draft-invoice` («Pedido por pagar»,
142
+ `<DraftInvoice loaderData={…} actionData={…} />` con `loadOrderDraft` y
143
+ `orderDraftAction`) y `complaint-book` («Libro de Reclamaciones»,
144
+ `<ComplaintBook loaderData={…} actionData={…} />` con `loadComplaintBook` y
145
+ `complaintBookAction`, en la ruta `libro-de-reclamaciones`). Cada una exporta
146
+ `catalog` y `settings` como las secciones del tema; `complaint-book` no tiene
147
+ ajustes. `complaintBookLinks(settings)` devuelve el enlace del pie solo para
148
+ tiendas en soles (como la API, que responde 404 al resto), y el formulario usa `<Captcha>` con la acción Turnstile
149
+ `complaint_book`. El formulario va en multipart con hasta 3 adjuntos (JPG, PNG,
150
+ WebP o PDF de 5 MB); `complaintBookAttachmentError(files)` los valida en el
151
+ navegador y en la action.
152
+
153
+ Se pintan con el kit del tema: importan `@theme/ui/*` (`button`, `input`,
154
+ `label`, `textarea`, `checkbox`, `radio-group`, `select`),
155
+ que el plugin `themeUi()` de `@ecomiq/storefront/vite` lleva a
156
+ `app/components/ui/*`, y solo usan clases con los tokens del tema. Si al tema le
157
+ falta un componente, el build falla con el archivo que falta y la sección que lo
158
+ usa. El código fuente viaja en `src/sections` del paquete: «Personalizar» en el
159
+ editor lo copia a `app/components/sections/<id>.tsx` y apunta la ruta a esa
160
+ copia.
@@ -0,0 +1,258 @@
1
+ import { optional, text } from "./form-BtQcbXlJ.js";
2
+ import { identityDocumentError, isIdentityDocumentType } from "./documents-T1mzc_j8.js";
3
+ import { ADDRESS_INTENTS, ORDER_REQUEST_INTENTS, isIntent } from "./form-contracts-BNpHaTGJ.js";
4
+ import { readPlace } from "./place-CmW4hBWY.js";
5
+ import { customerHeaders, requireCustomer, requireCustomerWith } from "./session-CKvmFJyg.js";
6
+ import { found, readCountries, readDocumentCountries, store } from "./store-8Q-_LFrQ.js";
7
+ import { requestUrl } from "./urls-CpGQPxvf.js";
8
+ import { data } from "react-router";
9
+ import { ApiError } from "@ecomiq/core";
10
+ // src/account.ts
11
+ const DEFAULT_ADDRESS_LABEL = "Casa";
12
+ function placeName(form, name) {
13
+ const value = text(form, name);
14
+ if (value.includes("|")) return readPlace(value).name;
15
+ return value;
16
+ }
17
+ function readCustomerAddress(form, countryCode) {
18
+ return {
19
+ addressKey: text(form, "label") || DEFAULT_ADDRESS_LABEL,
20
+ countryIsoCode: countryCode,
21
+ addressLine: text(form, "line"),
22
+ department: placeName(form, "department") || null,
23
+ province: placeName(form, "province") || null,
24
+ district: placeName(form, "district") || null,
25
+ cellPhone: optional(form, "phone"),
26
+ reference: optional(form, "reference"),
27
+ isDefault: form.get("default") === "on"
28
+ };
29
+ }
30
+ async function loadAccount(request, context) {
31
+ return { name: (await requireCustomer(request, context)).name };
32
+ }
33
+ const ORDER_STATUSES = [
34
+ "open",
35
+ "delivered",
36
+ "cancelled"
37
+ ];
38
+ function readOrderFilters(url) {
39
+ const status = ORDER_STATUSES.find((value) => value === url.searchParams.get("status")) ?? null;
40
+ const sort = url.searchParams.get("sort") === "oldest" ? "oldest" : "newest";
41
+ const view = url.searchParams.get("view") === "grid" ? "grid" : "list";
42
+ return {
43
+ q: (url.searchParams.get("q") ?? "").trim().slice(0, 100),
44
+ status,
45
+ sort,
46
+ view
47
+ };
48
+ }
49
+ /** The query string of the orders list for these filters, without the default values. */
50
+ function orderFiltersQuery(filters) {
51
+ const query = new URLSearchParams();
52
+ if (filters.q !== "") query.set("q", filters.q);
53
+ if (filters.status !== null) query.set("status", filters.status);
54
+ if (filters.sort === "oldest") query.set("sort", "oldest");
55
+ if (filters.view === "grid") query.set("view", "grid");
56
+ return query;
57
+ }
58
+ async function loadOrders(request, context) {
59
+ const url = requestUrl(request);
60
+ const filters = readOrderFilters(url);
61
+ const page = await requireCustomerWith(request, context, (headers) => store(context).getCustomerOrders({
62
+ ...headers,
63
+ cursor: url.searchParams.get("cursor") ?? void 0,
64
+ search: filters.q || void 0,
65
+ status: filters.status ?? void 0,
66
+ sortDirection: filters.sort === "oldest" ? "asc" : "desc"
67
+ }));
68
+ let next = null;
69
+ if (page.hasNextPage && page.nextCursor) {
70
+ const query = orderFiltersQuery(filters);
71
+ query.set("cursor", page.nextCursor);
72
+ next = `${url.pathname}?${query}`;
73
+ }
74
+ return {
75
+ orders: page.data,
76
+ next,
77
+ filters
78
+ };
79
+ }
80
+ async function loadOrder(request, context, id) {
81
+ return { order: await found(requireCustomerWith(request, context, (headers) => store(context).getCustomerOrder(id, headers))) };
82
+ }
83
+ const MAX_RETURN_PHOTOS = 3;
84
+ function orderRequestError(error, intent) {
85
+ const code = error instanceof ApiError ? error.code ?? "" : "";
86
+ if (code.includes("Receipt")) return "Las fotos deben ser JPG, PNG o WebP de hasta 5 MB.";
87
+ if (code === "Orders.ReturnPhotosLimit") return "Puedes adjuntar hasta 3 fotos.";
88
+ if (code === "Orders.ReturnQuantityInvalid") return "Revisa las cantidades a devolver.";
89
+ if (code === "Orders.ReturnUnavailable") return "Este pedido ya no admite devoluciones.";
90
+ if (code === "Orders.CancellationUnavailable") return "Este pedido ya no se puede cancelar.";
91
+ return intent === "return" ? "No pudimos enviar tu solicitud de devolución." : "No pudimos enviar tu solicitud de cancelación.";
92
+ }
93
+ function returnLines(form) {
94
+ const quantities = form.getAll("quantity");
95
+ return form.getAll("itemId").map((itemId, index) => ({
96
+ itemId: String(itemId),
97
+ quantity: Number(quantities[index] ?? 0)
98
+ })).filter((line) => line.itemId !== "" && Number.isInteger(line.quantity) && line.quantity > 0);
99
+ }
100
+ /** Return or cancellation request the customer sends from an order of their account. */
101
+ async function orderRequestAction(request, context, orderId) {
102
+ const current = await requireCustomer(request, context);
103
+ const client = store(context);
104
+ const headers = customerHeaders(current);
105
+ const form = await request.formData();
106
+ const intent = text(form, "intent");
107
+ if (!isIntent(ORDER_REQUEST_INTENTS, intent)) return data({
108
+ sent: null,
109
+ error: "Acción no válida."
110
+ }, { status: 400 });
111
+ const reason = text(form, "reason");
112
+ const comment = text(form, "comment") || void 0;
113
+ if (reason === "") return data({
114
+ sent: null,
115
+ error: "Elige un motivo."
116
+ }, { status: 400 });
117
+ try {
118
+ if (intent === "cancel") {
119
+ await client.requestCustomerOrderCancellation(orderId, {
120
+ reason,
121
+ comment
122
+ }, headers);
123
+ return {
124
+ sent: "cancel",
125
+ error: null
126
+ };
127
+ }
128
+ const items = returnLines(form);
129
+ if (items.length === 0) return data({
130
+ sent: null,
131
+ error: "Elige qué productos quieres devolver."
132
+ }, { status: 400 });
133
+ const photos = form.getAll("photos").filter((photo) => photo instanceof File && photo.size > 0);
134
+ if (photos.length > MAX_RETURN_PHOTOS) return data({
135
+ sent: null,
136
+ error: "Puedes adjuntar hasta 3 fotos."
137
+ }, { status: 400 });
138
+ await client.requestCustomerOrderReturn(orderId, {
139
+ reason,
140
+ comment,
141
+ items,
142
+ photos
143
+ }, headers);
144
+ return {
145
+ sent: "return",
146
+ error: null
147
+ };
148
+ } catch (error) {
149
+ return data({
150
+ sent: null,
151
+ error: orderRequestError(error, intent)
152
+ }, { status: 400 });
153
+ }
154
+ }
155
+ async function loadAddresses(request, context) {
156
+ const client = store(context);
157
+ const [addresses, countries] = await requireCustomerWith(request, context, (headers) => Promise.all([client.getCustomerAddresses(headers), readCountries(client)]));
158
+ return {
159
+ addresses,
160
+ countries
161
+ };
162
+ }
163
+ async function addressAction(request, context) {
164
+ const current = await requireCustomer(request, context);
165
+ const client = store(context);
166
+ const headers = customerHeaders(current);
167
+ const form = await request.formData();
168
+ const intent = text(form, "intent") || "save";
169
+ if (!isIntent(ADDRESS_INTENTS, intent)) return data({ error: "Acción no válida." }, { status: 400 });
170
+ try {
171
+ if (intent === "delete") {
172
+ await client.deleteCustomerAddress(text(form, "id"), headers);
173
+ return { error: null };
174
+ }
175
+ if (intent === "default") {
176
+ const address = (await client.getCustomerAddresses(headers)).find((item) => item.id === text(form, "id"));
177
+ if (address) await client.updateCustomerAddress(address.id, {
178
+ ...address,
179
+ isDefault: true
180
+ }, headers);
181
+ return { error: null };
182
+ }
183
+ const { store: settings } = await client.getSettings();
184
+ const requestedCountry = text(form, "country");
185
+ if (requestedCountry !== "" && requestedCountry !== settings.countryCode) return data({ error: "La dirección debe ser dentro del país de la tienda." }, { status: 400 });
186
+ const input = readCustomerAddress(form, settings.countryCode);
187
+ if (!input.addressLine || !input.district || !input.cellPhone) return data({ error: "Completa la dirección, el distrito y el celular." }, { status: 400 });
188
+ const id = text(form, "id");
189
+ if (id) await client.updateCustomerAddress(id, input, headers);
190
+ else await client.createCustomerAddress(input, headers);
191
+ return { error: null };
192
+ } catch (error) {
193
+ if (error instanceof ApiError && error.status < 500) return data({ error: "Revisa los datos de la dirección." }, { status: 400 });
194
+ return data({ error: "No pudimos guardar la dirección." }, { status: 400 });
195
+ }
196
+ }
197
+ async function loadProfile(request, context) {
198
+ const client = store(context);
199
+ const [me, countries] = await requireCustomerWith(request, context, (headers) => Promise.all([client.getCustomerMe(headers), readDocumentCountries(client)]));
200
+ return {
201
+ me,
202
+ countries
203
+ };
204
+ }
205
+ async function profileAction(request, context) {
206
+ const current = await requireCustomer(request, context);
207
+ const client = store(context);
208
+ const headers = customerHeaders(current);
209
+ const form = await request.formData();
210
+ const firstName = text(form, "firstName");
211
+ const lastName = text(form, "lastName");
212
+ try {
213
+ const me = await client.getCustomerMe(headers);
214
+ const { store: settings } = await client.getSettings();
215
+ const number = text(form, "document");
216
+ const type = text(form, "identificationType");
217
+ const country = text(form, "identificationCountryCode");
218
+ if (number !== "" && !isIdentityDocumentType(type)) return data({
219
+ saved: false,
220
+ error: "Elige el tipo de documento."
221
+ }, { status: 400 });
222
+ const documentError = isIdentityDocumentType(type) ? identityDocumentError(type, country, number) : null;
223
+ if (documentError) return data({
224
+ saved: false,
225
+ error: documentError
226
+ }, { status: 400 });
227
+ if (me.entityIdentificationNumber && !/^[A-Z]{2}$/.test(country)) return data({
228
+ saved: false,
229
+ error: "Elige el país emisor del documento."
230
+ }, { status: 400 });
231
+ await client.patchCustomer({
232
+ firstName,
233
+ lastName,
234
+ phone: text(form, "phone"),
235
+ identificationNumber: number || null,
236
+ identificationType: number ? type : null,
237
+ identificationCountryCode: number || me.entityIdentificationNumber ? country : null,
238
+ entityName: me.entityName,
239
+ entityIdentificationNumber: me.entityIdentificationNumber,
240
+ gender: me.gender || null,
241
+ role: me.role,
242
+ companyName: me.companyName,
243
+ dateOfBirth: me.dateOfBirth,
244
+ consent: me.consent,
245
+ countryIsoCode: me.countryIsoCode ?? settings.countryCode
246
+ }, headers);
247
+ return {
248
+ saved: true,
249
+ error: null
250
+ };
251
+ } catch {
252
+ return data({
253
+ saved: false,
254
+ error: "No pudimos guardar tus datos."
255
+ }, { status: 400 });
256
+ }
257
+ }
258
+ export { addressAction, loadAccount, loadAddresses, loadOrder, loadOrders, loadProfile, orderFiltersQuery, orderRequestAction, profileAction, readCustomerAddress, readOrderFilters };
@@ -0,0 +1,39 @@
1
+ import { CustomerCsrfField } from "./customer-csrf-C1oDX-Py.js";
2
+ import { usePageAction } from "./page-action-Ctkf4xC6.js";
3
+ import { Form } from "react-router";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ // src/account-forms.tsx
6
+ const ADDRESS_ACTION = "/account/addresses";
7
+ const PROFILE_ACTION = "/account/profile";
8
+ function AddressForm({ intent = "save", addressId, children, ...props }) {
9
+ const action = usePageAction(ADDRESS_ACTION);
10
+ return /* @__PURE__ */ jsxs(Form, {
11
+ method: "post",
12
+ action,
13
+ ...props,
14
+ children: [
15
+ /* @__PURE__ */ jsx(CustomerCsrfField, {}),
16
+ /* @__PURE__ */ jsx("input", {
17
+ type: "hidden",
18
+ name: "intent",
19
+ value: intent
20
+ }),
21
+ /* @__PURE__ */ jsx("input", {
22
+ type: "hidden",
23
+ name: "id",
24
+ value: addressId ?? ""
25
+ }),
26
+ children
27
+ ]
28
+ });
29
+ }
30
+ function ProfileForm({ children, ...props }) {
31
+ const action = usePageAction(PROFILE_ACTION);
32
+ return /* @__PURE__ */ jsxs(Form, {
33
+ method: "post",
34
+ action,
35
+ ...props,
36
+ children: [/* @__PURE__ */ jsx(CustomerCsrfField, {}), children]
37
+ });
38
+ }
39
+ export { ADDRESS_ACTION, AddressForm, PROFILE_ACTION, ProfileForm };
@@ -0,0 +1,13 @@
1
+ import { FetcherFormProps } from "react-router";
2
+ type FormProps = Omit<FetcherFormProps, "action" | "method" | "encType">;
3
+ export type AddressFormProps = FormProps & ({
4
+ intent?: "save";
5
+ addressId?: string | null;
6
+ } | {
7
+ intent: "default" | "delete";
8
+ addressId: string;
9
+ });
10
+ export type ProfileFormProps = FormProps;
11
+ export declare function AddressForm({ intent, addressId, children, ...props }: AddressFormProps): import("react").JSX.Element;
12
+ export declare function ProfileForm({ children, ...props }: ProfileFormProps): import("react").JSX.Element;
13
+ export {};