@ecomiq/storefront 2.0.8 → 2.0.11

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/bin/ecomiq.mjs CHANGED
@@ -89,7 +89,7 @@ export async function runCli(command = process.argv[2] ?? 'help') {
89
89
  runtime,
90
90
  })
91
91
  banner(
92
- `dev · ${config.name ?? 'tienda'} ${c.dim(`· runtime ${runtime}`)} ${c.dim('http://localhost:' + port)}`,
92
+ `dev · ${config.domain ?? 'tienda'} ${c.dim(`· runtime ${runtime}`)} ${c.dim('http://localhost:' + port)}`,
93
93
  )
94
94
  const server = await createServer({
95
95
  ...viteConfig,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ecomiq/storefront",
3
- "version": "2.0.8",
3
+ "version": "2.0.11",
4
4
  "description": "Micro framework SSR de Ecomiq para storefronts. Páginas, datos y deploy sin configurar nada.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -76,7 +76,7 @@
76
76
  "vite": "^8.1.0",
77
77
  "wrangler": "^4.100.0",
78
78
  "zod": "^3.25.0",
79
- "@ecomiq/core": "^0.1.1"
79
+ "@ecomiq/core": "^0.1.3"
80
80
  },
81
81
  "peerDependencies": {
82
82
  "react": "^19.0.0",
package/src/api-proxy.ts CHANGED
@@ -125,7 +125,7 @@ export async function proxyStorefrontRequest(
125
125
  for (const [key, value] of Object.entries(config.api?.headers ?? {})) {
126
126
  const lower = key.toLowerCase()
127
127
  if (FORBIDDEN_SERVER_HEADERS.has(lower) || lower.startsWith('cf-')) continue
128
- headers.set(key, value)
128
+ headers.set(key, value as string)
129
129
  }
130
130
  headers.set('accept', headers.get('accept') ?? 'application/json')
131
131
 
@@ -145,7 +145,7 @@ export async function proxyStorefrontRequest(
145
145
  const isSettings = path === 'settings' || path.startsWith('settings/')
146
146
  if (isSettings) {
147
147
  headers.delete('x-Store-Id')
148
- headers.set('x-Store-Domain', config.slug)
148
+ headers.set('x-Store-Domain', config.domain)
149
149
  } else {
150
150
  try {
151
151
  const storeId = await getStorefrontClient().getStoreId()
package/src/client.ts CHANGED
@@ -20,7 +20,7 @@ export function getStorefrontClient(options: CreateApiOptions = {}): StorefrontC
20
20
  if (lower === 'x-store-id' || lower === 'x-store-domain') delete headers[key]
21
21
  }
22
22
  sharedClient = createCoreClient({
23
- slug: config.slug,
23
+ domain: config.domain,
24
24
  ...config.api,
25
25
  ...options,
26
26
  headers,
@@ -36,7 +36,7 @@ export function resetStorefrontClient(): void {
36
36
  }
37
37
 
38
38
  /**
39
- * Cliente storefront. Slug y defaults de API salen del config de la tienda.
39
+ * Cliente storefront. Domain y defaults de API salen del config de la tienda.
40
40
  *
41
41
  * ```ts
42
42
  * export const api = createClient()
package/src/codegen.mjs CHANGED
@@ -106,14 +106,9 @@ export async function generateApp({ cwd, appDir, frameworkRoot, config }) {
106
106
  )
107
107
 
108
108
  const publicConfig = {
109
- name: config.name,
110
- slug: config.slug,
109
+ domain: config.domain,
111
110
  }
112
- if (config.description !== undefined) publicConfig.description = config.description
113
111
  if (config.theme !== undefined) publicConfig.theme = config.theme
114
- if (config.seo !== undefined) publicConfig.seo = config.seo
115
- if (config.analytics !== undefined) publicConfig.analytics = config.analytics
116
- if (config.layout !== undefined) publicConfig.layout = config.layout
117
112
 
118
113
  for (const serverOnlyKey of ['api', 'dev', 'deploy', 'env']) {
119
114
  if (Object.hasOwn(publicConfig, serverOnlyKey)) {
@@ -141,7 +136,7 @@ export async function generateApp({ cwd, appDir, frameworkRoot, config }) {
141
136
  ` if (import.meta.env.DEV && config.dev?.apiBaseUrl) {\n` +
142
137
  ` api = { ...api, baseUrl: config.dev.apiBaseUrl }\n` +
143
138
  ` }\n` +
144
- ` registerServerConfig({ slug: config.slug, api })\n` +
139
+ ` registerServerConfig({ domain: config.domain, api })\n` +
145
140
  ` return startServer.fetch(...args)\n` +
146
141
  ` },\n` +
147
142
  `})\n`,
@@ -223,7 +218,7 @@ export async function generateApp({ cwd, appDir, frameworkRoot, config }) {
223
218
  reconcileGeneratedRoutes(appDir, routesDir, desiredRoutes)
224
219
 
225
220
  // ── 9. wrangler.jsonc para deploy en Cloudflare Workers ──
226
- const workerName = config.deploy?.name ?? slugify(config.name ?? 'ecomiq-store')
221
+ const workerName = config.deploy?.name ?? slugify(config.domain ?? 'ecomiq-store')
227
222
  writeGeneratedFile(
228
223
  join(appDir, 'wrangler.jsonc'),
229
224
  JSON.stringify(
@@ -0,0 +1,70 @@
1
+ import { Link } from '../../link'
2
+ import { Button, buttonVariants, cn } from '../../ui'
3
+ import type { CheckoutFieldId } from './form-schema'
4
+ import { CheckoutTextField } from './checkout-form-controls'
5
+
6
+ /** Paso 1: Mis datos (email). */
7
+ export function CheckoutContactSection({
8
+ email,
9
+ fieldError,
10
+ sessionLabel,
11
+ isSaving,
12
+ onEmailChange,
13
+ onClearError,
14
+ onContinueAsGuest,
15
+ }: {
16
+ email: string
17
+ fieldError?: string
18
+ sessionLabel?: string | null
19
+ isSaving?: boolean
20
+ onEmailChange: (value: string) => void
21
+ onClearError: (id: CheckoutFieldId) => void
22
+ onContinueAsGuest: () => void | Promise<void>
23
+ }) {
24
+ return (
25
+ <div className="space-y-5">
26
+ {sessionLabel ? (
27
+ <p className="text-sm text-muted-foreground">
28
+ Sesión como <span className="font-medium text-foreground">{sessionLabel}</span>
29
+ </p>
30
+ ) : null}
31
+
32
+ <CheckoutTextField
33
+ id="email"
34
+ label="Correo electrónico"
35
+ error={fieldError}
36
+ value={email}
37
+ onChange={(v) => {
38
+ onClearError('email')
39
+ onEmailChange(v)
40
+ }}
41
+ type="email"
42
+ autoComplete="email"
43
+ />
44
+
45
+ <div className="flex flex-col gap-3 sm:flex-row">
46
+ {!sessionLabel ? (
47
+ <Link
48
+ to="/account/login"
49
+ search={{
50
+ redirect:
51
+ typeof window !== 'undefined' ? window.location.pathname : '/checkout',
52
+ }}
53
+ className={cn(buttonVariants({ variant: 'default' }), 'uppercase tracking-wide')}
54
+ >
55
+ ¿Ya tienes una cuenta?
56
+ </Link>
57
+ ) : null}
58
+ <Button
59
+ type="button"
60
+ variant={sessionLabel ? 'default' : 'outline'}
61
+ className="uppercase tracking-wide"
62
+ disabled={isSaving}
63
+ onClick={() => void onContinueAsGuest()}
64
+ >
65
+ {sessionLabel ? 'Continuar' : 'Continuar como invitado'}
66
+ </Button>
67
+ </div>
68
+ </div>
69
+ )
70
+ }
@@ -17,6 +17,8 @@ export function CheckoutOrderSummary({
17
17
  promotionCodes,
18
18
  formError,
19
19
  isSaving,
20
+ canSubmit = true,
21
+ submitLabel = 'Pagar',
20
22
  onCouponCodeChange,
21
23
  onApplyCoupon,
22
24
  onRemoveCoupon,
@@ -34,6 +36,8 @@ export function CheckoutOrderSummary({
34
36
  promotionCodes: string[]
35
37
  formError: string | null
36
38
  isSaving: boolean
39
+ canSubmit?: boolean
40
+ submitLabel?: string
37
41
  onCouponCodeChange: (value: string) => void
38
42
  onApplyCoupon: () => void
39
43
  onRemoveCoupon: (code: string) => void
@@ -113,8 +117,13 @@ export function CheckoutOrderSummary({
113
117
  </p>
114
118
  ) : null}
115
119
 
116
- <Button type="submit" className="mt-6 w-full" size="lg" disabled={isSaving}>
117
- {isSaving ? 'Procesando…' : 'Pay now'}
120
+ <Button
121
+ type="submit"
122
+ className="mt-6 w-full"
123
+ size="lg"
124
+ disabled={isSaving || !canSubmit}
125
+ >
126
+ {isSaving ? 'Procesando…' : submitLabel}
118
127
  </Button>
119
128
  </aside>
120
129
  )
@@ -51,11 +51,8 @@ export function CheckoutPaymentSection({
51
51
  onMarkProviderCompleted: () => void
52
52
  onReceiptFileChange: (file: File | null) => void
53
53
  }) {
54
- const selectedMethod = methods.find((m) => m.code === selectedCode) ?? null
55
-
56
54
  return (
57
- <section className="space-y-4">
58
- <h2 className="text-xl font-semibold tracking-tight">Seleccionar método de pago</h2>
55
+ <div className="space-y-4">
59
56
  <div className="space-y-3">
60
57
  {methods.map((method) => {
61
58
  const selected = selectedCode === method.code
@@ -137,7 +134,7 @@ export function CheckoutPaymentSection({
137
134
 
138
135
  {!usesProviderUi && !method.isManual ? (
139
136
  <p className="text-xs text-muted-foreground">
140
- Continúa con Pay now para confirmar este método de pago.
137
+ Continúa con Pagar para confirmar este método de pago.
141
138
  </p>
142
139
  ) : null}
143
140
  </div>
@@ -147,7 +144,7 @@ export function CheckoutPaymentSection({
147
144
  })}
148
145
  </div>
149
146
  <FieldError message={fieldError} />
150
- </section>
147
+ </div>
151
148
  )
152
149
  }
153
150
 
@@ -203,7 +200,7 @@ function ProviderPaymentPanel({
203
200
  ) : null}
204
201
  {completed ? (
205
202
  <p className="text-xs text-muted-foreground">
206
- Pago confirmado. Pulsa Pay now para finalizar tu pedido.
203
+ Pago confirmado. Pulsa Pagar para finalizar tu pedido.
207
204
  </p>
208
205
  ) : (
209
206
  <Button type="button" size="sm" variant="outline" onClick={onMarkCompleted}>