@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
@@ -0,0 +1,259 @@
1
+ import type { CustomerOrderLineItem, CustomerOrderListItem } from "@ecomiq/core";
2
+ import { Form, Link, useLocation, useNavigate } from "react-router";
3
+ import { Button } from "@theme/ui/button";
4
+ import { Input } from "@theme/ui/input";
5
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@theme/ui/select";
6
+ import { money, useStorefrontLocale, useStorefrontText, type SectionCatalog } from "../index";
7
+ import {
8
+ PayButton,
9
+ PaymentPreview,
10
+ ReorderButton,
11
+ mainPayment,
12
+ orderFiltersQuery,
13
+ orderStepLabel,
14
+ orderStepOf,
15
+ useOrderHeadline,
16
+ useOrderPages,
17
+ useOrderStepDetail,
18
+ type OrderFilters,
19
+ type OrdersData,
20
+ } from "../entries/account";
21
+
22
+ export const catalog: SectionCatalog = {
23
+ name: "Mis pedidos",
24
+ description: "Pedidos del cliente con búsqueda, filtros, estado y pago.",
25
+ };
26
+
27
+ const STATUSES: ReadonlyArray<{ value: OrderFilters["status"]; label: string }> = [
28
+ { value: null, label: "Todos" },
29
+ { value: "open", label: "En curso" },
30
+ { value: "delivered", label: "Entregados" },
31
+ { value: "cancelled", label: "Cancelados" },
32
+ ];
33
+
34
+ function Collage({ items }: { items: CustomerOrderLineItem[] }) {
35
+ const shown = items.slice(0, 4);
36
+ const hidden = items.length - shown.length;
37
+ const tile = (index: number) => {
38
+ if (shown.length === 1) return "col-span-2 row-span-2";
39
+ if (shown.length === 2) return "row-span-2";
40
+ if (shown.length === 3 && index === 0) return "row-span-2";
41
+ return "";
42
+ };
43
+ return (
44
+ <div className="grid aspect-[5/4] grid-cols-2 grid-rows-2 gap-1 overflow-hidden rounded-md">
45
+ {shown.map((item, index) => (
46
+ <span key={item.id} className={`relative min-h-0 overflow-hidden bg-muted ${tile(index)}`}>
47
+ {item.thumbnail ? <img src={item.thumbnail} alt="" loading="lazy" decoding="async" className="size-full object-cover" /> : null}
48
+ {hidden > 0 && index === shown.length - 1 ? (
49
+ <span className="absolute inset-0 flex items-center justify-center bg-foreground/55 text-lg font-semibold text-background">+{hidden + 1}</span>
50
+ ) : null}
51
+ </span>
52
+ ))}
53
+ {shown.length === 0 ? <span className="col-span-2 row-span-2 bg-muted" /> : null}
54
+ </div>
55
+ );
56
+ }
57
+
58
+ function Thumbnails({ items }: { items: CustomerOrderLineItem[] }) {
59
+ const shown = items.slice(0, 4);
60
+ const hidden = items.length - shown.length;
61
+ const size = items.length <= 2 ? "size-24 sm:size-28" : "size-16";
62
+ return (
63
+ <div className="flex gap-2">
64
+ {shown.map((item, index) => (
65
+ <span key={item.id} className={`relative shrink-0 overflow-hidden rounded-md border bg-muted ${size}`}>
66
+ {item.thumbnail ? <img src={item.thumbnail} alt="" loading="lazy" decoding="async" className="size-full object-cover" /> : null}
67
+ {hidden > 0 && index === shown.length - 1 ? (
68
+ <span className="absolute inset-0 flex items-center justify-center bg-foreground/55 text-sm font-semibold text-background">+{hidden + 1}</span>
69
+ ) : null}
70
+ </span>
71
+ ))}
72
+ </div>
73
+ );
74
+ }
75
+
76
+ function OrderCard({ order }: { order: CustomerOrderListItem }) {
77
+ const storefrontTranslate = useStorefrontText();
78
+ const { locale } = useStorefrontLocale();
79
+ const stepDetail = useOrderStepDetail();
80
+ const step = orderStepOf(order);
81
+ const detail = stepDetail(step, order.items);
82
+ const payment = mainPayment(order.payments);
83
+ const units = order.items.reduce((sum, item) => sum + item.quantity, 0);
84
+ return (
85
+ <Link to={`/account/orders/${order.orderId}`} className="group flex h-full flex-col gap-4 rounded-lg border bg-card p-4 text-card-foreground">
86
+ <div className="flex flex-col gap-0.5">
87
+ <p className={`font-heading text-xl ${step === "cancelled" ? "text-muted-foreground" : ""}`}>{storefrontTranslate(orderStepLabel(step))}</p>
88
+ {detail === null ? null : <p className="text-sm text-muted-foreground">{detail}</p>}
89
+ </div>
90
+ <Collage items={order.items} />
91
+ <div className="mt-auto grid grid-cols-[minmax(0,1fr)_auto] gap-x-4 gap-y-1 text-sm">
92
+ <p className="font-medium group-hover:underline">{storefrontTranslate("Pedido {value0}", { value0: order.orderNumber })}</p>
93
+ <p className="text-right font-medium tabular-nums">{money(order.total, order.currencyCode, locale)}</p>
94
+ <p className="text-muted-foreground">{units === 1 ? storefrontTranslate("1 producto") : storefrontTranslate("{value0} productos", { value0: units })}</p>
95
+ {payment ? <PaymentPreview payment={payment} className="justify-end text-muted-foreground" /> : null}
96
+ </div>
97
+ </Link>
98
+ );
99
+ }
100
+
101
+ function OrderListCard({ order }: { order: CustomerOrderListItem }) {
102
+ const storefrontTranslate = useStorefrontText();
103
+ const { locale } = useStorefrontLocale();
104
+ const headline = useOrderHeadline();
105
+ const payment = mainPayment(order.payments);
106
+ return (
107
+ <div className="relative flex flex-col gap-4 rounded-lg border bg-card p-4 text-card-foreground transition-colors hover:border-foreground/30 sm:p-5">
108
+ <Thumbnails items={order.items} />
109
+ <div className="flex flex-wrap items-end justify-between gap-x-4 gap-y-3">
110
+ <div className="flex min-w-0 flex-col gap-1">
111
+ <Link
112
+ to={`/account/orders/${order.orderId}`}
113
+ className={`font-heading text-lg after:absolute after:inset-0 after:rounded-lg ${orderStepOf(order) === "cancelled" ? "text-muted-foreground" : ""}`}
114
+ >
115
+ {headline(order)}
116
+ </Link>
117
+ <p className="flex flex-wrap items-center gap-x-1.5 text-sm text-muted-foreground">
118
+ <span>{storefrontTranslate("Pedido {value0}", { value0: order.orderNumber })}</span>
119
+ <span aria-hidden="true">·</span>
120
+ <span>{money(order.total, order.currencyCode, locale)}</span>
121
+ {payment ? (
122
+ <>
123
+ <span aria-hidden="true">·</span>
124
+ <PaymentPreview payment={payment} />
125
+ </>
126
+ ) : null}
127
+ </p>
128
+ </div>
129
+ {order.total - order.totalPaid > 0 && orderStepOf(order) !== "cancelled" ? (
130
+ <PayButton path={`/account/orders/${order.orderId}`} label={storefrontTranslate("Pagar")} variant="outline" />
131
+ ) : (
132
+ <ReorderButton items={order.items} variant="outline" />
133
+ )}
134
+ </div>
135
+ </div>
136
+ );
137
+ }
138
+
139
+ const VIEW_ICONS = {
140
+ list: "M4 6h16M4 12h16M4 18h16",
141
+ grid: "M4 4h7v7H4zM13 4h7v7h-7zM4 13h7v7H4zM13 13h7v7h-7z",
142
+ } as const;
143
+
144
+ export function AccountOrders({ loaderData }: { loaderData: OrdersData }) {
145
+ const storefrontTranslate = useStorefrontText();
146
+ const { pathname } = useLocation();
147
+ const navigate = useNavigate();
148
+ const { orders, more } = useOrderPages(loaderData);
149
+ const { filters } = loaderData;
150
+ const filtered = filters.q !== "" || filters.status !== null;
151
+ const href = (next: OrderFilters) => {
152
+ const query = orderFiltersQuery(next).toString();
153
+ return query === "" ? pathname : `${pathname}?${query}`;
154
+ };
155
+
156
+ if (orders.length === 0 && !filtered)
157
+ return (
158
+ <div className="flex flex-col items-start gap-4 rounded-lg border bg-card p-8 text-card-foreground md:p-10">
159
+ <h2 className="text-2xl">{storefrontTranslate("Aún no tienes pedidos")}</h2>
160
+ <p className="text-sm text-muted-foreground">{storefrontTranslate("Cuando compres, verás aquí el estado de cada pedido.")}</p>
161
+ <Link to="/products" className="text-sm font-medium underline underline-offset-4">
162
+ {storefrontTranslate("Ver productos")}
163
+ </Link>
164
+ </div>
165
+ );
166
+
167
+ return (
168
+ <div className="@container flex flex-col gap-6">
169
+ <div className="flex items-center justify-between gap-4">
170
+ <h2 className="text-3xl">{storefrontTranslate("Pedidos")}</h2>
171
+ <div className="hidden gap-1 sm:flex" role="group" aria-label={storefrontTranslate("Vista")}>
172
+ {(["list", "grid"] as const).map((view) => (
173
+ <Link
174
+ key={view}
175
+ to={href({ ...filters, view })}
176
+ aria-pressed={filters.view === view}
177
+ aria-label={storefrontTranslate(view === "list" ? "Ver como lista" : "Ver como cuadrícula")}
178
+ className={`flex size-9 items-center justify-center rounded-md transition-colors ${filters.view === view ? "bg-muted text-foreground" : "text-muted-foreground hover:text-foreground"}`}
179
+ >
180
+ <svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" className="size-4">
181
+ <path d={VIEW_ICONS[view]} />
182
+ </svg>
183
+ </Link>
184
+ ))}
185
+ </div>
186
+ </div>
187
+ <div className="flex flex-col gap-4">
188
+ <Form method="get" action={pathname} className="flex gap-2" role="search">
189
+ <div className="relative min-w-0 flex-1">
190
+ <svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" className="pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground">
191
+ <circle cx="11" cy="11" r="7" />
192
+ <path d="m20 20-3.5-3.5" />
193
+ </svg>
194
+ <Input type="search" name="q" defaultValue={filters.q} placeholder={storefrontTranslate("Buscar")} aria-label={storefrontTranslate("Buscar pedidos")} maxLength={100} className="pl-9" />
195
+ </div>
196
+ {filters.status !== null ? <input type="hidden" name="status" value={filters.status} /> : null}
197
+ {filters.sort === "oldest" ? <input type="hidden" name="sort" value="oldest" /> : null}
198
+ {filters.view === "grid" ? <input type="hidden" name="view" value="grid" /> : null}
199
+ <Select value={filters.sort} onValueChange={(sort) => navigate(href({ ...filters, sort: sort === "oldest" ? "oldest" : "newest" }))}>
200
+ <SelectTrigger aria-label={storefrontTranslate("Ordenar pedidos")} className="h-auto shrink-0 self-stretch data-[size=default]:h-auto">
201
+ <SelectValue>{storefrontTranslate(filters.sort === "oldest" ? "Más antiguos" : "Más recientes")}</SelectValue>
202
+ </SelectTrigger>
203
+ <SelectContent>
204
+ <SelectItem value="newest">{storefrontTranslate("Más recientes")}</SelectItem>
205
+ <SelectItem value="oldest">{storefrontTranslate("Más antiguos")}</SelectItem>
206
+ </SelectContent>
207
+ </Select>
208
+ </Form>
209
+ <div className="border-b">
210
+ <nav className="-mb-px flex gap-6 overflow-x-auto" aria-label={storefrontTranslate("Filtrar pedidos")}>
211
+ {STATUSES.map((status) => {
212
+ const current = status.value === filters.status;
213
+ return (
214
+ <Link
215
+ key={status.label}
216
+ to={href({ ...filters, status: status.value })}
217
+ aria-current={current ? "page" : undefined}
218
+ className={`shrink-0 whitespace-nowrap border-b-2 pb-3 text-sm transition-colors ${current ? "border-foreground font-medium text-foreground" : "border-transparent text-muted-foreground hover:text-foreground"}`}
219
+ >
220
+ {storefrontTranslate(status.label)}
221
+ </Link>
222
+ );
223
+ })}
224
+ </nav>
225
+ </div>
226
+ </div>
227
+ {orders.length === 0 ? (
228
+ <div className="flex flex-col items-start gap-3 py-6">
229
+ <p className="font-heading text-xl">{storefrontTranslate("Ningún pedido coincide")}</p>
230
+ <p className="text-sm text-muted-foreground">{storefrontTranslate("Prueba con otro número de pedido, producto o estado.")}</p>
231
+ <Link to={pathname} className="text-sm font-medium underline underline-offset-4">
232
+ {storefrontTranslate("Quitar filtros")}
233
+ </Link>
234
+ </div>
235
+ ) : filters.view === "grid" ? (
236
+ <ul className="grid gap-4 @lg:grid-cols-2">
237
+ {orders.map((order) => (
238
+ <li key={order.orderId}>
239
+ <OrderCard order={order} />
240
+ </li>
241
+ ))}
242
+ </ul>
243
+ ) : (
244
+ <ul className="flex flex-col gap-3">
245
+ {orders.map((order) => (
246
+ <li key={order.orderId}>
247
+ <OrderListCard order={order} />
248
+ </li>
249
+ ))}
250
+ </ul>
251
+ )}
252
+ {more ? (
253
+ <Button type="button" variant="outline" className="self-center" disabled={more.loading} onClick={() => more.load()}>
254
+ {more.loading ? storefrontTranslate("Cargando…") : storefrontTranslate("Ver más pedidos")}
255
+ </Button>
256
+ ) : null}
257
+ </div>
258
+ );
259
+ }
@@ -0,0 +1,70 @@
1
+ import type { CustomerMe } from "@ecomiq/core";
2
+ import type { ReactNode } from "react";
3
+ import { useNavigation } from "react-router";
4
+ import { Button } from "@theme/ui/button";
5
+ import { Input } from "@theme/ui/input";
6
+ import { useStorefrontText, type SectionCatalog } from "../index";
7
+ import { CustomerDocumentFields, ProfileForm, type ProfileActionData } from "../entries/account";
8
+
9
+ export const catalog: SectionCatalog = {
10
+ name: "Mi perfil",
11
+ description: "Nombre, celular y documento del cliente.",
12
+ };
13
+
14
+ function Labeled({ label, hint, className = "", children }: { label: string; hint?: string; className?: string; children: ReactNode }) {
15
+ return (
16
+ <label className={`flex flex-col gap-1.5 text-sm ${className}`}>
17
+ <span className="font-medium">{label}</span>
18
+ {children}
19
+ {hint ? <span className="text-xs text-muted-foreground">{hint}</span> : null}
20
+ </label>
21
+ );
22
+ }
23
+
24
+ export function AccountProfile({ loaderData, actionData }: { loaderData: { me: CustomerMe; countries: { code: string; name: string }[] }; actionData?: ProfileActionData }) {
25
+ const storefrontTranslate = useStorefrontText();
26
+ const { me, countries } = loaderData;
27
+ const busy = useNavigation().state !== "idle";
28
+ return (
29
+ <div className="flex flex-col gap-6">
30
+ <h2 className="text-3xl">{storefrontTranslate("Datos personales")}</h2>
31
+ <ProfileForm className="flex max-w-2xl flex-col gap-4">
32
+ {actionData?.error ? (
33
+ <p role="alert" className="rounded-md bg-destructive/10 px-4 py-3 text-sm text-destructive">
34
+ {storefrontTranslate(actionData.error)}
35
+ </p>
36
+ ) : null}
37
+ {actionData?.saved ? (
38
+ <p role="status" className="rounded-md bg-muted px-4 py-3 text-sm">
39
+ {storefrontTranslate("Datos guardados.")}
40
+ </p>
41
+ ) : null}
42
+ <section className="flex flex-col gap-4 rounded-lg border bg-card p-5 text-card-foreground md:p-6">
43
+ <h3 className="font-heading text-lg">{storefrontTranslate("Tus datos")}</h3>
44
+ <div className="grid gap-4 sm:grid-cols-2">
45
+ <Labeled label={storefrontTranslate("Nombre")}>
46
+ <Input name="firstName" autoComplete="given-name" defaultValue={me.firstName ?? ""} maxLength={100} />
47
+ </Labeled>
48
+ <Labeled label={storefrontTranslate("Apellido")}>
49
+ <Input name="lastName" autoComplete="family-name" defaultValue={me.lastName ?? ""} maxLength={100} />
50
+ </Labeled>
51
+ <Labeled label={storefrontTranslate("Celular")}>
52
+ <Input name="phone" type="tel" autoComplete="tel" defaultValue={me.phone ?? ""} />
53
+ </Labeled>
54
+ <div className="flex flex-col gap-1.5 text-sm">
55
+ <span className="font-medium">{storefrontTranslate("Correo")}</span>
56
+ <p className="flex h-10 items-center text-muted-foreground">{me.email ?? "—"}</p>
57
+ <span className="text-xs text-muted-foreground">{storefrontTranslate("Escríbenos si necesitas cambiarlo.")}</span>
58
+ </div>
59
+ </div>
60
+ </section>
61
+ <section className="rounded-lg border bg-card p-5 text-card-foreground md:p-6">
62
+ <CustomerDocumentFields customer={me} countries={countries} />
63
+ </section>
64
+ <Button type="submit" className="w-fit" disabled={busy}>
65
+ {busy ? storefrontTranslate("Guardando…") : storefrontTranslate("Guardar cambios")}
66
+ </Button>
67
+ </ProfileForm>
68
+ </div>
69
+ );
70
+ }