@ecomiq/storefront 2.1.4 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +377 -76
- package/dist/account-Dx4e3syi.js +258 -0
- package/dist/account-forms-AVk71ko7.js +39 -0
- package/dist/account-forms.d.ts +13 -0
- package/dist/account.d.ts +240 -0
- package/dist/address-defaults-BqjRhS82.js +14 -0
- package/dist/address-defaults.d.ts +11 -0
- package/dist/analytics/analytics-CG1Qagwl.js +148 -0
- package/dist/analytics/analytics.d.ts +1 -0
- package/dist/analytics/config-DJr-GRhs.js +62 -0
- package/dist/analytics/config.d.ts +22 -0
- package/dist/analytics/consent-B13rBpBs.js +57 -0
- package/dist/analytics/consent-banner-9QvRRy8v.js +239 -0
- package/dist/analytics/consent-banner.d.ts +20 -0
- package/dist/analytics/cookies-pLozllyB.js +100 -0
- package/dist/analytics/cookies.d.ts +6 -0
- package/dist/analytics/destinations-iECrlLIr.js +144 -0
- package/dist/analytics/events-Dt81tIp1.js +102 -0
- package/dist/analytics/events.d.ts +51 -0
- package/dist/analytics/tracker-p4yaoOyk.js +51 -0
- package/dist/api-cache-DsuIn5hX.js +159 -0
- package/dist/bank-accounts-DlEczQQ5.js +81 -0
- package/dist/bank-accounts.d.ts +4 -0
- package/dist/captcha-DAqaIx8m.js +117 -0
- package/dist/captcha.d.ts +34 -0
- package/dist/cart-D7DxZ2lD.js +30 -0
- package/dist/cart-actions-Bsub_FFG.js +116 -0
- package/dist/cart-actions.d.ts +15 -0
- package/dist/cart-drawer-B7PPsR69.js +22 -0
- package/dist/cart-drawer.d.ts +9 -0
- package/dist/cart-form-y9P1r_EX.js +81 -0
- package/dist/cart-form.d.ts +24 -0
- package/dist/cart-summary-ur2VWKr-.js +89 -0
- package/dist/cart-summary.d.ts +31 -0
- package/dist/cart.d.ts +4 -0
- package/dist/catalog-7gJ-l5hW.js +67 -0
- package/dist/catalog-hooks-B7ZP4wYY.js +312 -0
- package/dist/catalog-hooks.d.ts +111 -0
- package/dist/catalog.d.ts +5 -0
- package/dist/checkout-DVWSXANi.js +474 -0
- package/dist/checkout-form-CbOIdENC.js +131 -0
- package/dist/checkout-form.d.ts +20 -0
- package/dist/checkout.d.ts +86 -0
- package/dist/complaint-book-BvwLvfx0.js +117 -0
- package/dist/complaint-book.d.ts +62 -0
- package/dist/culqi-authentication-BGr20vAJ.js +204 -0
- package/dist/culqi-authentication.d.ts +15 -0
- package/dist/culqi-checkout-CTXpKgp_.js +55 -0
- package/dist/culqi-three-ds-HP3mfrvV.js +33 -0
- package/dist/culqi-three-ds.d.ts +29 -0
- package/dist/customer-avatar-CJXSDroK.js +12 -0
- package/dist/customer-avatar.d.ts +5 -0
- package/dist/customer-cookies-DHOgFAMV.js +45 -0
- package/dist/customer-csrf-C1oDX-Py.js +17 -0
- package/dist/customer-csrf.d.ts +3 -0
- package/dist/customer-document-fields-C1K-_DAD.js +70 -0
- package/dist/customer-document-fields.d.ts +9 -0
- package/dist/customer-login-form-C7AC6vXd.js +144 -0
- package/dist/customer-login-form.d.ts +17 -0
- package/dist/customer-registration-form-BEm_NEfP.js +93 -0
- package/dist/customer-registration-form.d.ts +8 -0
- package/dist/document-url-CGsAl5Tf.js +9 -0
- package/dist/documents-T1mzc_j8.js +38 -0
- package/dist/documents.d.ts +16 -0
- package/dist/entries/account.d.ts +11 -0
- package/dist/entries/account.js +10 -0
- package/dist/entries/analytics.d.ts +6 -0
- package/dist/entries/analytics.js +5 -0
- package/dist/entries/cart.d.ts +8 -0
- package/dist/entries/cart.js +7 -0
- package/dist/entries/checkout.d.ts +12 -0
- package/dist/entries/checkout.js +11 -0
- package/dist/entries/order.d.ts +11 -0
- package/dist/entries/order.js +11 -0
- package/dist/favicon-YpyhVJ9H.js +28 -0
- package/dist/favicon.d.ts +4 -0
- package/dist/form-BtQcbXlJ.js +18 -0
- package/dist/form-contracts-BNpHaTGJ.js +166 -0
- package/dist/form-contracts.d.ts +42 -0
- package/dist/form.d.ts +3 -0
- package/dist/hidden-CCWtOWKR.js +3 -0
- package/dist/hidden.d.ts +4 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.js +50 -0
- package/dist/invoice-fields-BG0HjL6T.js +103 -0
- package/dist/invoice-fields.d.ts +39 -0
- package/dist/links-kFxBZfdb.js +96 -0
- package/dist/links.d.ts +21 -0
- package/dist/mercadopago-checkout-DC7RXa8k.js +27 -0
- package/dist/mercadopago-dialog-UTQev0MG.js +180 -0
- package/dist/mercadopago-dialog.d.ts +21 -0
- package/dist/money-DtGOtDri.js +32 -0
- package/dist/money.d.ts +1 -0
- package/dist/optimistic-cart-BveVOHuh.js +53 -0
- package/dist/optimistic-cart.d.ts +16 -0
- package/dist/order-display-DTt5WBbc.js +112 -0
- package/dist/order-display.d.ts +20 -0
- package/dist/order-draft-DxV1Uhm3.js +38 -0
- package/dist/order-draft.d.ts +16 -0
- package/dist/order-pages-Dm6l5m0m.js +38 -0
- package/dist/order-pages.d.ts +12 -0
- package/dist/order-payment-continuation-D_d5PGA4.js +212 -0
- package/dist/order-payment-continuation.d.ts +10 -0
- package/dist/order-payment-in-review-x4gdLFHZ.js +65 -0
- package/dist/order-payment-in-review.d.ts +5 -0
- package/dist/order-status-BJXLJwxq.js +162 -0
- package/dist/order-status.d.ts +89 -0
- package/dist/order-view-9IlBg5AF.js +62 -0
- package/dist/order-view.d.ts +12 -0
- package/dist/page-action-Ctkf4xC6.js +7 -0
- package/dist/page-seo-a5FJl8x5.js +262 -0
- package/dist/page-seo.d.ts +34 -0
- package/dist/pages-Ca_Gt6mq.js +150 -0
- package/dist/pages.d.ts +45 -0
- package/dist/payment-dialog-frame-B-Q_xQ94.js +57 -0
- package/dist/payment-logo-BoPaGJc_.js +46 -0
- package/dist/payment-logo-svgs-By9lDTLK.js +20 -0
- package/dist/payment-logo.d.ts +11 -0
- package/dist/payment-logos-BYvdwYyJ.js +23 -0
- package/dist/payment-methods-B8ocTgFZ.js +73 -0
- package/dist/payment-methods.d.ts +58 -0
- package/dist/payment-return-5cjypwIw.js +7 -0
- package/dist/place-CmW4hBWY.js +13 -0
- package/dist/place.d.ts +4 -0
- package/dist/preview-BiIBif3C.js +427 -0
- package/dist/preview-address-Cf0sJ-9p.js +21 -0
- package/dist/preview-cart-Dg2CVktS.js +376 -0
- package/dist/product-preview-BspMAecJ.js +51 -0
- package/dist/product-preview.d.ts +5 -0
- package/dist/product-variants-BNDHvs1y.js +46 -0
- package/dist/product-variants.d.ts +12 -0
- package/dist/public-pages-XtwlaLwt.js +194 -0
- package/dist/public-pages.d.ts +67 -0
- package/dist/registration-CpDcv8ql.js +91 -0
- package/dist/registration.d.ts +12 -0
- package/dist/request-security-CRsRMgwj.js +76 -0
- package/dist/rich-text-M-Ju8RL4.js +9 -0
- package/dist/rich-text.d.ts +5 -0
- package/dist/route-text-DcJw2SsK.js +9 -0
- package/dist/route-text.d.ts +4 -0
- package/dist/section-preview-CmsMl3yu.js +83 -0
- package/dist/section-preview.d.ts +12 -0
- package/dist/sections/account-addresses.d.ts +18 -0
- package/dist/sections/account-addresses.js +375 -0
- package/dist/sections/account-order.d.ts +12 -0
- package/dist/sections/account-order.js +592 -0
- package/dist/sections/account-orders.d.ts +8 -0
- package/dist/sections/account-orders.js +359 -0
- package/dist/sections/account-profile.d.ts +16 -0
- package/dist/sections/account-profile.js +123 -0
- package/dist/sections/checkout.d.ts +24 -0
- package/dist/sections/checkout.js +963 -0
- package/dist/sections/complaint-book.d.ts +8 -0
- package/dist/sections/complaint-book.js +538 -0
- package/dist/sections/design-system.d.ts +1 -0
- package/dist/sections/design-system.js +310 -0
- package/dist/sections/draft-invoice.d.ts +20 -0
- package/dist/sections/draft-invoice.js +158 -0
- package/dist/sections/order-tracking.d.ts +19 -0
- package/dist/sections/order-tracking.js +141 -0
- package/dist/sections-CNUMWTF_.js +77 -0
- package/dist/sections.d.ts +19 -0
- package/dist/seo-GpDRhAAA.js +78 -0
- package/dist/session-CKvmFJyg.js +379 -0
- package/dist/session.d.ts +24 -0
- package/dist/settings-B0NO2A6Y.js +78 -0
- package/dist/settings.d.ts +51 -0
- package/dist/source-marker-DhqSkW7n.js +4 -0
- package/dist/sources-B-3JFJfb.js +46 -0
- package/dist/sources.d.ts +7 -0
- package/dist/store-8Q-_LFrQ.js +152 -0
- package/dist/store-contact--hY6CoFb.js +19 -0
- package/dist/store-contact.d.ts +6 -0
- package/dist/store.d.ts +17 -0
- package/dist/storefront-language-DrMjVbmk.js +29 -0
- package/dist/storefront-language.d.ts +14 -0
- package/dist/storefront-text-D25ae1qf.js +11 -0
- package/dist/storefront-text-en-ljjjSS4q.js +1030 -0
- package/dist/storefront-text-pt-BtHaJLcp.js +1030 -0
- package/dist/storefront-text.d.ts +4 -0
- package/dist/stripe-dialog-Ev9s3Z62.js +396 -0
- package/dist/stripe-dialog.d.ts +30 -0
- package/dist/telemetry-HuZXWBPi.js +114 -0
- package/dist/telemetry.d.ts +10 -0
- package/dist/templates-CAqoNyTW.js +40 -0
- package/dist/templates.d.ts +15 -0
- package/dist/urls-CpGQPxvf.js +71 -0
- package/dist/urls.d.ts +18 -0
- package/dist/use-checkout-CZcxXJXi.js +42 -0
- package/dist/use-checkout-payment-9R-zacrJ.js +80 -0
- package/dist/use-checkout-payment.d.ts +18 -0
- package/dist/use-checkout.d.ts +36 -0
- package/dist/use-culqi-checkout-CrjLAipU.js +109 -0
- package/dist/use-order-payment-BKIz_IO0.js +45 -0
- package/dist/use-order-payment.d.ts +18 -0
- package/dist/use-payment-token-CErx-tN-.js +105 -0
- package/dist/vite-payment-logos-kziu7wKb.js +27 -0
- package/dist/vite-payment-logos.d.ts +24 -0
- package/dist/vite-public-assets-DW2fgtVb.js +209 -0
- package/dist/vite-public-assets.d.ts +29 -0
- package/dist/vite-sections-DTBr0-Kg.js +464 -0
- package/dist/vite-sections.d.ts +21 -0
- package/dist/vite-theme-ui-BMO-CDi3.js +41 -0
- package/dist/vite-theme-ui.d.ts +10 -0
- package/dist/vite.d.ts +36 -0
- package/dist/vite.js +127 -0
- package/dist/voucher-payment-CVFDZ1L8.js +66 -0
- package/dist/worker-CNi-gzCu.js +86 -0
- package/dist/worker.d.ts +27 -0
- package/package.json +100 -76
- package/src/sections/account-addresses.tsx +215 -0
- package/src/sections/account-order.tsx +424 -0
- package/src/sections/account-orders.tsx +259 -0
- package/src/sections/account-profile.tsx +70 -0
- package/src/sections/checkout.tsx +586 -0
- package/src/sections/complaint-book.tsx +325 -0
- package/src/sections/design-system.tsx +146 -0
- package/src/sections/draft-invoice.tsx +105 -0
- package/src/sections/order-tracking.tsx +81 -0
- package/src/vite-client.d.ts +4 -0
- package/bin/ecomiq.mjs +0 -179
- package/public/design-bridge.js +0 -318
- package/src/api-proxy.ts +0 -194
- package/src/auth/create-storefront-auth.ts +0 -94
- package/src/auth/ecomiq-oauth-password-client.ts +0 -26
- package/src/auth/ecomiq-oauth-password-constants.ts +0 -24
- package/src/auth/ecomiq-oauth-password-plugin.ts +0 -294
- package/src/auth/ecomiq-oauth-password-types.ts +0 -24
- package/src/auth/ecomiq-storefront-sign-in.ts +0 -44
- package/src/auth/env.ts +0 -7
- package/src/auth/secure-cookies.ts +0 -23
- package/src/auth/storefront-auth-base-url.ts +0 -117
- package/src/auth/storefront-auth.ts +0 -7
- package/src/cart-session.ts +0 -239
- package/src/client.ts +0 -48
- package/src/codegen.mjs +0 -801
- package/src/components/account/customer-addresses-panel.tsx +0 -678
- package/src/components/account/customer-order-detail-panel.tsx +0 -285
- package/src/components/account/customer-orders-panel.tsx +0 -192
- package/src/components/account/customer-profile-panel.tsx +0 -379
- package/src/components/checkout/cart-sync.ts +0 -143
- package/src/components/checkout/checkout-contact-section.tsx +0 -76
- package/src/components/checkout/checkout-external-update-banner.tsx +0 -15
- package/src/components/checkout/checkout-form-controls.tsx +0 -139
- package/src/components/checkout/checkout-line-items.tsx +0 -43
- package/src/components/checkout/checkout-order-summary.tsx +0 -165
- package/src/components/checkout/checkout-payment-section.tsx +0 -212
- package/src/components/checkout/checkout-session-view.tsx +0 -564
- package/src/components/checkout/checkout-shipping-address-section.tsx +0 -400
- package/src/components/checkout/checkout-shipping-section.tsx +0 -98
- package/src/components/checkout/checkout-states.tsx +0 -73
- package/src/components/checkout/checkout-step-card.tsx +0 -101
- package/src/components/checkout/checkout-steps.ts +0 -111
- package/src/components/checkout/form-schema.ts +0 -281
- package/src/components/checkout/format.ts +0 -15
- package/src/components/checkout/index.ts +0 -5
- package/src/components/checkout/map-customer-to-checkout.ts +0 -188
- package/src/components/checkout/types.ts +0 -41
- package/src/components/checkout/use-checkout-customer-prefill.ts +0 -409
- package/src/components/checkout/use-checkout-geo.ts +0 -50
- package/src/components/checkout/use-checkout-session.ts +0 -640
- package/src/components/hero.tsx +0 -291
- package/src/config.d.ts +0 -94
- package/src/config.mjs +0 -146
- package/src/format-money.ts +0 -31
- package/src/health.ts +0 -90
- package/src/hooks/index.ts +0 -9
- package/src/hooks/recently-viewed.ts +0 -125
- package/src/index.ts +0 -349
- package/src/link.tsx +0 -2
- package/src/pages/account/account-page-skeleton.tsx +0 -69
- package/src/pages/account/account-page-view.tsx +0 -270
- package/src/pages/account/account-shell.tsx +0 -101
- package/src/pages/account/parse-account-route.ts +0 -36
- package/src/pages/account.tsx +0 -16
- package/src/pages/api.$.ts +0 -20
- package/src/pages/api.auth.$.ts +0 -16
- package/src/pages/checkout.$checkoutId.tsx +0 -60
- package/src/pages/checkout.tsx +0 -31
- package/src/pages/pages.$pageSlug.tsx +0 -74
- package/src/pages/thank-you.tsx +0 -53
- package/src/providers/auth.tsx +0 -96
- package/src/providers/cart.tsx +0 -275
- package/src/providers/ecomiq.ts +0 -137
- package/src/providers/index.ts +0 -26
- package/src/proxy-api.ts +0 -20
- package/src/public-config.ts +0 -24
- package/src/review-submission.ts +0 -89
- package/src/runtime/context.ts +0 -2
- package/src/runtime/default-layout.tsx +0 -64
- package/src/runtime/head.ts +0 -149
- package/src/runtime/page.tsx +0 -143
- package/src/runtime/postcss-browser-stub.mjs +0 -5
- package/src/server-config-store.ts +0 -35
- package/src/server.ts +0 -286
- package/src/styles.css +0 -76
- package/src/ui/badge.tsx +0 -32
- package/src/ui/button.tsx +0 -31
- package/src/ui/card.tsx +0 -31
- package/src/ui/carousel.tsx +0 -218
- package/src/ui/cn.ts +0 -6
- package/src/ui/index.ts +0 -8
- package/src/ui/separator.tsx +0 -6
- package/src/ui/skeleton.tsx +0 -6
- package/src/ui/storefront-error.tsx +0 -49
- package/src/utils.ts +0 -36
- package/src/vite-inline.mjs +0 -263
- package/templates/__root.tsx +0 -83
- 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,113 +1,414 @@
|
|
|
1
1
|
# @ecomiq/storefront
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
SDK de temas de Ecomiq para React Router 8. Trae los loaders y actions de
|
|
4
|
+
catálogo, carrito, checkout y cuenta de cliente, las secciones editables y los
|
|
5
|
+
plugins de Vite que corren la tienda en un Worker de Cloudflare. Los datos
|
|
6
|
+
vienen de tu tienda en Ecomiq; el diseño es tuyo.
|
|
5
7
|
|
|
6
|
-
|
|
8
|
+
- [Empezar](#empezar)
|
|
9
|
+
- [Archivos de la plataforma](#archivos-de-la-plataforma)
|
|
10
|
+
- [Entradas del paquete](#entradas-del-paquete)
|
|
11
|
+
- [Uso básico](#uso-básico)
|
|
12
|
+
- [Login de clientes](#login-de-clientes)
|
|
13
|
+
- [Registro de clientes](#registro-de-clientes)
|
|
14
|
+
- [Enlaces de catálogo](#enlaces-de-catálogo)
|
|
15
|
+
- [Logos de medios de pago](#logos-de-medios-de-pago)
|
|
16
|
+
- [Medición y consentimiento](#medición-y-consentimiento)
|
|
17
|
+
- [Secciones de Ecomiq](#secciones-de-ecomiq)
|
|
18
|
+
- [Temas publicados](#temas-publicados)
|
|
19
|
+
|
|
20
|
+
## Empezar
|
|
21
|
+
|
|
22
|
+
La forma más corta es bajar el código de tu tienda, que ya trae este paquete:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm create ecomiq@latest mi-tienda
|
|
26
|
+
cd mi-tienda && npm install
|
|
27
|
+
npx ecomiq dev
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Para agregarlo a un proyecto React Router existente:
|
|
7
31
|
|
|
8
32
|
```bash
|
|
9
|
-
npm install @ecomiq/storefront
|
|
10
|
-
# o
|
|
11
|
-
yarn add @ecomiq/storefront
|
|
12
|
-
# o
|
|
13
|
-
pnpm add @ecomiq/storefront
|
|
33
|
+
npm install @ecomiq/storefront @ecomiq/core react react-dom react-router
|
|
14
34
|
```
|
|
15
35
|
|
|
16
|
-
|
|
36
|
+
| Requisito | Versión |
|
|
37
|
+
| ------------ | ---------------------------------------------- |
|
|
38
|
+
| Node.js | 22.22 o superior |
|
|
39
|
+
| React | 19 |
|
|
40
|
+
| React Router | 8, en modo framework con SSR |
|
|
41
|
+
| Runtime | Cloudflare Workers (`@cloudflare/vite-plugin`) |
|
|
42
|
+
|
|
43
|
+
`react` y `react-router` son dependencias peer: el SDK usa las del tema.
|
|
44
|
+
|
|
45
|
+
Guía completa: <https://docs.ecomiq.pe/es/docs/guides/storefront/themes>
|
|
46
|
+
|
|
47
|
+
## Archivos de la plataforma
|
|
17
48
|
|
|
18
|
-
|
|
49
|
+
`ecomiq init` y el editor de Ecomiq escriben estos archivos; no los edites en
|
|
50
|
+
un tema.
|
|
19
51
|
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
import {
|
|
52
|
+
```ts title="vite.config.ts"
|
|
53
|
+
import { publicAssets, catalogLinks, paymentLogos, sectionLoaders, themeUi } from "@ecomiq/storefront/vite";
|
|
54
|
+
import { fileURLToPath } from "node:url";
|
|
55
|
+
import { cloudflare } from "@cloudflare/vite-plugin";
|
|
56
|
+
import { reactRouter } from "@react-router/dev/vite";
|
|
57
|
+
import tailwindcss from "@tailwindcss/vite";
|
|
58
|
+
import { defineConfig } from "vite";
|
|
23
59
|
|
|
24
60
|
export default defineConfig({
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
})
|
|
61
|
+
plugins: [publicAssets(), catalogLinks(), sectionLoaders(), paymentLogos(), themeUi(), cloudflare({ viteEnvironment: { name: "ssr" } }), tailwindcss(), reactRouter()],
|
|
62
|
+
resolve: { alias: { "~": fileURLToPath(new URL("./app", import.meta.url)) } },
|
|
63
|
+
build: { rolldownOptions: { output: { codeSplitting: { groups: [{ name: "icons", test: /[\\/]node_modules[\\/](?:@phosphor-icons|@heroicons|@mdi|@remixicon|lucide-react|iconoir-react)[\\/]/ }] } } } },
|
|
64
|
+
});
|
|
29
65
|
```
|
|
30
66
|
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
import { definePage, serverApi } from '@ecomiq/storefront'
|
|
67
|
+
```ts title="workers/app.ts"
|
|
68
|
+
import { createRequestHandler } from "@ecomiq/storefront";
|
|
34
69
|
|
|
35
|
-
export default
|
|
36
|
-
loader: () => serverApi.getProducts({ page: 1, pageSize: 12 }),
|
|
37
|
-
component: ({ data }) => <pre>{JSON.stringify(data.products, null, 2)}</pre>,
|
|
38
|
-
})
|
|
70
|
+
export default createRequestHandler(() => import("virtual:react-router/server-build"), import.meta.env.MODE);
|
|
39
71
|
```
|
|
40
72
|
|
|
41
|
-
|
|
73
|
+
`wrangler.jsonc` define la tienda en `vars`: `ECOMIQ_STORE` (el slug) y
|
|
74
|
+
`ECOMIQ_API_URL` (la API Storefront, `https://storefront.ecomiq.pe`). Los tipos
|
|
75
|
+
de los módulos virtuales del SDK se cargan con
|
|
76
|
+
`/// <reference types="@ecomiq/storefront/vite-client" />`.
|
|
42
77
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
78
|
+
| Plugin | Qué hace |
|
|
79
|
+
| ------------------ | ----------------------------------------------------------------------------------------------------------- |
|
|
80
|
+
| `publicAssets()` | Versiona las imágenes y fuentes de `public/` y, al compilar, genera sus anchos en WebP. |
|
|
81
|
+
| `catalogLinks()` | Genera `virtual:ecomiq-links` con los enlaces editables del tema. |
|
|
82
|
+
| `sectionLoaders()` | Suma al loader de cada ruta el `load` de las secciones que usa y aplica las plantillas de `app/templates/`. |
|
|
83
|
+
| `paymentLogos()` | Escribe los SVG de medios de pago en el build. |
|
|
84
|
+
| `themeUi()` | Lleva `@theme/ui/*` a `app/components/ui/*` del tema. |
|
|
85
|
+
|
|
86
|
+
## Entradas del paquete
|
|
87
|
+
|
|
88
|
+
| Import | Para qué |
|
|
89
|
+
| ---------------------------------- | ---------------------------------------------------------------- |
|
|
90
|
+
| `@ecomiq/storefront` | Cliente de la tienda, loaders de páginas, sesión, enlaces y SEO. |
|
|
91
|
+
| `@ecomiq/storefront/vite` | Plugins de Vite. |
|
|
92
|
+
| `@ecomiq/storefront/cart` | Carrito: `CartForm`, `useCart`, drawer y carrito optimista. |
|
|
93
|
+
| `@ecomiq/storefront/checkout` | Checkout, medios de pago y comprobante. |
|
|
94
|
+
| `@ecomiq/storefront/account` | Cuenta: pedidos, direcciones y perfil. |
|
|
95
|
+
| `@ecomiq/storefront/order` | Estado y pago de un pedido. |
|
|
96
|
+
| `@ecomiq/storefront/analytics` | Medición, píxeles y aviso de consentimiento. |
|
|
97
|
+
| `@ecomiq/storefront/sections/<id>` | [Secciones de Ecomiq](#secciones-de-ecomiq) listas para usar. |
|
|
98
|
+
| `@ecomiq/storefront/vite-client` | Tipos de los módulos virtuales. |
|
|
99
|
+
|
|
100
|
+
## Uso básico
|
|
101
|
+
|
|
102
|
+
### Loader raíz
|
|
103
|
+
|
|
104
|
+
`store(context)` devuelve el cliente de la tienda configurada en el Worker.
|
|
105
|
+
`readStorefrontLayout` lee la configuración, las colecciones y los enlaces del
|
|
106
|
+
tema en una sola pasada.
|
|
107
|
+
|
|
108
|
+
```tsx title="app/root.tsx"
|
|
109
|
+
import manifestLinks from "virtual:ecomiq-links";
|
|
110
|
+
import { readCart, readStorefrontLayout, store } from "@ecomiq/storefront";
|
|
111
|
+
import { readAnalytics } from "@ecomiq/storefront/analytics";
|
|
112
|
+
import type { Route } from "./+types/root";
|
|
113
|
+
|
|
114
|
+
export { shouldRevalidateCatalogRoot as shouldRevalidate } from "@ecomiq/storefront";
|
|
115
|
+
|
|
116
|
+
export async function loader({ request, context }: Route.LoaderArgs) {
|
|
117
|
+
const client = store(context);
|
|
118
|
+
const [{ settings, storefrontLinks }, cart] = await Promise.all([
|
|
119
|
+
readStorefrontLayout({ client, links: manifestLinks }),
|
|
120
|
+
readCart(request, client),
|
|
121
|
+
]);
|
|
122
|
+
return {
|
|
123
|
+
storefrontLinks,
|
|
124
|
+
publishedPages: settings.cms.pages.map((page) => `/pages/${page.slug}`),
|
|
125
|
+
analytics: readAnalytics(context, settings, cart),
|
|
126
|
+
cart,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
47
129
|
```
|
|
48
130
|
|
|
49
|
-
|
|
131
|
+
### Una sección editable
|
|
50
132
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
133
|
+
Una sección exporta `settings` con lo que el comerciante cambia en el editor.
|
|
134
|
+
El loader de la ruta lee esos ajustes; nunca escribas a mano precios, stock ni
|
|
135
|
+
productos.
|
|
136
|
+
|
|
137
|
+
```tsx title="app/components/sections/new-arrivals.tsx"
|
|
138
|
+
import type { ProductSummary } from "@ecomiq/core";
|
|
139
|
+
import { money, setting, StorefrontLink } from "@ecomiq/storefront";
|
|
140
|
+
|
|
141
|
+
export const settings = {
|
|
142
|
+
arrivals: {
|
|
143
|
+
title: setting.text("Recién llegados", "Título"),
|
|
144
|
+
collection: setting.collection("novedades", "Colección"),
|
|
145
|
+
limit: setting.number(8, "Cantidad"),
|
|
146
|
+
link: setting.link("/collections/novedades", "Enlace"),
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
type Props = { products: ProductSummary[]; currency: string; language: string };
|
|
151
|
+
|
|
152
|
+
export function NewArrivals({ products, currency, language }: Props) {
|
|
153
|
+
return (
|
|
154
|
+
<section>
|
|
155
|
+
<h2>{settings.arrivals.title}</h2>
|
|
156
|
+
<StorefrontLink to={settings.arrivals.link}>Ver todo</StorefrontLink>
|
|
157
|
+
<ul>
|
|
158
|
+
{products.map((product) => (
|
|
159
|
+
<li key={product.id}>
|
|
160
|
+
{product.name} · {money(product.price, currency, language)}
|
|
161
|
+
</li>
|
|
162
|
+
))}
|
|
163
|
+
</ul>
|
|
164
|
+
</section>
|
|
165
|
+
);
|
|
166
|
+
}
|
|
54
167
|
```
|
|
55
168
|
|
|
56
|
-
|
|
169
|
+
```tsx title="app/routes/home.tsx"
|
|
170
|
+
import { pickProducts, store } from "@ecomiq/storefront";
|
|
171
|
+
import { NewArrivals, settings } from "~/components/sections/new-arrivals";
|
|
172
|
+
import type { Route } from "./+types/home";
|
|
57
173
|
|
|
58
|
-
|
|
174
|
+
export async function loader({ context }: Route.LoaderArgs) {
|
|
175
|
+
const client = store(context);
|
|
176
|
+
const [shop, products] = await Promise.all([
|
|
177
|
+
client.getSettings(),
|
|
178
|
+
pickProducts(client, { collection: settings.arrivals.collection, limit: settings.arrivals.limit }),
|
|
179
|
+
]);
|
|
180
|
+
return { products, currency: shop.store.currency, language: shop.store.language };
|
|
181
|
+
}
|
|
59
182
|
|
|
60
|
-
|
|
61
|
-
|
|
183
|
+
export default function Home({ loaderData }: Route.ComponentProps) {
|
|
184
|
+
return <NewArrivals {...loaderData} />;
|
|
185
|
+
}
|
|
62
186
|
```
|
|
63
187
|
|
|
64
|
-
`
|
|
188
|
+
`pickProducts` acepta `collection`, `category`, `products`, `limit` y `sort`.
|
|
189
|
+
Los ajustes disponibles son `setting.text`, `image`, `link`, `collection`,
|
|
190
|
+
`category`, `product`, `products`, `number` y `toggle`. El primer argumento es
|
|
191
|
+
el valor inicial y debe ser literal; el segundo, la etiqueta que ve el
|
|
192
|
+
comerciante.
|
|
65
193
|
|
|
66
|
-
|
|
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.
|
|
194
|
+
### Carrito
|
|
70
195
|
|
|
71
|
-
|
|
196
|
+
```tsx title="app/routes/cart.tsx"
|
|
197
|
+
import { cartAction, loadCart } from "@ecomiq/storefront";
|
|
198
|
+
import type { Route } from "./+types/cart";
|
|
72
199
|
|
|
73
|
-
|
|
200
|
+
export async function loader({ request, context }: Route.LoaderArgs) {
|
|
201
|
+
return loadCart(request, context);
|
|
202
|
+
}
|
|
74
203
|
|
|
75
|
-
|
|
204
|
+
export async function action({ request, context }: Route.ActionArgs) {
|
|
205
|
+
return cartAction(request, context);
|
|
206
|
+
}
|
|
207
|
+
```
|
|
76
208
|
|
|
77
|
-
|
|
78
|
-
|
|
209
|
+
Con un cliente con sesión, el Worker rechaza con 403 cualquier petición que no
|
|
210
|
+
sea de lectura si no trae el token de la sesión: los formularios llevan
|
|
211
|
+
`<CustomerCsrfField />` y los `fetch` propios, la cabecera `X-Customer-Csrf`.
|
|
212
|
+
`FORM_CONTRACTS` lista los `intent` y los campos que acepta cada acción.
|
|
79
213
|
|
|
80
|
-
|
|
81
|
-
import { createDefaultStorefrontDefinition } from '@ecomiq/storefront-definition'
|
|
82
|
-
import { DefinitionRenderer } from '@ecomiq/storefront-definition/react'
|
|
214
|
+
## Login de clientes
|
|
83
215
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
216
|
+
La tienda elige el modo de acceso en Admin, en **Configuración → Compra →
|
|
217
|
+
Cuentas de clientes**. El SDK lee esa configuración: `hosted` redirige a
|
|
218
|
+
Identity y `storefront` muestra el formulario del tema. Los dos modos usan las
|
|
219
|
+
mismas cuentas y la misma sesión de cliente.
|
|
88
220
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
'featured-products': [],
|
|
98
|
-
},
|
|
99
|
-
collectionsBySectionId: {
|
|
100
|
-
'featured-collections': [],
|
|
101
|
-
},
|
|
102
|
-
}}
|
|
103
|
-
/>
|
|
104
|
-
)
|
|
221
|
+
La ruta `/account/login` usa dos helpers:
|
|
222
|
+
|
|
223
|
+
```tsx title="app/routes/login.tsx"
|
|
224
|
+
import { CustomerLoginForm, startCustomerLogin, submitCustomerLogin } from "@ecomiq/storefront";
|
|
225
|
+
import type { Route } from "./+types/login";
|
|
226
|
+
|
|
227
|
+
export function loader({ request, context }: Route.LoaderArgs) {
|
|
228
|
+
return startCustomerLogin(request, context);
|
|
105
229
|
}
|
|
106
|
-
```
|
|
107
230
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
applyStorefrontDefinitionPatch,
|
|
112
|
-
} from '@ecomiq/storefront-definition'
|
|
231
|
+
export function action({ request, context }: Route.ActionArgs) {
|
|
232
|
+
return submitCustomerLogin(request, context);
|
|
233
|
+
}
|
|
113
234
|
```
|
|
235
|
+
|
|
236
|
+
El componente de la ruta pinta `CustomerLoginForm` con
|
|
237
|
+
`data={actionData ?? loaderData}`. Su prop `classNames` define `form`, `field`,
|
|
238
|
+
`label`, `input`, `button`, `secondary`, `error` y `hint`; la página, la
|
|
239
|
+
tipografía, los colores y los controles siguen siendo del tema. Los temas de
|
|
240
|
+
Ecomiq ya traen esta integración.
|
|
241
|
+
|
|
242
|
+
Para una interfaz propia, usa `<Form method="post">` de React Router con los
|
|
243
|
+
mismos helpers y este contrato:
|
|
244
|
+
|
|
245
|
+
| `intent` | Campos del formulario |
|
|
246
|
+
| -------- | --------------------------------------------------------------------------------------------------------------- |
|
|
247
|
+
| `send` | `email` y el token CAPTCHA si está habilitado. |
|
|
248
|
+
| `verify` | `code` de seis dígitos; en el paso `secondFactor`, el código de autenticación o recuperación en `secondFactor`. |
|
|
249
|
+
| `resend` | El token CAPTCHA si está habilitado; respeta `retryAt`. |
|
|
250
|
+
| `reset` | Ninguno; vuelve al ingreso del correo. |
|
|
251
|
+
|
|
252
|
+
Los datos públicos son `step`, `email`, `captcha`, `retryAt` y `error`. La
|
|
253
|
+
transacción OAuth, PKCE y las claves de verificación viajan en una cookie
|
|
254
|
+
firmada HttpOnly; el formulario propio no envía esos valores.
|
|
255
|
+
|
|
256
|
+
CAPTCHA es opcional por tienda e independiente del modo: `off`, Turnstile o
|
|
257
|
+
Google reCAPTCHA v2. `CustomerLoginForm` carga y reinicia el proveedor
|
|
258
|
+
configurado. Una interfaz propia envía `cf-turnstile-response` o
|
|
259
|
+
`g-recaptcha-response`; Turnstile usa la acción `customer_login_code`.
|
|
260
|
+
|
|
261
|
+
## Registro de clientes
|
|
262
|
+
|
|
263
|
+
La tienda configura nombre, apellido, teléfono y fecha de nacimiento como
|
|
264
|
+
`hidden`, `optional` o `required`. Después del código, los dos modos de login
|
|
265
|
+
crean la sesión y consultan `GET /v1/customer/registration`. Si falta completar
|
|
266
|
+
el alta, redirigen a `/account/register?next=...`; el destino se limita a una
|
|
267
|
+
ruta interna segura.
|
|
268
|
+
|
|
269
|
+
La ruta de registro usa `loadCustomerRegistration` en el loader,
|
|
270
|
+
`submitCustomerRegistration` en la action y `CustomerRegistrationForm` con las
|
|
271
|
+
mismas clases del login. Los datos incluyen `registration`, `storeName`, `next`,
|
|
272
|
+
`today` (la fecha local de la tienda) y `error`. Una interfaz propia envía
|
|
273
|
+
`firstName`, `lastName`, `phone` y `dateOfBirth` (`YYYY-MM-DD`) con
|
|
274
|
+
`<CustomerCsrfField />`.
|
|
275
|
+
|
|
276
|
+
`intent=complete` guarda los campos visibles; `intent=skip` omite los opcionales
|
|
277
|
+
cuando no hay obligatorios. Los dos llaman `POST /v1/customer/registration`. El
|
|
278
|
+
backend valida los requisitos vigentes y recuerda que el cliente completó el
|
|
279
|
+
paso: un cliente existente solo vuelve si faltan datos que ahora son
|
|
280
|
+
obligatorios.
|
|
281
|
+
|
|
282
|
+
Las rutas de cuenta usan `requireCustomer`. El checkout admite invitados y llama
|
|
283
|
+
`requireCustomerRegistration(request, context, current)` cuando hay sesión. La
|
|
284
|
+
ruta de registro usa `customer` para no redirigirse a sí misma. La API también
|
|
285
|
+
exige el registro completo antes de las operaciones protegidas.
|
|
286
|
+
|
|
287
|
+
## Enlaces de catálogo
|
|
288
|
+
|
|
289
|
+
Los enlaces a productos y categorías siguen funcionando aunque cambien su
|
|
290
|
+
patrón, slug o URL personalizada. Los menús se resuelven en la configuración
|
|
291
|
+
cacheada del servidor. Para botones y otros enlaces editables, `catalogLinks()`
|
|
292
|
+
genera `virtual:ecomiq-links` al compilar; no analiza código durante las
|
|
293
|
+
visitas.
|
|
294
|
+
|
|
295
|
+
El loader raíz pasa ese manifiesto a `readStorefrontLayout` y devuelve
|
|
296
|
+
`storefrontLinks`. `StorefrontLink` y `StorefrontAnchor` usan ese mapa sin hacer
|
|
297
|
+
peticiones. El SDK deduplica los destinos, agrupa hasta 100 por petición y
|
|
298
|
+
comparte los resultados durante 30 segundos; los cambios se ven al renovar esa
|
|
299
|
+
caché.
|
|
300
|
+
|
|
301
|
+
El loader también devuelve `publishedPages` con las rutas `/pages/<slug>` del
|
|
302
|
+
snapshot público. Los dos componentes ocultan los enlaces a `/pages/...` que
|
|
303
|
+
todavía no están publicados; al publicar la página, el siguiente snapshot
|
|
304
|
+
recupera el enlace sin consultar la API por cada enlace.
|
|
305
|
+
|
|
306
|
+
El selector del editor guarda la identidad del destino con
|
|
307
|
+
`setting.link("/products/cuaderno", "Comprar", { type: "product", id: "42" })`.
|
|
308
|
+
Con referencia devuelve un `CatalogLink`; sin referencia conserva la URL como
|
|
309
|
+
texto. Los dos sirven para `StorefrontLink` y `StorefrontAnchor`, que mantienen
|
|
310
|
+
el destino aunque otro producto reutilice la URL antigua, y reconocen los
|
|
311
|
+
enlaces viejos que resuelve el historial del catálogo. Los enlaces externos,
|
|
312
|
+
las rutas fuera del catálogo, los parámetros y las anclas se conservan.
|
|
313
|
+
|
|
314
|
+
En código propio, usa esos componentes para los enlaces editables. Las tarjetas
|
|
315
|
+
que ya reciben `product.url` o `category.url` pueden usar esos valores tal cual.
|
|
316
|
+
|
|
317
|
+
## Logos de medios de pago
|
|
318
|
+
|
|
319
|
+
`PaymentLogo` pinta un `<img>` de 38×24 que apunta a
|
|
320
|
+
`/assets/payment-logos/<código>.svg`; el JavaScript de la tienda solo lleva los
|
|
321
|
+
nombres. `paymentLogos()` escribe esos SVG en el build del navegador y los sirve
|
|
322
|
+
en desarrollo. `paymentLogoCodes` convierte los medios de pago de la tienda en
|
|
323
|
+
esos códigos.
|
|
324
|
+
|
|
325
|
+
## Medición y consentimiento
|
|
326
|
+
|
|
327
|
+
`@ecomiq/storefront/analytics` carga GA4, Google Tag Manager, Meta Pixel y el
|
|
328
|
+
código propio que la tienda configura en Admin (**Tienda online → Ajustes →
|
|
329
|
+
Medición y píxeles**), y solo después de que el cliente los acepta. Cada
|
|
330
|
+
herramienta pide su finalidad: GA4, «Medición»; Meta Pixel, «Publicidad»;
|
|
331
|
+
Google Tag Manager y el código propio, las dos, porque pueden llevar cualquier
|
|
332
|
+
etiqueta.
|
|
333
|
+
|
|
334
|
+
El loader raíz devuelve `analytics: readAnalytics(context, settings, cart)`, que
|
|
335
|
+
es `null` sin IDs ni código propio y en el lienzo del editor. El `Layout` pinta
|
|
336
|
+
`<Analytics />` y `<ConsentBanner />`. El aviso no trae estilos: el tema le pasa
|
|
337
|
+
`className` y `classNames` (`text`, `link`, `configure`, `options`, `option`,
|
|
338
|
+
`actions`, `accept`, `reject`; sin `configure` usa la clase de `link`). Nombra
|
|
339
|
+
los proveedores que usa la tienda, avisa que los datos pueden tratarse fuera del
|
|
340
|
+
país y enlaza `/pages/privacidad` si existe. «Rechazar» y «Aceptar» van en la
|
|
341
|
+
primera capa; «Configurar» muestra una casilla sin marcar por finalidad y
|
|
342
|
+
«Guardar». Se pinta solo en el navegador.
|
|
343
|
+
|
|
344
|
+
La decisión se guarda 12 meses en la cookie `__Host-ecomiq-consent` como
|
|
345
|
+
`<elección>|<versión>|<fecha ISO>`, por ejemplo
|
|
346
|
+
`analytics.marketing|2.gm.4|2026-10-12T15:30:00.000Z` o `none|…`. La versión
|
|
347
|
+
junta la del aviso, las herramientas activas y la versión publicada de la página
|
|
348
|
+
de privacidad: si cambia, el aviso vuelve a preguntar y nada se carga hasta la
|
|
349
|
+
nueva decisión. Una cookie sin versión no cuenta como decisión. Las cookies del
|
|
350
|
+
SDK usan el prefijo `__Host-` y `Secure`, así que otra tienda del mismo dominio
|
|
351
|
+
no puede escribirlas.
|
|
352
|
+
|
|
353
|
+
Para otros scripts, `window.ecomiq.consent.get()` devuelve
|
|
354
|
+
`{ analytics, marketing, version, date }` o `null`,
|
|
355
|
+
`window.ecomiq.consent.set({ analytics, marketing })` guarda una decisión y el
|
|
356
|
+
evento `ecomiq:consent` avisa cada cambio.
|
|
357
|
+
|
|
358
|
+
Para cambiar o retirar la decisión, el pie del tema pinta `<ConsentLink />`
|
|
359
|
+
(«Cookies», con las clases de los enlaces vecinos): vuelve a abrir el aviso y no
|
|
360
|
+
pinta nada cuando la tienda no mide. Retirar una finalidad borra sus cookies
|
|
361
|
+
(`_ga*`, `_gid`, `_gat*`, `_fbp`, `_fbc`, `_gcl_*`), avisa a Google y Meta y
|
|
362
|
+
recarga la página si alguna herramienta ya estaba cargada.
|
|
363
|
+
|
|
364
|
+
Los loaders del SDK agregan `analytics` a sus datos (`productPage`,
|
|
365
|
+
`resolvePage`, `collectionPage`, `loadCheckout`, `loadOrderStatus`) y la ruta
|
|
366
|
+
`/products` usa `catalogAnalytics(q, result.products)`; las rutas devuelven esa
|
|
367
|
+
clave tal cual. `<Analytics />` envía `page_view`, `view_item`,
|
|
368
|
+
`view_item_list`, `search`, `add_to_cart` y `remove_from_cart` (comparando el
|
|
369
|
+
carrito de la raíz), `begin_checkout` una vez por carrito y `purchase`, que lee
|
|
370
|
+
la cookie `__Host-ecomiq-purchase` de 10 minutos que deja el pago cuando hay
|
|
371
|
+
consentimiento.
|
|
372
|
+
|
|
373
|
+
## Secciones de Ecomiq
|
|
374
|
+
|
|
375
|
+
`@ecomiq/storefront/sections/<id>` trae secciones de página listas:
|
|
376
|
+
|
|
377
|
+
| Sección | Nombre en el editor | Componente y datos |
|
|
378
|
+
| ---------------- | ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
|
|
379
|
+
| `order-tracking` | Seguimiento | `<OrderTracking loaderData={…} />` con `loadTracking`. |
|
|
380
|
+
| `draft-invoice` | Pedido por pagar | `<DraftInvoice loaderData={…} actionData={…} />` con `loadOrderDraft` y `orderDraftAction`. |
|
|
381
|
+
| `complaint-book` | Libro de Reclamaciones | `<ComplaintBook loaderData={…} actionData={…} />` con `loadComplaintBook` y `complaintBookAction`, en la ruta `libro-de-reclamaciones`. |
|
|
382
|
+
|
|
383
|
+
Cada una exporta `catalog` y `settings` como las secciones del tema;
|
|
384
|
+
`complaint-book` no tiene ajustes. `complaintBookLinks(settings)` devuelve el
|
|
385
|
+
enlace del pie solo para tiendas en soles, igual que la API, que responde 404 al
|
|
386
|
+
resto. Su formulario usa `<Captcha>` con la acción Turnstile `complaint_book` y
|
|
387
|
+
va en multipart con hasta 3 adjuntos (JPG, PNG, WebP o PDF de hasta 5 MB);
|
|
388
|
+
`complaintBookAttachmentError(files)` los valida en el navegador y en la action.
|
|
389
|
+
|
|
390
|
+
Las secciones se pintan con el kit del tema: importan `@theme/ui/*` (`button`,
|
|
391
|
+
`input`, `label`, `textarea`, `checkbox`, `radio-group`, `select`), que
|
|
392
|
+
`themeUi()` lleva a `app/components/ui/*`, y solo usan clases con los tokens del
|
|
393
|
+
tema. Si al tema le falta un componente, el build falla con el archivo que falta
|
|
394
|
+
y la sección que lo usa.
|
|
395
|
+
|
|
396
|
+
El código fuente viaja en `src/sections` del paquete: «Personalizar» en el
|
|
397
|
+
editor lo copia a `app/components/sections/<id>.tsx` y apunta la ruta a esa
|
|
398
|
+
copia.
|
|
399
|
+
|
|
400
|
+
## Temas publicados
|
|
401
|
+
|
|
402
|
+
Un tema publicado es un build compilado. Para que una tienda use una función
|
|
403
|
+
nueva del SDK, como el login dentro de la tienda o los enlaces de catálogo, hay
|
|
404
|
+
que actualizar el tema y volver a publicarlo. Cambiar solo la configuración de
|
|
405
|
+
la tienda no modifica builds anteriores. Los cambios posteriores de URLs del
|
|
406
|
+
catálogo no necesitan otra publicación.
|
|
407
|
+
|
|
408
|
+
En desarrollo contra un Identity local, `ECOMIQ_AUTH_URL` (por ejemplo
|
|
409
|
+
`http://localhost:8000`) cambia el transporte del BFF hacia Identity sin tocar
|
|
410
|
+
la autoridad OAuth pública ni la validación TLS.
|
|
411
|
+
|
|
412
|
+
## Licencia
|
|
413
|
+
|
|
414
|
+
MIT
|