@thorprovider/storefront 0.3.1 → 0.4.0-mvp.2
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/README.md +321 -152
- package/VENDOR.md +69 -0
- package/assets/openspec/config.yaml +38 -0
- package/assets/templates/AGENTS.md +76 -0
- package/assets/templates/app/app/[[...slug]]/page.tsx +54 -2
- package/assets/templates/app/app/[[...slug]]/renderer.tsx +13 -2
- package/assets/templates/app/app/globals.css +5 -8
- package/assets/templates/app/app/layout.tsx +17 -7
- package/assets/templates/app/app/robots.ts +19 -0
- package/assets/templates/app/app/sitemap.ts +71 -0
- package/assets/templates/app/lib/__STOREFRONT__/actions.ts +612 -0
- package/assets/templates/app/lib/__STOREFRONT__/cart-state.ts +66 -0
- package/assets/templates/app/lib/__STOREFRONT__/catalog.ts +50 -57
- package/assets/templates/app/lib/__STOREFRONT__/commerce.ts +679 -0
- package/assets/templates/app/lib/__STOREFRONT__/composition.ts +26 -0
- package/assets/templates/app/lib/__STOREFRONT__/handlers.core.ts +197 -0
- package/assets/templates/app/lib/__STOREFRONT__/handlers.ts +5 -36
- package/assets/templates/app/lib/__STOREFRONT__/icon-map.ts +27 -0
- package/assets/templates/app/lib/__STOREFRONT__/mappers.ts +13 -11
- package/assets/templates/app/lib/__STOREFRONT__/registry.tsx +264 -51
- package/assets/templates/app/lib/__STOREFRONT__/runtime.ts +6 -3
- package/assets/templates/app/lib/__STOREFRONT__/schema.ts +136 -0
- package/assets/templates/app/lib/__STOREFRONT__/section-observation.ts +182 -0
- package/assets/templates/app/lib/__STOREFRONT__/section-sources.ts +130 -0
- package/assets/templates/app/lib/__STOREFRONT__/session.core.ts +470 -0
- package/assets/templates/app/lib/__STOREFRONT__/session.ts +169 -0
- package/assets/templates/app/lib/__STOREFRONT__/shell/content.ts +120 -0
- package/assets/templates/app/lib/__STOREFRONT__/shell/props.ts +38 -0
- package/assets/templates/app/lib/__STOREFRONT__/spec/index.ts +129 -10
- package/assets/templates/app/lib/__STOREFRONT__/spec/page-root.ts +5 -1
- package/assets/templates/app/lib/__STOREFRONT__/spec/seo.ts +191 -0
- package/assets/templates/app/lib/__STOREFRONT__/state.core.ts +257 -0
- package/assets/templates/app/lib/__STOREFRONT__/state.ts +7 -31
- package/assets/templates/app/lib/__STOREFRONT__/store-context.ts +161 -0
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/cta.client.tsx +25 -0
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/cta.tsx +16 -0
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/faq.client.tsx +24 -0
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/faq.tsx +5 -18
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/index.ts +18 -0
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/logoCloud.tsx +26 -14
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/pricing.tsx +36 -18
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/products.client.tsx +100 -0
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/products.tsx +19 -0
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/schema.cta.ts +19 -0
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/schema.faq.ts +18 -0
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/schema.products.ts +39 -0
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/statistics.tsx +35 -14
- package/assets/templates/app/lib/__STOREFRONT__/views/sections/testimonials.tsx +31 -13
- package/assets/templates/app/lib/__STOREFRONT__/views/types.ts +5 -3
- package/assets/templates/features/checkout/handlers.ts +159 -0
- package/assets/templates/features/checkout/state.ts +61 -0
- package/assets/templates/features/customer-auth/handlers.ts +59 -0
- package/assets/templates/features/customer-auth/state.ts +45 -0
- package/assets/templates/features/recommendations/state.ts +11 -0
- package/assets/templates/views/account/content.ts +35 -0
- package/assets/templates/views/account/index.tsx +114 -0
- package/assets/templates/views/account/registry.tsx +439 -0
- package/assets/templates/views/account/schema.ts +53 -0
- package/assets/templates/views/cart/content.ts +11 -0
- package/assets/templates/views/cart/data.ts +23 -0
- package/assets/templates/views/cart/index.tsx +53 -0
- package/assets/templates/views/cart/props.ts +12 -0
- package/assets/templates/views/cart/registry.tsx +81 -0
- package/assets/templates/views/cart/schema.ts +52 -0
- package/assets/templates/views/category/assembly/assembly.json +29 -0
- package/assets/templates/views/category/assembly/index.skeleton.tsx +251 -0
- package/assets/templates/views/category/assembly/registry.skeleton.tsx +34 -0
- package/assets/templates/views/category/assembly/slots/breadcrumb/Breadcrumb/binding.json +5 -0
- package/assets/templates/views/category/assembly/slots/breadcrumb/Breadcrumb/catalog.part +4 -0
- package/assets/templates/views/category/assembly/slots/breadcrumb/Breadcrumb/element.part +7 -0
- package/assets/templates/views/category/assembly/slots/breadcrumb/Breadcrumb/registry.part +18 -0
- package/assets/templates/views/category/assembly/slots/filter/CategoryFilter2/catalog.part +5 -0
- package/assets/templates/views/category/assembly/slots/filter/CategoryFilter2/element.part +34 -0
- package/assets/templates/views/category/assembly/slots/filter/CategoryFilter2/registry.part +71 -0
- package/assets/templates/views/category/content.ts +30 -0
- package/assets/templates/views/category/data.ts +12 -0
- package/assets/templates/views/category/index.tsx +299 -0
- package/assets/templates/views/category/props.ts +23 -0
- package/assets/templates/views/category/registry.tsx +122 -0
- package/assets/templates/views/category/schema.ts +91 -0
- package/assets/templates/views/checkout/content.ts +105 -0
- package/assets/templates/views/checkout/data.ts +23 -0
- package/assets/templates/views/checkout/index.tsx +111 -0
- package/assets/templates/views/checkout/props.ts +49 -0
- package/assets/templates/views/checkout/registry.tsx +217 -0
- package/assets/templates/views/checkout/schema.ts +229 -0
- package/assets/templates/views/home/assembly/assembly.json +33 -0
- package/assets/templates/views/home/assembly/index.skeleton.tsx +90 -0
- package/assets/templates/views/home/assembly/registry.skeleton.tsx +25 -0
- package/assets/templates/views/home/assembly/slots/benefits/Feature1/binding.json +5 -0
- package/assets/templates/views/home/assembly/slots/benefits/Feature1/catalog.part +4 -0
- package/assets/templates/views/home/assembly/slots/benefits/Feature1/element.part +4 -0
- package/assets/templates/views/home/assembly/slots/benefits/Feature1/registry.part +11 -0
- package/assets/templates/views/home/assembly/slots/benefits/Feature2/binding.json +5 -0
- package/assets/templates/views/home/assembly/slots/benefits/Feature2/catalog.part +4 -0
- package/assets/templates/views/home/assembly/slots/benefits/Feature2/element.part +4 -0
- package/assets/templates/views/home/assembly/slots/benefits/Feature2/registry.part +10 -0
- package/assets/templates/views/home/assembly/slots/categories/ProductCategory2/binding.json +5 -0
- package/assets/templates/views/home/assembly/slots/categories/ProductCategory2/catalog.part +4 -0
- package/assets/templates/views/home/assembly/slots/categories/ProductCategory2/element.part +5 -0
- package/assets/templates/views/home/assembly/slots/categories/ProductCategory2/registry.part +16 -0
- package/assets/templates/views/home/assembly/slots/hero/StorefrontHero1/binding.json +5 -0
- package/assets/templates/views/home/assembly/slots/hero/StorefrontHero1/catalog.part +4 -0
- package/assets/templates/views/home/assembly/slots/hero/StorefrontHero1/element.part +5 -0
- package/assets/templates/views/home/assembly/slots/hero/StorefrontHero1/registry.part +26 -0
- package/assets/templates/views/home/content.ts +70 -0
- package/assets/templates/views/home/data.ts +24 -0
- package/assets/templates/views/home/index.tsx +57 -85
- package/assets/templates/views/home/props.ts +22 -0
- package/assets/templates/views/home/registry.tsx +38 -22
- package/assets/templates/views/home/schema.ts +93 -0
- package/assets/templates/views/product/content.ts +25 -0
- package/assets/templates/views/product/data.ts +50 -0
- package/assets/templates/views/product/index.tsx +148 -0
- package/assets/templates/views/product/props.ts +27 -0
- package/assets/templates/views/product/registry.tsx +103 -0
- package/assets/templates/views/product/schema.ts +121 -0
- package/assets/templates/views/static/content.ts +99 -0
- package/assets/templates/views/static/index.tsx +60 -0
- package/assets/templates/views/static/registry.tsx +66 -0
- package/assets/templates/views/static/schema.ts +45 -0
- package/bin/storefront.js +2424 -148
- package/examples/merchandising/category-led.json +37 -0
- package/examples/merchandising/collection-led.json +37 -0
- package/package.json +15 -9
- package/recipes/archetypes.json +28 -14
- package/recipes/catalog.json +400 -0
- package/recipes/catalog.mjs +128 -0
- package/recipes/catalog.schema.json +64 -0
- package/recipes/feature.schema.json +89 -0
- package/recipes/features.json +162 -0
- package/recipes/manifest.schema.json +69 -0
- package/recipes/operations.schema.json +43 -0
- package/recipes/recipe.schema.json +11 -2
- package/recipes/recipes.json +76 -19
- package/recipes/sections.json +34 -5
- package/recipes/validate.mjs +838 -32
- package/scripts/candidate.mjs +236 -0
- package/scripts/composers.mjs +160 -0
- package/scripts/env-file.mjs +86 -0
- package/scripts/file-classes.mjs +121 -0
- package/scripts/logical-controls.mjs +61 -0
- package/scripts/manifest.mjs +298 -0
- package/scripts/migrate-english-routes.mjs +276 -0
- package/scripts/operation-registry.mjs +256 -0
- package/scripts/operations.mjs +720 -0
- package/scripts/ownership-conflict.mjs +356 -0
- package/scripts/pinning.mjs +573 -0
- package/scripts/plan-apply.mjs +987 -0
- package/scripts/preflight.mjs +51 -0
- package/scripts/reconcile.mjs +549 -0
- package/scripts/render-templates.mjs +338 -68
- package/scripts/schema-validate.mjs +132 -0
- package/scripts/section-compat.mjs +300 -0
- package/scripts/section-config.mjs +253 -0
- package/scripts/section-operations.mjs +508 -0
- package/scripts/starter.mjs +17 -0
- package/scripts/sync-assets.mjs +22 -15
- package/scripts/theme/color.mjs +185 -0
- package/scripts/theme/css-theme.mjs +233 -0
- package/scripts/theme/fonts.mjs +123 -0
- package/scripts/theme/import-export.mjs +125 -0
- package/scripts/theme/preset.mjs +93 -0
- package/scripts/theme/theme-plan.mjs +292 -0
- package/scripts/theme/tokens.mjs +137 -0
- package/scripts/view-assembly.mjs +337 -0
- package/scripts/view-selection.mjs +211 -0
- package/skills/sf-feature/SKILL.md +80 -0
- package/skills/sf-setup/SKILL.md +79 -0
- package/skills/sf-theme-gen/SKILL.md +100 -30
- package/skills/sf-theme-gen/references/shadcn-theming.md +87 -0
- package/skills/{shadcn-theming/references/templates → sf-theme-gen/references}/theme-setup.md +15 -19
- package/skills/{shadcn-theming → sf-theme-gen}/references/theming-guide.md +6 -11
- package/skills/sf-view-gen/SKILL.md +146 -93
- package/skills/sf-view-gen/assets/recipes/archetypes.json +28 -14
- package/skills/sf-view-gen/assets/recipes/catalog.json +400 -0
- package/skills/sf-view-gen/assets/recipes/catalog.schema.json +64 -0
- package/skills/sf-view-gen/assets/recipes/features.json +162 -0
- package/skills/sf-view-gen/assets/recipes/recipes.json +76 -19
- package/skills/sf-view-gen/assets/recipes/sections.json +34 -5
- package/skills/sf-view-gen/assets/templates/views/sections/cta.client.tsx +25 -0
- package/skills/sf-view-gen/assets/templates/views/sections/cta.tsx +16 -0
- package/skills/sf-view-gen/assets/templates/views/sections/faq.client.tsx +13 -9
- package/skills/sf-view-gen/assets/templates/views/sections/faq.tsx +2 -7
- package/skills/sf-view-gen/assets/templates/views/sections/logoCloud.client.tsx +12 -8
- package/skills/sf-view-gen/assets/templates/views/sections/logoCloud.tsx +2 -7
- package/skills/sf-view-gen/assets/templates/views/sections/pricing.client.tsx +14 -10
- package/skills/sf-view-gen/assets/templates/views/sections/pricing.tsx +2 -9
- package/skills/sf-view-gen/assets/templates/views/sections/products.client.tsx +100 -0
- package/skills/sf-view-gen/assets/templates/views/sections/products.tsx +19 -0
- package/skills/sf-view-gen/assets/templates/views/sections/schema.cta.ts +19 -0
- package/skills/sf-view-gen/assets/templates/views/sections/schema.faq.ts +18 -0
- package/skills/sf-view-gen/assets/templates/views/sections/schema.logoCloud.ts +19 -0
- package/skills/sf-view-gen/assets/templates/views/sections/schema.pricing.ts +26 -0
- package/skills/sf-view-gen/assets/templates/views/sections/schema.products.ts +39 -0
- package/skills/sf-view-gen/assets/templates/views/sections/schema.statistics.ts +25 -0
- package/skills/sf-view-gen/assets/templates/views/sections/schema.testimonials.ts +23 -0
- package/skills/sf-view-gen/assets/templates/views/sections/statistics.client.tsx +16 -8
- package/skills/sf-view-gen/assets/templates/views/sections/statistics.tsx +2 -7
- package/skills/sf-view-gen/assets/templates/views/sections/testimonials.client.tsx +13 -9
- package/skills/sf-view-gen/assets/templates/views/sections/testimonials.tsx +2 -5
- package/skills/{json-render-core/SKILL.md → sf-view-gen/references/json-render-core.md} +4 -27
- package/skills/{json-render-next/SKILL.md → sf-view-gen/references/json-render-next.md} +5 -8
- package/skills/{json-render-react/SKILL.md → sf-view-gen/references/json-render-react.md} +3 -5
- package/skills/{json-render-shadcn/SKILL.md → sf-view-gen/references/json-render-shadcn.md} +3 -5
- package/skills/sf-view-gen/references/views.md +58 -33
- package/skills/sf-view-gen/scripts/catalog.mjs +128 -0
- package/skills/sf-view-gen/scripts/schema-validate.mjs +132 -0
- package/skills/sf-view-gen/scripts/validate.mjs +838 -32
- package/skills/storefront-workflow/SKILL.md +179 -0
- package/skills/{storefront-best-practices/reference/design.md → storefront-workflow/references/design-consistency.md} +13 -29
- package/CHANGELOG.md +0 -61
- package/commands/sf-add-view.md +0 -26
- package/commands/sf-theme.md +0 -20
- package/commands/sf-view.md +0 -25
- package/skills/building-storefronts/SKILL.md +0 -178
- package/skills/building-storefronts/references/frontend-integration.md +0 -229
- package/skills/json-render-remotion/SKILL.md +0 -111
- package/skills/json-render-solid/SKILL.md +0 -204
- package/skills/nextjs-shadcn/SKILL.md +0 -367
- package/skills/nextjs-shadcn/references/architecture.md +0 -499
- package/skills/nextjs-shadcn/references/project-setup.md +0 -162
- package/skills/nextjs-shadcn/references/shadcn-platform.md +0 -261
- package/skills/nextjs-shadcn/references/sidebar.md +0 -274
- package/skills/nextjs-shadcn/references/styling.md +0 -555
- package/skills/sf-view-gen/assets/templates/views/category/index.tsx +0 -86
- package/skills/sf-view-gen/assets/templates/views/category/registry.tsx +0 -48
- package/skills/sf-view-gen/assets/templates/views/checkout/index.tsx +0 -192
- package/skills/sf-view-gen/assets/templates/views/checkout/registry.tsx +0 -45
- package/skills/sf-view-gen/assets/templates/views/product/index.tsx +0 -122
- package/skills/sf-view-gen/assets/templates/views/product/registry.tsx +0 -49
- package/skills/sf-view-gen/assets/templates/views/user-panel/index.tsx +0 -168
- package/skills/sf-view-gen/assets/templates/views/user-panel/registry.tsx +0 -49
- package/skills/shadcn-component-discovery/SKILL.md +0 -273
- package/skills/shadcn-component-discovery/references/registries.md +0 -226
- package/skills/shadcn-theming/SKILL.md +0 -104
- package/skills/storefront-best-practices/SKILL.md +0 -421
- package/skills/storefront-best-practices/reference/components/breadcrumbs.md +0 -123
- package/skills/storefront-best-practices/reference/components/cart-popup.md +0 -189
- package/skills/storefront-best-practices/reference/components/country-selector.md +0 -298
- package/skills/storefront-best-practices/reference/components/footer.md +0 -112
- package/skills/storefront-best-practices/reference/components/hero.md +0 -241
- package/skills/storefront-best-practices/reference/components/megamenu.md +0 -239
- package/skills/storefront-best-practices/reference/components/navbar.md +0 -397
- package/skills/storefront-best-practices/reference/components/popups.md +0 -221
- package/skills/storefront-best-practices/reference/components/product-card.md +0 -125
- package/skills/storefront-best-practices/reference/components/product-reviews.md +0 -217
- package/skills/storefront-best-practices/reference/components/product-slider.md +0 -174
- package/skills/storefront-best-practices/reference/components/search.md +0 -101
- package/skills/storefront-best-practices/reference/connecting-to-backend.md +0 -391
- package/skills/storefront-best-practices/reference/features/promotions.md +0 -307
- package/skills/storefront-best-practices/reference/features/wishlist.md +0 -230
- package/skills/storefront-best-practices/reference/layouts/account.md +0 -380
- package/skills/storefront-best-practices/reference/layouts/cart.md +0 -316
- package/skills/storefront-best-practices/reference/layouts/checkout.md +0 -486
- package/skills/storefront-best-practices/reference/layouts/home-page.md +0 -264
- package/skills/storefront-best-practices/reference/layouts/order-confirmation.md +0 -231
- package/skills/storefront-best-practices/reference/layouts/product-details.md +0 -527
- package/skills/storefront-best-practices/reference/layouts/product-listing.md +0 -520
- package/skills/storefront-best-practices/reference/layouts/static-pages.md +0 -356
- package/skills/storefront-best-practices/reference/medusa.md +0 -307
- /package/skills/{storefront-best-practices/reference → storefront-workflow/references}/mobile-responsiveness.md +0 -0
- /package/skills/{storefront-best-practices/reference → storefront-workflow/references}/seo.md +0 -0
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
// Thor Commerce view module: checkout
|
|
2
|
-
// Server Component module: elements + catalog entries + route + loader only.
|
|
3
|
-
// The client-side component mappings live in ./registry.tsx ('use client'); this
|
|
4
|
-
// module imports them as data so the RSC graph never evaluates @json-render/react
|
|
5
|
-
// on the server. Registered by importing it in ../index.ts. Recipe: recipes.json -> "checkout".
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
getPaymentMethodsByRegion,
|
|
9
|
-
getRegionCountries,
|
|
10
|
-
} from '@thorprovider/runtime/commerce'
|
|
11
|
-
import { z } from 'zod'
|
|
12
|
-
import { pageRoot } from '../../spec/page-root'
|
|
13
|
-
import type { StorefrontElement } from '../../spec/types'
|
|
14
|
-
import type { ViewModule } from '../types'
|
|
15
|
-
import { registry } from './registry'
|
|
16
|
-
|
|
17
|
-
const elements: Record<string, StorefrontElement> = {
|
|
18
|
-
'checkout.view': {
|
|
19
|
-
type: 'Checkout',
|
|
20
|
-
visible: { $state: '/lastOrder', not: true },
|
|
21
|
-
props: {
|
|
22
|
-
title: 'Finalizar compra',
|
|
23
|
-
description: 'Completa tus datos para recibir tu pedido.',
|
|
24
|
-
orderSummary: {
|
|
25
|
-
items: { $state: '/cart' },
|
|
26
|
-
shipping: { $state: '/cartTotals/shipping' },
|
|
27
|
-
tax: { $state: '/cartTotals/tax' },
|
|
28
|
-
discount: { $state: '/cartTotals/discount' },
|
|
29
|
-
promoDiscount: { $state: '/cartTotals/promoDiscount' },
|
|
30
|
-
},
|
|
31
|
-
countries: { $state: '/checkoutCountries' },
|
|
32
|
-
paymentMethods: { $state: '/checkoutPaymentMethods' },
|
|
33
|
-
values: {
|
|
34
|
-
email: { $state: '/checkout/email' },
|
|
35
|
-
firstName: { $state: '/checkout/firstName' },
|
|
36
|
-
lastName: { $state: '/checkout/lastName' },
|
|
37
|
-
phone: { $state: '/checkout/phone' },
|
|
38
|
-
address: { $state: '/checkout/address' },
|
|
39
|
-
city: { $state: '/checkout/city' },
|
|
40
|
-
state: { $state: '/checkout/state' },
|
|
41
|
-
zipCode: { $state: '/checkout/zipCode' },
|
|
42
|
-
country: { $state: '/checkout/country' },
|
|
43
|
-
paymentMethod: { $state: '/checkout/paymentMethod' },
|
|
44
|
-
cardNumber: { $state: '/checkout/cardNumber' },
|
|
45
|
-
expiryDate: { $state: '/checkout/expiryDate' },
|
|
46
|
-
cvv: { $state: '/checkout/cvv' },
|
|
47
|
-
cardName: { $state: '/checkout/cardName' },
|
|
48
|
-
saveInfo: { $state: '/checkout/saveInfo' },
|
|
49
|
-
sameAsBilling: { $state: '/checkout/sameAsBilling' },
|
|
50
|
-
newsletter: { $state: '/checkout/newsletter' },
|
|
51
|
-
promoCode: { $state: '/checkout/promoCode' },
|
|
52
|
-
},
|
|
53
|
-
validation: {
|
|
54
|
-
email: {
|
|
55
|
-
validateOn: 'blur',
|
|
56
|
-
checks: [
|
|
57
|
-
{ type: 'required', message: 'Ingresa tu correo electrónico.' },
|
|
58
|
-
{ type: 'email', message: 'Ingresa un correo válido.' },
|
|
59
|
-
],
|
|
60
|
-
},
|
|
61
|
-
firstName: {
|
|
62
|
-
checks: [{ type: 'required', message: 'Ingresa tu nombre.' }],
|
|
63
|
-
},
|
|
64
|
-
lastName: {
|
|
65
|
-
checks: [{ type: 'required', message: 'Ingresa tus apellidos.' }],
|
|
66
|
-
},
|
|
67
|
-
phone: {
|
|
68
|
-
checks: [
|
|
69
|
-
{
|
|
70
|
-
type: 'pattern',
|
|
71
|
-
args: { pattern: '^[+]?[0-9]{7,15}$' },
|
|
72
|
-
message: 'Ingresa un teléfono válido.',
|
|
73
|
-
},
|
|
74
|
-
],
|
|
75
|
-
},
|
|
76
|
-
address: {
|
|
77
|
-
checks: [{ type: 'required', message: 'Ingresa tu dirección.' }],
|
|
78
|
-
},
|
|
79
|
-
city: {
|
|
80
|
-
checks: [{ type: 'required', message: 'Ingresa la ciudad.' }],
|
|
81
|
-
},
|
|
82
|
-
state: {
|
|
83
|
-
checks: [{ type: 'required', message: 'Ingresa la provincia.' }],
|
|
84
|
-
},
|
|
85
|
-
country: {
|
|
86
|
-
checks: [{ type: 'required', message: 'Selecciona tu país.' }],
|
|
87
|
-
},
|
|
88
|
-
zipCode: {
|
|
89
|
-
checks: [
|
|
90
|
-
{ type: 'required', message: 'Ingresa el código postal.' },
|
|
91
|
-
{
|
|
92
|
-
type: 'pattern',
|
|
93
|
-
args: { pattern: '^[0-9]{4,5}$' },
|
|
94
|
-
message: 'Código postal inválido.',
|
|
95
|
-
},
|
|
96
|
-
],
|
|
97
|
-
},
|
|
98
|
-
paymentMethod: {
|
|
99
|
-
checks: [{ type: 'required', message: 'Selecciona un método de pago.' }],
|
|
100
|
-
},
|
|
101
|
-
},
|
|
102
|
-
fieldDescriptions: {
|
|
103
|
-
email: 'Usaremos este correo para el seguimiento del pedido.',
|
|
104
|
-
phone: 'Te contactaremos para coordinar la entrega.',
|
|
105
|
-
promoCode: 'Aplica códigos promocionales válidos.',
|
|
106
|
-
},
|
|
107
|
-
},
|
|
108
|
-
on: { placeOrder: { action: 'placeOrder' } },
|
|
109
|
-
},
|
|
110
|
-
'checkout.confirmation': {
|
|
111
|
-
type: 'CheckoutConfirmation',
|
|
112
|
-
visible: { $state: '/lastOrder' },
|
|
113
|
-
props: {
|
|
114
|
-
order: { $state: '/lastOrder' },
|
|
115
|
-
orderLines: { $state: '/lastOrderLines' },
|
|
116
|
-
fulfilmentDetails: {
|
|
117
|
-
Confirmed: {
|
|
118
|
-
stage: 'Confirmed',
|
|
119
|
-
summary: 'Pago autorizado y el pedido fue enviado a preparación.',
|
|
120
|
-
location: 'Centro de distribución',
|
|
121
|
-
at: { $state: '/orderPlaced' },
|
|
122
|
-
},
|
|
123
|
-
Packed: {
|
|
124
|
-
stage: 'Packed',
|
|
125
|
-
summary: 'Los artículos fueron seleccionados y empacados.',
|
|
126
|
-
location: 'Centro de distribución',
|
|
127
|
-
at: null,
|
|
128
|
-
},
|
|
129
|
-
Shipped: {
|
|
130
|
-
stage: 'Shipped',
|
|
131
|
-
summary: 'El paquete fue entregado al transportista.',
|
|
132
|
-
location: 'En tránsito',
|
|
133
|
-
at: null,
|
|
134
|
-
},
|
|
135
|
-
Delivered: {
|
|
136
|
-
stage: 'Delivered',
|
|
137
|
-
summary: 'Entregado en tu dirección.',
|
|
138
|
-
location: 'Tu dirección',
|
|
139
|
-
at: null,
|
|
140
|
-
},
|
|
141
|
-
},
|
|
142
|
-
},
|
|
143
|
-
on: { continueShopping: { action: 'continueShopping' } },
|
|
144
|
-
},
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
const catalog = {
|
|
148
|
-
Checkout: {
|
|
149
|
-
props: z.record(z.string(), z.unknown()),
|
|
150
|
-
description: 'Checkout form with order summary, shipping and payment steps.',
|
|
151
|
-
},
|
|
152
|
-
CheckoutConfirmation: {
|
|
153
|
-
props: z.record(z.string(), z.unknown()),
|
|
154
|
-
description: 'Order confirmation with fulfilment progress.',
|
|
155
|
-
},
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
export const checkout: ViewModule = {
|
|
159
|
-
name: 'checkout',
|
|
160
|
-
elements,
|
|
161
|
-
catalog,
|
|
162
|
-
registry,
|
|
163
|
-
route: {
|
|
164
|
-
path: '/checkout',
|
|
165
|
-
loaderName: 'checkout',
|
|
166
|
-
layout: 'default',
|
|
167
|
-
metadata: {
|
|
168
|
-
title: 'Finalizar compra',
|
|
169
|
-
description: 'Completa tus datos de envío y pago para recibir tu pedido.',
|
|
170
|
-
},
|
|
171
|
-
entry: pageRoot(
|
|
172
|
-
'checkout',
|
|
173
|
-
['checkout.view', 'checkout.confirmation'],
|
|
174
|
-
elements,
|
|
175
|
-
),
|
|
176
|
-
},
|
|
177
|
-
loader: {
|
|
178
|
-
checkout: async () => {
|
|
179
|
-
const [countries, paymentMethods] = await Promise.all([
|
|
180
|
-
getRegionCountries(),
|
|
181
|
-
getPaymentMethodsByRegion(),
|
|
182
|
-
])
|
|
183
|
-
return {
|
|
184
|
-
checkoutCountries: countries.map((country) => ({
|
|
185
|
-
value: country.code,
|
|
186
|
-
label: country.name,
|
|
187
|
-
})),
|
|
188
|
-
checkoutPaymentMethods: paymentMethods,
|
|
189
|
-
}
|
|
190
|
-
},
|
|
191
|
-
},
|
|
192
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
// Thor Commerce view registry fragment: checkout
|
|
4
|
-
// Client boundary for the checkout view. Imports value bindings from
|
|
5
|
-
// @json-render/react and components from @thorprovider/blocks — both must stay
|
|
6
|
-
// on the client side of the RSC graph. Kept separate from index.tsx so the view
|
|
7
|
-
// spec (elements/catalog/route/loader) stays a pure Server Component module.
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
CheckoutForm1 as CheckoutBlock,
|
|
11
|
-
CheckoutConfirmation as CheckoutConfirmationBlock,
|
|
12
|
-
} from '@thorprovider/blocks'
|
|
13
|
-
import { useStateStore } from '@json-render/react'
|
|
14
|
-
import type { ViewRegistry } from '../types'
|
|
15
|
-
|
|
16
|
-
export const registry: ViewRegistry = {
|
|
17
|
-
Checkout: ({ props, emit }) => {
|
|
18
|
-
const { state, set } = useStateStore()
|
|
19
|
-
return (
|
|
20
|
-
<CheckoutBlock
|
|
21
|
-
title={props.title as string}
|
|
22
|
-
description={props.description as string}
|
|
23
|
-
orderSummary={props.orderSummary as never}
|
|
24
|
-
countries={props.countries as never}
|
|
25
|
-
paymentMethods={props.paymentMethods as never}
|
|
26
|
-
values={props.values as never}
|
|
27
|
-
fieldDescriptions={props.fieldDescriptions as never}
|
|
28
|
-
onChange={(field, value) => set(`/checkout/${field}`, value)}
|
|
29
|
-
onSubmit={() => emit('placeOrder')}
|
|
30
|
-
submitting={Boolean(state.checkoutPending)}
|
|
31
|
-
submitError={(state.checkoutError as string | null) ?? undefined}
|
|
32
|
-
/>
|
|
33
|
-
)
|
|
34
|
-
},
|
|
35
|
-
CheckoutConfirmation: ({ props, emit }) =>
|
|
36
|
-
props.order ? (
|
|
37
|
-
<CheckoutConfirmationBlock
|
|
38
|
-
order={props.order as never}
|
|
39
|
-
orderLines={props.orderLines as never}
|
|
40
|
-
fulfilmentDetails={props.fulfilmentDetails as never}
|
|
41
|
-
continueShoppingHref="#"
|
|
42
|
-
onContinueShopping={() => emit('continueShopping')}
|
|
43
|
-
/>
|
|
44
|
-
) : null,
|
|
45
|
-
}
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
// Thor Commerce view module: product
|
|
2
|
-
// Server Component module: elements + catalog entries + route + loader only.
|
|
3
|
-
// The client-side component mappings live in ./registry.tsx ('use client'); this
|
|
4
|
-
// module imports them as data so the RSC graph never evaluates @json-render/react
|
|
5
|
-
// on the server. Registered by importing it in ../index.ts. Recipe: recipes.json -> "product".
|
|
6
|
-
|
|
7
|
-
import { getProductByHandle } from '@thorprovider/runtime/commerce'
|
|
8
|
-
import { z } from 'zod'
|
|
9
|
-
import { pageRoot } from '../../spec/page-root'
|
|
10
|
-
import type { StorefrontElement } from '../../spec/types'
|
|
11
|
-
import type { ViewModule } from '../types'
|
|
12
|
-
import { registry } from './registry'
|
|
13
|
-
|
|
14
|
-
const elements: Record<string, StorefrontElement> = {
|
|
15
|
-
'product.overview': {
|
|
16
|
-
type: 'ProductOverview',
|
|
17
|
-
props: {
|
|
18
|
-
product: { $state: '/selectedProduct' },
|
|
19
|
-
},
|
|
20
|
-
on: { addToCart: { action: 'addToCart' } },
|
|
21
|
-
},
|
|
22
|
-
'product.reviews': {
|
|
23
|
-
type: 'Reviews',
|
|
24
|
-
props: {
|
|
25
|
-
pageTitle: 'Opiniones de clientes',
|
|
26
|
-
pageDescription: 'Lo que dicen quienes ya compraron este producto.',
|
|
27
|
-
reviews: [
|
|
28
|
-
{
|
|
29
|
-
id: 1,
|
|
30
|
-
userName: 'Carlos M.',
|
|
31
|
-
date: '2026-07-12',
|
|
32
|
-
rating: 5,
|
|
33
|
-
content: 'Excelente calidad y llegó antes de lo esperado. Muy buena compra.',
|
|
34
|
-
likes: 12,
|
|
35
|
-
comments: 2,
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
id: 2,
|
|
39
|
-
userName: 'Ana R.',
|
|
40
|
-
date: '2026-07-03',
|
|
41
|
-
rating: 4,
|
|
42
|
-
content: 'Funciona muy bien y la atención fue rápida. Lo recomiendo.',
|
|
43
|
-
likes: 7,
|
|
44
|
-
comments: 1,
|
|
45
|
-
},
|
|
46
|
-
{
|
|
47
|
-
id: 3,
|
|
48
|
-
userName: 'Luis P.',
|
|
49
|
-
date: '2026-06-28',
|
|
50
|
-
rating: 5,
|
|
51
|
-
content: 'Producto robusto, tal como aparece en la descripción.',
|
|
52
|
-
likes: 5,
|
|
53
|
-
comments: 0,
|
|
54
|
-
},
|
|
55
|
-
],
|
|
56
|
-
form: {
|
|
57
|
-
title: 'Deja tu opinión',
|
|
58
|
-
description: 'Tu experiencia ayuda a otros clientes.',
|
|
59
|
-
nameLabel: 'Nombre',
|
|
60
|
-
emailLabel: 'Correo electrónico',
|
|
61
|
-
reviewLabel: 'Tu reseña',
|
|
62
|
-
namePlaceholder: 'Tu nombre',
|
|
63
|
-
emailPlaceholder: 'tucorreo@ejemplo.cu',
|
|
64
|
-
reviewPlaceholder: 'Cuéntanos tu experiencia...',
|
|
65
|
-
submitButtonText: 'Publicar reseña',
|
|
66
|
-
submittingButtonText: 'Publicando...',
|
|
67
|
-
},
|
|
68
|
-
reviewsPerPage: 3,
|
|
69
|
-
},
|
|
70
|
-
on: {
|
|
71
|
-
submitReview: { action: 'submitReview' },
|
|
72
|
-
toggleReviewLike: { action: 'toggleReviewLike' },
|
|
73
|
-
},
|
|
74
|
-
},
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const catalog = {
|
|
78
|
-
ProductOverview: {
|
|
79
|
-
props: z.object({
|
|
80
|
-
product: z.record(z.string(), z.unknown()),
|
|
81
|
-
sizesLabel: z.string().optional(),
|
|
82
|
-
colorLabel: z.string().optional(),
|
|
83
|
-
reviewsLabel: z.string().optional(),
|
|
84
|
-
addToCartLabel: z.string().optional(),
|
|
85
|
-
}),
|
|
86
|
-
description: 'Detalle de producto: galería, precio, variantes y añadir al carrito.',
|
|
87
|
-
},
|
|
88
|
-
Reviews: {
|
|
89
|
-
props: z.object({
|
|
90
|
-
pageTitle: z.string().optional(),
|
|
91
|
-
pageDescription: z.string().optional(),
|
|
92
|
-
reviews: z.array(z.record(z.string(), z.unknown())),
|
|
93
|
-
form: z.record(z.string(), z.unknown()).optional(),
|
|
94
|
-
reviewsPerPage: z.number().optional(),
|
|
95
|
-
}),
|
|
96
|
-
description: 'Opiniones de clientes con resumen de valoración.',
|
|
97
|
-
},
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
export const product: ViewModule = {
|
|
101
|
-
name: 'product',
|
|
102
|
-
elements,
|
|
103
|
-
catalog,
|
|
104
|
-
registry,
|
|
105
|
-
route: {
|
|
106
|
-
path: '/productos/[id]',
|
|
107
|
-
loaderName: 'product',
|
|
108
|
-
layout: 'default',
|
|
109
|
-
metadata: {
|
|
110
|
-
title: 'Producto',
|
|
111
|
-
description: 'Detalles del producto seleccionado.',
|
|
112
|
-
},
|
|
113
|
-
entry: pageRoot('product', ['product.overview', 'product.reviews'], elements),
|
|
114
|
-
},
|
|
115
|
-
loader: {
|
|
116
|
-
product: async (params) => {
|
|
117
|
-
const id = Array.isArray(params.id) ? params.id[0] : params.id
|
|
118
|
-
const selectedProduct = await getProductByHandle(String(id))
|
|
119
|
-
return { selectedProduct }
|
|
120
|
-
},
|
|
121
|
-
},
|
|
122
|
-
}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
// Thor Commerce view registry fragment: product
|
|
4
|
-
// Client boundary for the product view. Imports value bindings from
|
|
5
|
-
// @json-render/react and components from @thorprovider/blocks — both must stay
|
|
6
|
-
// on the client side of the RSC graph. Kept separate from index.tsx so the view
|
|
7
|
-
// spec (elements/catalog/route/loader) stays a pure Server Component module.
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
ProductOverview1 as ProductOverviewBlock,
|
|
11
|
-
ReviewRating1 as ReviewsBlock,
|
|
12
|
-
} from '@thorprovider/blocks'
|
|
13
|
-
import { useStateStore } from '@json-render/react'
|
|
14
|
-
import type { ViewRegistry } from '../types'
|
|
15
|
-
|
|
16
|
-
export const registry: ViewRegistry = {
|
|
17
|
-
ProductOverview: ({ props, emit }) => {
|
|
18
|
-
const { set } = useStateStore()
|
|
19
|
-
return (
|
|
20
|
-
<ProductOverviewBlock
|
|
21
|
-
product={props.product as never}
|
|
22
|
-
onAddToCart={(product) => {
|
|
23
|
-
set('/lastClicked', product)
|
|
24
|
-
emit('addToCart')
|
|
25
|
-
}}
|
|
26
|
-
onToggleWishlist={() => {}}
|
|
27
|
-
/>
|
|
28
|
-
)
|
|
29
|
-
},
|
|
30
|
-
Reviews: ({ props, emit }) => {
|
|
31
|
-
const { set } = useStateStore()
|
|
32
|
-
return (
|
|
33
|
-
<ReviewsBlock
|
|
34
|
-
pageTitle={props.pageTitle as string}
|
|
35
|
-
pageDescription={props.pageDescription as string}
|
|
36
|
-
reviews={props.reviews as never}
|
|
37
|
-
form={props.form as never}
|
|
38
|
-
reviewsPerPage={props.reviewsPerPage as number}
|
|
39
|
-
onToggleReviewLike={() => {
|
|
40
|
-
emit('toggleReviewLike')
|
|
41
|
-
}}
|
|
42
|
-
onSubmitReview={(data) => {
|
|
43
|
-
set('/lastReview', data)
|
|
44
|
-
emit('submitReview')
|
|
45
|
-
}}
|
|
46
|
-
/>
|
|
47
|
-
)
|
|
48
|
-
},
|
|
49
|
-
}
|
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
// Thor Commerce view module: user-panel
|
|
2
|
-
// Server Component module: elements + catalog entries + route + loader only.
|
|
3
|
-
// The client-side component mappings live in ./registry.tsx ('use client'); this
|
|
4
|
-
// module imports them as data so the RSC graph never evaluates @json-render/react
|
|
5
|
-
// on the server. Registered by importing it in ../index.ts. Recipe: recipes.json -> "user-panel".
|
|
6
|
-
|
|
7
|
-
import { getCatalog } from '@thorprovider/runtime/commerce'
|
|
8
|
-
import { z } from 'zod'
|
|
9
|
-
import { pageRoot } from '../../spec/page-root'
|
|
10
|
-
import type { StorefrontElement } from '../../spec/types'
|
|
11
|
-
import type { ViewModule } from '../types'
|
|
12
|
-
import { registry } from './registry'
|
|
13
|
-
|
|
14
|
-
const elements: Record<string, StorefrontElement> = {
|
|
15
|
-
'userPanel.shell': {
|
|
16
|
-
type: 'AppShell',
|
|
17
|
-
props: {
|
|
18
|
-
brandName: '__SITE_NAME__',
|
|
19
|
-
navGroupLabel: 'Mi cuenta',
|
|
20
|
-
navItems: [
|
|
21
|
-
{ label: 'Mis pedidos', href: '/cuenta', icon: 'package', active: true },
|
|
22
|
-
{ label: 'Mi perfil', href: '/cuenta/perfil', icon: 'user' },
|
|
23
|
-
{ label: 'Ajustes', href: '/cuenta/ajustes', icon: 'settings' },
|
|
24
|
-
],
|
|
25
|
-
user: {
|
|
26
|
-
name: 'Cliente Demo',
|
|
27
|
-
email: 'cliente@ejemplo.com',
|
|
28
|
-
initials: 'CD',
|
|
29
|
-
},
|
|
30
|
-
breadcrumb: [
|
|
31
|
-
{ label: 'Inicio', href: '/' },
|
|
32
|
-
{ label: 'Mi cuenta' },
|
|
33
|
-
],
|
|
34
|
-
pageTitle: 'Mi cuenta',
|
|
35
|
-
pageDescription: 'Consulta tus pedidos recientes y gestiona tu cuenta.',
|
|
36
|
-
action: { label: 'Seguir comprando', href: '/' },
|
|
37
|
-
stats: [
|
|
38
|
-
{ label: 'Pedidos', value: '1' },
|
|
39
|
-
{ label: 'Estado', value: 'Confirmado' },
|
|
40
|
-
],
|
|
41
|
-
},
|
|
42
|
-
children: ['userPanel.orderHistory'],
|
|
43
|
-
},
|
|
44
|
-
'userPanel.orderHistory': {
|
|
45
|
-
type: 'OrderHistory',
|
|
46
|
-
props: {
|
|
47
|
-
orders: { $state: '/lastOrderLines' },
|
|
48
|
-
title: 'Historial de pedidos',
|
|
49
|
-
description: 'Tus compras recientes y su estado.',
|
|
50
|
-
},
|
|
51
|
-
on: {
|
|
52
|
-
viewOrder: { action: 'viewOrder' },
|
|
53
|
-
downloadInvoice: { action: 'downloadInvoice' },
|
|
54
|
-
},
|
|
55
|
-
},
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const ctaSchema = z.object({ label: z.string(), href: z.string().optional() })
|
|
59
|
-
|
|
60
|
-
const appShellNavItemSchema = z.object({
|
|
61
|
-
label: z.string(),
|
|
62
|
-
href: z.string(),
|
|
63
|
-
icon: z.enum([
|
|
64
|
-
'layout-dashboard',
|
|
65
|
-
'package',
|
|
66
|
-
'user',
|
|
67
|
-
'settings',
|
|
68
|
-
'home',
|
|
69
|
-
'shopping-cart',
|
|
70
|
-
'bar-chart-3',
|
|
71
|
-
'users',
|
|
72
|
-
'folder-kanban',
|
|
73
|
-
]),
|
|
74
|
-
active: z.boolean().optional(),
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
const appShellUserSchema = z.object({
|
|
78
|
-
name: z.string(),
|
|
79
|
-
email: z.string(),
|
|
80
|
-
initials: z.string(),
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
const breadcrumbItemSchema = z.object({
|
|
84
|
-
label: z.string(),
|
|
85
|
-
href: z.string().optional(),
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
const statSchema = z.object({
|
|
89
|
-
label: z.string(),
|
|
90
|
-
value: z.string(),
|
|
91
|
-
})
|
|
92
|
-
|
|
93
|
-
const orderLineSchema = z.object({
|
|
94
|
-
name: z.string(),
|
|
95
|
-
image: z.string(),
|
|
96
|
-
color: z.string(),
|
|
97
|
-
size: z.string(),
|
|
98
|
-
quantity: z.number(),
|
|
99
|
-
price: z.number(),
|
|
100
|
-
orderDate: z.string(),
|
|
101
|
-
})
|
|
102
|
-
|
|
103
|
-
const catalog = {
|
|
104
|
-
AppShell: {
|
|
105
|
-
props: z.object({
|
|
106
|
-
brandName: z.string().optional(),
|
|
107
|
-
navGroupLabel: z.string().optional(),
|
|
108
|
-
navItems: z.array(appShellNavItemSchema).optional(),
|
|
109
|
-
user: appShellUserSchema.optional(),
|
|
110
|
-
breadcrumb: z.array(breadcrumbItemSchema).optional(),
|
|
111
|
-
pageTitle: z.string().optional(),
|
|
112
|
-
pageDescription: z.string().optional(),
|
|
113
|
-
action: ctaSchema.optional(),
|
|
114
|
-
stats: z.array(statSchema).optional(),
|
|
115
|
-
}),
|
|
116
|
-
slots: ['default'],
|
|
117
|
-
description: 'Panel de cuenta con navegación lateral, cabecera y área de contenido.',
|
|
118
|
-
},
|
|
119
|
-
OrderHistory: {
|
|
120
|
-
props: z.object({
|
|
121
|
-
orders: z.array(orderLineSchema),
|
|
122
|
-
title: z.string().optional(),
|
|
123
|
-
description: z.string().optional(),
|
|
124
|
-
}),
|
|
125
|
-
description: 'Historial de pedidos del cliente.',
|
|
126
|
-
},
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
export const userPanel: ViewModule = {
|
|
130
|
-
name: 'user-panel',
|
|
131
|
-
elements,
|
|
132
|
-
catalog,
|
|
133
|
-
registry,
|
|
134
|
-
route: {
|
|
135
|
-
path: '/cuenta',
|
|
136
|
-
loaderName: 'userPanel',
|
|
137
|
-
layout: 'default',
|
|
138
|
-
metadata: {
|
|
139
|
-
title: 'Mi cuenta',
|
|
140
|
-
description: 'Consulta tu historial de pedidos y gestiona tu cuenta.',
|
|
141
|
-
},
|
|
142
|
-
entry: pageRoot('userPanel', ['userPanel.shell'], elements),
|
|
143
|
-
},
|
|
144
|
-
loader: {
|
|
145
|
-
userPanel: async () => {
|
|
146
|
-
const { products } = await getCatalog()
|
|
147
|
-
const placedAt = new Date()
|
|
148
|
-
const orderDate = placedAt.toISOString().slice(0, 10)
|
|
149
|
-
const lastOrderLines = products.slice(0, 3).map((product, index) => ({
|
|
150
|
-
name: product.title,
|
|
151
|
-
image: product.image,
|
|
152
|
-
color: 'Estándar',
|
|
153
|
-
size: 'Único',
|
|
154
|
-
quantity: index + 1,
|
|
155
|
-
price: product.price,
|
|
156
|
-
orderDate,
|
|
157
|
-
}))
|
|
158
|
-
const lastOrder = {
|
|
159
|
-
number: `TC-${placedAt.getFullYear()}0001`,
|
|
160
|
-
placedAt: placedAt.toISOString(),
|
|
161
|
-
email: 'cliente@ejemplo.com',
|
|
162
|
-
status: 'Confirmado',
|
|
163
|
-
total: lastOrderLines.reduce((sum, line) => sum + line.price * line.quantity, 0),
|
|
164
|
-
}
|
|
165
|
-
return { lastOrder, lastOrderLines, orderPlaced: lastOrderLines.length > 0 }
|
|
166
|
-
},
|
|
167
|
-
},
|
|
168
|
-
}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
// Thor Commerce view registry fragment: user-panel
|
|
4
|
-
// Client boundary for the user-panel view. Imports value bindings from
|
|
5
|
-
// @json-render/react and components from @thorprovider/blocks — both must stay
|
|
6
|
-
// on the client side of the RSC graph. Kept separate from index.tsx so the view
|
|
7
|
-
// spec (elements/catalog/route/loader) stays a pure Server Component module.
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
AppShell1 as AppShellBlock,
|
|
11
|
-
OrderHistory1 as OrderHistoryBlock,
|
|
12
|
-
} from '@thorprovider/blocks'
|
|
13
|
-
import { useStateStore } from '@json-render/react'
|
|
14
|
-
import type { ViewRegistry } from '../types'
|
|
15
|
-
|
|
16
|
-
export const registry: ViewRegistry = {
|
|
17
|
-
AppShell: ({ props, children }) => (
|
|
18
|
-
<AppShellBlock
|
|
19
|
-
brandName={props.brandName as string}
|
|
20
|
-
navGroupLabel={props.navGroupLabel as string}
|
|
21
|
-
navItems={props.navItems as never}
|
|
22
|
-
user={props.user as never}
|
|
23
|
-
breadcrumb={props.breadcrumb as never}
|
|
24
|
-
pageTitle={props.pageTitle as string}
|
|
25
|
-
pageDescription={props.pageDescription as string}
|
|
26
|
-
action={props.action as never}
|
|
27
|
-
stats={props.stats as never}
|
|
28
|
-
>
|
|
29
|
-
{children}
|
|
30
|
-
</AppShellBlock>
|
|
31
|
-
),
|
|
32
|
-
OrderHistory: ({ props, emit }) => {
|
|
33
|
-
const { set } = useStateStore()
|
|
34
|
-
return (
|
|
35
|
-
<OrderHistoryBlock
|
|
36
|
-
orders={props.orders as never}
|
|
37
|
-
title={props.title as string}
|
|
38
|
-
description={props.description as string}
|
|
39
|
-
onViewDetails={() => {
|
|
40
|
-
set('/orderDetailsOpen', true)
|
|
41
|
-
emit('viewOrder')
|
|
42
|
-
}}
|
|
43
|
-
onDownloadInvoice={() => {
|
|
44
|
-
emit('downloadInvoice')
|
|
45
|
-
}}
|
|
46
|
-
/>
|
|
47
|
-
)
|
|
48
|
-
},
|
|
49
|
-
}
|