@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
@@ -1,270 +0,0 @@
1
- import { useEffect, useRef, type ReactNode } from 'react'
2
- import { useQueryClient } from '@tanstack/react-query'
3
- import { useRouterState } from '@tanstack/react-router'
4
- import {
5
- createCustomerAddress,
6
- customerMeToProfile,
7
- deleteCustomerAddress,
8
- getCustomerAddresses,
9
- getCustomerMe,
10
- getCustomerOrder,
11
- getCustomerOrders,
12
- patchCustomer,
13
- toCustomerSavedAddresses,
14
- updateCustomerAddress,
15
- type CustomerAddressUpsertInput,
16
- type CustomerProfilePatch,
17
- } from '@ecomiq/core'
18
- import { MapPinHouse, MonitorSmartphone, Package, UserRound } from 'lucide-react'
19
- import { CustomerAddressesPanel } from '../../components/account/customer-addresses-panel'
20
- import { CustomerOrderDetailPanel } from '../../components/account/customer-order-detail-panel'
21
- import { CustomerOrdersPanel } from '../../components/account/customer-orders-panel'
22
- import { CustomerProfilePanel } from '../../components/account/customer-profile-panel'
23
- import {
24
- useApiQuery,
25
- useAuth,
26
- useSearchNavigate,
27
- useSettings,
28
- } from '../../providers'
29
- import { createStorefrontProxyApi } from '../../proxy-api'
30
- import { AccountShell } from './account-shell'
31
- import {
32
- AccountPageSkeleton,
33
- AccountSectionSkeleton,
34
- } from './account-page-skeleton'
35
- import { parseAccountRoute } from './parse-account-route'
36
-
37
- const ACCOUNT_BASE = '/account'
38
- const ORDERS_BASE = `${ACCOUNT_BASE}/orders`
39
- const LOGIN_HREF = '/login'
40
- const HOME_HREF = '/'
41
-
42
- function proxyApi() {
43
- return createStorefrontProxyApi()
44
- }
45
-
46
- export function AccountPageView() {
47
- const pathname = useRouterState({ select: (s) => s.location.pathname })
48
- const { section, orderId } = parseAccountRoute(pathname || ACCOUNT_BASE)
49
- const navigate = useSearchNavigate()
50
- const queryClient = useQueryClient()
51
- const settings = useSettings()
52
- const { client, session, isPending, signOut } = useAuth()
53
- const isAuthenticated = Boolean(session?.user)
54
- const redirectTargetRef = useRef<string | null>(null)
55
- const language = settings.store.language || 'es-PE'
56
-
57
- const profileQuery = useApiQuery(
58
- ['account-customer-me'],
59
- async () => customerMeToProfile(await getCustomerMe(proxyApi())),
60
- {
61
- enabled: section === 'personal' && isAuthenticated && !isPending,
62
- freshForMs: 60_000,
63
- },
64
- )
65
-
66
- const addressesQuery = useApiQuery(
67
- ['customer-addresses'],
68
- async () =>
69
- toCustomerSavedAddresses(await getCustomerAddresses(proxyApi())),
70
- {
71
- enabled: section === 'addresses' && isAuthenticated && !isPending,
72
- freshForMs: 30_000,
73
- },
74
- )
75
-
76
- const ordersQuery = useApiQuery(
77
- ['customer-orders'],
78
- async () => getCustomerOrders(proxyApi()),
79
- {
80
- enabled:
81
- section === 'orders' && !orderId && isAuthenticated && !isPending,
82
- freshForMs: 30_000,
83
- },
84
- )
85
-
86
- const orderDetailQuery = useApiQuery(
87
- ['customer-order', orderId],
88
- async () => getCustomerOrder(proxyApi(), orderId!),
89
- {
90
- enabled:
91
- section === 'orders' && Boolean(orderId) && isAuthenticated && !isPending,
92
- freshForMs: 30_000,
93
- },
94
- )
95
-
96
- useEffect(() => {
97
- if (isPending || isAuthenticated) return
98
-
99
- const redirectTarget = redirectTargetRef.current ?? (pathname || ACCOUNT_BASE)
100
- redirectTargetRef.current = redirectTarget
101
-
102
- void navigate({
103
- to: LOGIN_HREF,
104
- search: { redirect: redirectTarget },
105
- replace: true,
106
- })
107
- }, [isAuthenticated, isPending, navigate, pathname])
108
-
109
- const handleLogout = async () => {
110
- await signOut()
111
- void navigate({ to: HOME_HREF, replace: true })
112
- }
113
-
114
- const invalidateAddresses = () =>
115
- queryClient.invalidateQueries({ queryKey: ['customer-addresses'] })
116
-
117
- const handleUpdateProfile = async (payload: CustomerProfilePatch) => {
118
- await patchCustomer(proxyApi(), payload)
119
- const displayName = `${payload.firstName} ${payload.lastName}`.trim()
120
- try {
121
- await client.$fetch('/update-user', {
122
- method: 'POST',
123
- body: {
124
- name: displayName || payload.firstName,
125
- firstName: payload.firstName,
126
- lastName: payload.lastName,
127
- phone: payload.phone,
128
- },
129
- })
130
- } catch {
131
- // La sesión Better Auth es secundaria; el PATCH upstream ya se aplicó.
132
- }
133
- await queryClient.invalidateQueries({ queryKey: ['account-customer-me'] })
134
- }
135
-
136
- const handleCreateAddress = async (payload: CustomerAddressUpsertInput) => {
137
- await createCustomerAddress(proxyApi(), payload)
138
- await invalidateAddresses()
139
- }
140
-
141
- const handleUpdateAddress = async (
142
- addressId: string,
143
- payload: CustomerAddressUpsertInput,
144
- ) => {
145
- await updateCustomerAddress(proxyApi(), addressId, payload)
146
- await invalidateAddresses()
147
- }
148
-
149
- const handleDeleteAddress = async (addressId: string) => {
150
- await deleteCustomerAddress(proxyApi(), addressId)
151
- await invalidateAddresses()
152
- }
153
-
154
- const menuItems = [
155
- {
156
- key: 'personal',
157
- href: ACCOUNT_BASE,
158
- label: 'Datos personales',
159
- icon: <UserRound className="size-4" />,
160
- },
161
- {
162
- key: 'addresses',
163
- href: `${ACCOUNT_BASE}/addresses`,
164
- label: 'Direcciones',
165
- icon: <MapPinHouse className="size-4" />,
166
- },
167
- {
168
- key: 'orders',
169
- href: ORDERS_BASE,
170
- label: 'Mis pedidos',
171
- icon: <Package className="size-4" />,
172
- },
173
- {
174
- key: 'devices',
175
- href: `${ACCOUNT_BASE}/devices`,
176
- label: 'Dispositivos vinculados',
177
- icon: <MonitorSmartphone className="size-4" />,
178
- },
179
- ]
180
-
181
- if (isPending || !isAuthenticated) {
182
- return <AccountPageSkeleton />
183
- }
184
-
185
- let sectionContent: ReactNode
186
-
187
- switch (section) {
188
- case 'personal':
189
- sectionContent = (
190
- <SectionPanel>
191
- <CustomerProfilePanel
192
- profile={profileQuery.data}
193
- isLoading={profileQuery.isLoading}
194
- errorMessage={profileQuery.error?.message}
195
- onUpdateProfile={handleUpdateProfile}
196
- />
197
- </SectionPanel>
198
- )
199
- break
200
- case 'addresses':
201
- sectionContent = (
202
- <SectionPanel>
203
- <CustomerAddressesPanel
204
- addresses={addressesQuery.data}
205
- isLoading={addressesQuery.isLoading}
206
- errorMessage={addressesQuery.error?.message}
207
- onCreateAddress={handleCreateAddress}
208
- onUpdateAddress={handleUpdateAddress}
209
- onDeleteAddress={handleDeleteAddress}
210
- />
211
- </SectionPanel>
212
- )
213
- break
214
- case 'orders':
215
- sectionContent = (
216
- <SectionPanel>
217
- {orderId ? (
218
- <CustomerOrderDetailPanel
219
- order={orderDetailQuery.data}
220
- isLoading={orderDetailQuery.isLoading}
221
- errorMessage={orderDetailQuery.error?.message}
222
- backHref={ORDERS_BASE}
223
- language={language}
224
- productHref={(handle) => `/products/${encodeURIComponent(handle)}`}
225
- />
226
- ) : (
227
- <CustomerOrdersPanel
228
- orders={ordersQuery.data}
229
- isLoading={ordersQuery.isLoading}
230
- errorMessage={ordersQuery.error?.message}
231
- orderDetailBasePath={ORDERS_BASE}
232
- shopHref={HOME_HREF}
233
- language={language}
234
- />
235
- )}
236
- </SectionPanel>
237
- )
238
- break
239
- case 'devices':
240
- sectionContent = (
241
- <SectionPanel>
242
- <h2 className="text-lg font-medium text-foreground">Dispositivos vinculados</h2>
243
- <p className="mt-2 text-muted-foreground">
244
- Aún no hay endpoint para listar sesiones/dispositivos.
245
- </p>
246
- <p className="mt-1 text-sm text-muted-foreground">
247
- Cuando esté disponible el backend, podrás cerrar sesiones remotas desde aquí.
248
- </p>
249
- </SectionPanel>
250
- )
251
- break
252
- default:
253
- sectionContent = <AccountSectionSkeleton />
254
- }
255
-
256
- return (
257
- <AccountShell
258
- menuItems={menuItems}
259
- onLogout={() => void handleLogout()}
260
- pathname={pathname}
261
- homeHref={HOME_HREF}
262
- >
263
- {sectionContent}
264
- </AccountShell>
265
- )
266
- }
267
-
268
- function SectionPanel({ children }: { children: ReactNode }) {
269
- return <div className="px-6">{children}</div>
270
- }
@@ -1,101 +0,0 @@
1
- import type { ReactNode } from 'react'
2
- import { ArrowLeft, ChevronRight, LogOut } from 'lucide-react'
3
- import { Link } from '../../link'
4
- import { cn } from '../../ui/cn'
5
- import {
6
- accountSectionLabel,
7
- parseAccountRoute,
8
- } from './parse-account-route'
9
-
10
- export type AccountMenuItem = {
11
- key: string
12
- href: string
13
- label: string
14
- icon: ReactNode
15
- }
16
-
17
- type AccountShellProps = {
18
- menuItems: AccountMenuItem[]
19
- onLogout: () => void
20
- profileSyncError?: string | null
21
- children: ReactNode
22
- pathname: string
23
- homeHref?: string
24
- }
25
-
26
- export function AccountShell({
27
- menuItems,
28
- onLogout,
29
- profileSyncError,
30
- children,
31
- pathname,
32
- homeHref = '/',
33
- }: AccountShellProps) {
34
- const { section, orderId } = parseAccountRoute(pathname || '/account')
35
- const sectionTitle = accountSectionLabel(section, orderId)
36
-
37
- return (
38
- <div className="container max-w-6xl mx-auto px-4 py-8">
39
- <Link
40
- to={homeHref}
41
- className="inline-flex items-center gap-2 text-sm text-muted-foreground transition-colors [@media(hover:hover)]:hover:text-foreground"
42
- >
43
- <ArrowLeft className="size-4" />
44
- <span className="underline">Volver a la tienda</span>
45
- </Link>
46
-
47
- <h1 className="mt-2 text-3xl font-semibold tracking-tight">Mi perfil</h1>
48
-
49
- {profileSyncError ? (
50
- <p className="mt-3 text-sm text-amber-800">{profileSyncError}</p>
51
- ) : null}
52
-
53
- <div className="mt-8 grid grid-cols-1 gap-6 lg:grid-cols-[320px_1fr]">
54
- <aside className="overflow-hidden rounded-xl border border-border bg-background lg:sticky lg:top-15 lg:self-start">
55
- <nav className="divide-y divide-border">
56
- {menuItems.map((item) => {
57
- const isOrders = item.key === 'orders'
58
- const active =
59
- (section === item.key && !orderId) ||
60
- (isOrders && section === 'orders' && Boolean(orderId))
61
-
62
- return (
63
- <Link
64
- key={item.key}
65
- to={item.href}
66
- className={cn(
67
- 'flex items-center justify-between border-b border-border px-4 py-4 text-[15px] transition-colors',
68
- active
69
- ? 'bg-muted font-semibold'
70
- : '[@media(hover:hover)]:hover:bg-muted',
71
- )}
72
- >
73
- <span className="flex items-center gap-3">
74
- <span className="text-muted-foreground">{item.icon}</span>
75
- <span>{item.label}</span>
76
- </span>
77
- <ChevronRight className="size-4 text-muted-foreground" />
78
- </Link>
79
- )
80
- })}
81
- <button
82
- type="button"
83
- onClick={onLogout}
84
- className="flex w-full items-center justify-between px-4 py-4 text-left text-[15px] transition-colors [@media(hover:hover)]:hover:bg-muted"
85
- >
86
- <span className="flex items-center gap-3">
87
- <LogOut className="size-4 text-muted-foreground" />
88
- <span>Cerrar sesión</span>
89
- </span>
90
- <ChevronRight className="size-4 text-muted-foreground" />
91
- </button>
92
- </nav>
93
- </aside>
94
-
95
- <section className="min-w-0" aria-label={sectionTitle}>
96
- {children}
97
- </section>
98
- </div>
99
- </div>
100
- )
101
- }
@@ -1,36 +0,0 @@
1
- export type AccountSection = 'personal' | 'addresses' | 'orders' | 'devices'
2
-
3
- export type ParsedAccountRoute = {
4
- section: AccountSection
5
- orderId?: string
6
- }
7
-
8
- const SECTION_LABELS: Record<AccountSection, string> = {
9
- personal: 'Datos personales',
10
- addresses: 'Direcciones',
11
- orders: 'Mis pedidos',
12
- devices: 'Dispositivos vinculados',
13
- }
14
-
15
- export function accountSectionLabel(section: AccountSection, orderId?: string): string {
16
- if (section === 'orders' && orderId) return 'Detalle del pedido'
17
- return SECTION_LABELS[section]
18
- }
19
-
20
- /** Deriva sección y orderId desde `/account/...`. */
21
- export function parseAccountRoute(pathname: string): ParsedAccountRoute {
22
- const normalized = pathname.replace(/\/$/, '') || '/'
23
- const parts = normalized.split('/').filter(Boolean)
24
- const accountIdx = parts.indexOf('account')
25
- if (accountIdx === -1) return { section: 'personal' }
26
-
27
- const sub = parts.slice(accountIdx + 1)
28
- if (sub.length === 0) return { section: 'personal' }
29
- if (sub[0] === 'addresses') return { section: 'addresses' }
30
- if (sub[0] === 'devices') return { section: 'devices' }
31
- if (sub[0] === 'orders') {
32
- if (sub[1]) return { section: 'orders', orderId: decodeURIComponent(sub[1]) }
33
- return { section: 'orders' }
34
- }
35
- return { section: 'personal' }
36
- }
@@ -1,16 +0,0 @@
1
- /**
2
- * Área de cuenta cerrada de Ecomiq (`/account`, `/account/addresses`, …).
3
- * Los templates no pueden overridear estas rutas desde `pages/account`.
4
- * Login/register viven en la raíz del template (`/login`, `/register`).
5
- */
6
- import { definePage } from '../index'
7
- import { AccountPageView } from './account/account-page-view'
8
-
9
- export default definePage({
10
- meta: () => ({
11
- title: 'Mi cuenta',
12
- description: 'Gestiona tu cuenta, direcciones y pedidos',
13
- noIndex: true,
14
- }),
15
- component: AccountPageView,
16
- })
@@ -1,20 +0,0 @@
1
- /**
2
- * Proxy catch-all same-origin: `/api/*` → storefront `/v1/*`.
3
- * Ruta cerrada del framework (no hace falta en pages/ del usuario).
4
- */
5
- import { proxyStorefrontRequest } from '../api-proxy'
6
-
7
- type ApiHandlerArgs = {
8
- request: Request
9
- params: { _splat?: string }
10
- }
11
-
12
- async function handle({ request, params }: ApiHandlerArgs) {
13
- return proxyStorefrontRequest(request, params._splat)
14
- }
15
-
16
- export const GET = handle
17
- export const POST = handle
18
- export const PUT = handle
19
- export const PATCH = handle
20
- export const DELETE = handle
@@ -1,16 +0,0 @@
1
- /**
2
- * Better Auth catch-all: `/api/auth/*`.
3
- * Ruta cerrada del framework (no hace falta en pages/ del usuario).
4
- */
5
- import { storefrontAuth } from '../auth/storefront-auth'
6
-
7
- type ApiHandlerArgs = {
8
- request: Request
9
- }
10
-
11
- async function handle({ request }: ApiHandlerArgs) {
12
- return storefrontAuth.handler(request)
13
- }
14
-
15
- export const GET = handle
16
- export const POST = handle
@@ -1,60 +0,0 @@
1
- /**
2
- * Checkout cerrado de Ecomiq (`/checkout/$checkoutId`).
3
- * Los templates heredan la ruta vía codegen; no se puede overridear desde `pages/`.
4
- * `/checkout` sin ID redirige a `/cart` (ver `checkout.tsx`).
5
- */
6
- import { useEffect } from 'react'
7
- import { CheckoutSessionView } from '../components/checkout'
8
- import { definePage } from '../index'
9
- import { useAuth, useSearchNavigate, useSettings } from '../providers'
10
-
11
- export default definePage<undefined, { checkoutId: string }>({
12
- meta: () => ({
13
- title: 'Checkout',
14
- description: 'Confirma tu pedido y completa la compra',
15
- noIndex: true,
16
- }),
17
- component: CheckoutPage,
18
- })
19
-
20
- function CheckoutPage({ params }: { params: { checkoutId: string } }) {
21
- const checkoutId = params.checkoutId?.trim() ?? ''
22
- const { store } = useSettings()
23
- const allowGuest = store.checkoutSettings.general.allowGuestCheckout
24
- const { session, isPending: authPending } = useAuth()
25
- const navigate = useSearchNavigate()
26
- const isAuthenticated = Boolean(session?.user)
27
- const needsAuth = !allowGuest && !authPending && !isAuthenticated && Boolean(checkoutId)
28
-
29
- useEffect(() => {
30
- if (checkoutId) return
31
- void navigate({ to: '/cart', replace: true })
32
- }, [checkoutId, navigate])
33
-
34
- useEffect(() => {
35
- if (!needsAuth || !checkoutId) return
36
- void navigate({
37
- to: '/login',
38
- search: { redirect: `/checkout/${checkoutId}` },
39
- replace: true,
40
- })
41
- }, [needsAuth, navigate, checkoutId])
42
-
43
- if (!checkoutId) {
44
- return (
45
- <div className="mx-auto w-full max-w-6xl px-4 py-16 text-center text-sm text-muted-foreground">
46
- Redirigiendo al carrito…
47
- </div>
48
- )
49
- }
50
-
51
- if (authPending || needsAuth) {
52
- return (
53
- <div className="mx-auto w-full max-w-6xl px-4 py-16 text-center text-sm text-muted-foreground">
54
- {needsAuth ? 'Redirigiendo para iniciar sesión…' : 'Cargando…'}
55
- </div>
56
- )
57
- }
58
-
59
- return <CheckoutSessionView cartToken={checkoutId} />
60
- }
@@ -1,31 +0,0 @@
1
- /**
2
- * Checkout cerrado de Ecomiq (`/checkout` / `/checkout/`).
3
- * Sin ID → redirige al carrito. El flujo vive en `/checkout/$checkoutId`
4
- * (ruta hermana, no hija: codegen usa `checkout.index.tsx`).
5
- */
6
- import { useEffect } from 'react'
7
- import { definePage } from '../index'
8
- import { useSearchNavigate } from '../providers'
9
-
10
- export default definePage({
11
- meta: () => ({
12
- title: 'Checkout',
13
- description: 'Confirma tu pedido y completa la compra',
14
- noIndex: true,
15
- }),
16
- component: CheckoutRedirectPage,
17
- })
18
-
19
- function CheckoutRedirectPage() {
20
- const navigate = useSearchNavigate()
21
-
22
- useEffect(() => {
23
- void navigate({ to: '/cart', replace: true })
24
- }, [navigate])
25
-
26
- return (
27
- <div className="mx-auto w-full max-w-6xl px-4 py-16 text-center text-sm text-muted-foreground">
28
- Redirigiendo al carrito…
29
- </div>
30
- )
31
- }
@@ -1,111 +0,0 @@
1
- /**
2
- * Página de contenido (`/pages/$pageSlug`).
3
- * La Definition es la dueña de estas rutas; el CMS queda solo como fallback
4
- * de lectura para tiendas que aún no migraron sus páginas.
5
- */
6
- import type { CmsPageDetailsDto } from '@ecomiq/core'
7
- import type { ActiveStorefrontPage } from '../storefront-runtime'
8
- import {
9
- DefinitionSections,
10
- definePage,
11
- sanitizeHtml,
12
- serverApi,
13
- stripHtml,
14
- z,
15
- } from '../index'
16
- import { StorefrontError } from '../ui'
17
-
18
- const ContentPageSettingsSchema = z.object({
19
- title: z.string().optional(),
20
- html: z.string().optional(),
21
- seo: z.object({
22
- title: z.string().optional(),
23
- description: z.string().optional(),
24
- }).optional(),
25
- }).passthrough()
26
-
27
- type ContentPageData =
28
- | Extract<ActiveStorefrontPage, { kind: 'definition' }>
29
- | {
30
- kind: 'cms'
31
- page: CmsPageDetailsDto
32
- content: z.infer<typeof ContentPageSettingsSchema>
33
- }
34
-
35
- export default definePage<ContentPageData, { pageSlug: string }>({
36
- loader: async ({ params }) => {
37
- const resolved = await serverApi.getActiveStorefrontPage(
38
- `/pages/${params.pageSlug}`,
39
- )
40
- if (resolved.kind === 'definition') return resolved
41
-
42
- const page = await serverApi.getPageBySlug(params.pageSlug)
43
- if (page.status !== 'published') throw new Error('Página no publicada')
44
-
45
- return {
46
- kind: 'cms' as const,
47
- page,
48
- content: ContentPageSettingsSchema.parse(page.settings ?? {}),
49
- }
50
- },
51
-
52
- meta: ({ data, settings }) => {
53
- if (data.kind === 'definition') {
54
- const { page } = data
55
- return {
56
- title: page.seo.title ?? page.title ?? settings?.store.name ?? '',
57
- ...(page.seo.description === undefined
58
- ? {}
59
- : { description: page.seo.description }),
60
- ...(page.seo.noindex ? { noIndex: true } : {}),
61
- }
62
- }
63
- return {
64
- title: data.content.seo?.title ?? data.content.title ?? data.page.name,
65
- description: data.content.seo?.description ?? (
66
- data.content.html
67
- ? stripHtml(data.content.html).slice(0, 155)
68
- : undefined
69
- ),
70
- }
71
- },
72
-
73
- error: () => (
74
- <StorefrontError
75
- title="Página no disponible"
76
- description="El contenido no existe o todavía no está publicado."
77
- />
78
- ),
79
-
80
- component: ({ data, settings }) => {
81
- if (data.kind === 'definition') {
82
- return (
83
- <DefinitionSections
84
- definition={data.definition}
85
- pageId={data.page.id}
86
- data={data.data}
87
- locale={settings.store.language}
88
- currency={settings.store.currency}
89
- />
90
- )
91
- }
92
- return (
93
- <article className="mx-auto w-full max-w-4xl px-4 py-10 sm:py-14">
94
- <header className="mb-8 border-b pb-8">
95
- <h1 className="text-balance text-3xl font-semibold tracking-[-0.02em] md:text-4xl">
96
- {data.content.title ?? data.page.name}
97
- </h1>
98
- </header>
99
-
100
- {data.content.html ? (
101
- <div
102
- className="prose prose-neutral max-w-none text-foreground prose-headings:font-semibold prose-a:text-primary"
103
- dangerouslySetInnerHTML={{ __html: sanitizeHtml(data.content.html) }}
104
- />
105
- ) : (
106
- <p className="text-muted-foreground">Contenido no disponible.</p>
107
- )}
108
- </article>
109
- )
110
- },
111
- })