Compare commits

...
Author SHA1 Message Date
devopsandClaude Sonnet 5 71c8752eeb Merge: páginas reales de Envíos y Contacto en el footer
Build and Push Frontend / Escaneo de Secretos (Gitleaks) (push) Successful in 28s
Build and Push Frontend / Construir y Subir Imagen (push) Successful in 9m24s
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01THZFwPzrwv6VAbuwmaf5vR
2026-09-12 02:55:28 +00:00
devopsandClaude Sonnet 5 cda25dea2e feat(ecommerce): páginas reales de Envíos y Contacto en el footer
El footer "Ayuda" no tenía contenido real -- los 4 links apuntaban a
/catalog. Se agregan dos páginas nuevas con información real:

- /envios: transportadoras reales de EnvíoClick (Coordinadora, Envía,
  TCC, Rappi, Pibox -- confirmadas en una cotización real, ver ADR
  0010 §2) y cómo se calcula el costo.
- /contacto: WhatsApp real (+57 301 613 8155, mismo número ya usado en
  el fallback de checkout) y correo [email protected] (reenviado
  por Cloudflare Email Routing -- configuración manual de DNS pendiente
  del lado del usuario, fuera de alcance de este cambio).

"Preguntas frecuentes" y "Cambios" quedan sin contenido real definido
todavía, apuntando a /catalog como antes.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01THZFwPzrwv6VAbuwmaf5vR
2026-09-12 02:55:24 +00:00
gitea-actions 392a832109 chore(gitops): deploy Docs Portal v1.0.244 [skip ci] 2026-09-11 13:36:00 +00:00
devops a069807960 chore: release v1.0.243 [skip ci] 2026-09-11 13:28:36 +00:00
devopsandClaude Sonnet 5 96b08eda01 Merge: resultados de la segunda tanda de pruebas con navegador real (ADR 0010)
Build and Push Docs Portal / Escaneo de Secretos (Gitleaks) (push) Successful in 26s
Build and Push Docs Portal / Construir y publicar Docs Portal (push) Successful in 6m43s
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01THZFwPzrwv6VAbuwmaf5vR
2026-09-11 13:12:21 +00:00
devopsandClaude Sonnet 5 e6c3e0ed8d docs(adr-0010): resultados de la segunda tanda de pruebas con navegador real
Checkout con carrito vacío, fallback WhatsApp, filtros de catálogo,
búsqueda sin resultados (bug encontrado y corregido en otro commit),
slug de producto inválido (hallazgo pendiente de investigar: responde
200 en vez de 404), zoom interactivo, wishlist, otros viewports,
página 404 genérica, accesibilidad básica del buscador, y registro/
login con email -- todo verificado con Chromium real vía el harness de
.browser-scratch/.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01THZFwPzrwv6VAbuwmaf5vR
2026-09-11 13:12:00 +00:00
devopsandClaude Sonnet 5 35fdea5df5 Merge: mostrar mensaje cuando el buscador no tiene resultados
Build and Push Frontend / Escaneo de Secretos (Gitleaks) (push) Successful in 23s
Build and Push Frontend / Construir y Subir Imagen (push) Successful in 19m18s
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01THZFwPzrwv6VAbuwmaf5vR
2026-09-11 13:08:53 +00:00
devopsandClaude Sonnet 5 8d44f2e771 fix(ecommerce): mostrar mensaje cuando el buscador no tiene resultados
Encontrado probando en vivo con navegador real (Docker + Playwright):
una búsqueda de 2+ caracteres sin coincidencias no mostraba nada -- ni
"Buscando…" ni ningún mensaje. El usuario quedaba sin feedback de que
su búsqueda de verdad corrió. Se agrega un estado vacío con el botón
de buscar en todo el catálogo (esa búsqueda completa puede usar
criterios más amplios que el autocompletado).

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01THZFwPzrwv6VAbuwmaf5vR
2026-09-11 13:08:50 +00:00
gitea-actions ef6dc1f6a8 chore(gitops): deploy Docs Portal v1.0.242 [skip ci] 2026-09-10 21:46:38 +00:00
devopsandClaude Sonnet 5 352762b9d2 Merge: ampliar checklist de pruebas reales pendientes (ADR 0010)
Build and Push Docs Portal / Escaneo de Secretos (Gitleaks) (push) Successful in 20s
Build and Push Docs Portal / Construir y publicar Docs Portal (push) Successful in 6m6s
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01THZFwPzrwv6VAbuwmaf5vR
2026-09-10 21:40:11 +00:00
devopsandClaude Sonnet 5 58cc93bb2f docs(adr-0010): ampliar checklist de pruebas reales pendientes
Cubre el resto de la superficie del storefront (checkout edge cases,
filtros de catalogo, variantes de producto, cuenta/wishlist,
accesibilidad, otros viewports) agrupado por riesgo, no solo lo ya
probado.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01THZFwPzrwv6VAbuwmaf5vR
2026-09-10 21:40:09 +00:00
gitea-actions 5eaa94818f chore(gitops): deploy Docs Portal v1.0.241 [skip ci] 2026-09-10 17:56:48 +00:00
gitea-actions 66a81ad9a3 chore(gitops): deploy Medusa v1.0.239 [skip ci] 2026-09-10 17:49:42 +00:00
devops 39e1bf61d3 chore: release v1.0.240 [skip ci] 2026-09-10 17:23:09 +00:00
devopsandClaude Sonnet 5 b5a1f70d1d Merge: documentar resultados de pruebas con navegador real (ADR 0010)
Build and Push Docs Portal / Escaneo de Secretos (Gitleaks) (push) Successful in 38s
Build and Push Docs Portal / Construir y publicar Docs Portal (push) Successful in 6m20s
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01THZFwPzrwv6VAbuwmaf5vR
2026-09-10 17:13:12 +00:00
8 changed files with 254 additions and 22 deletions

No files matched your search

@@ -328,7 +328,69 @@ compartido) para que el contenedor vea los archivos de verdad.
`<select>` del checkout. Ningún banco PSE real tiene código "0" —
se filtra explícitamente en `pse-banks/route.ts`.
### Pendiente — checklist ampliado para la próxima sesión con navegador
Ampliado 2026-09-10 con el resto de la superficie real del storefront
(4 páginas + `components/{account,cart,catalog,checkout,home,layout,
product,search,wishlist}`), agrupado por riesgo, y ejecutado el mismo
día contra `shop.cruzcloud.net` con el harness de `.browser-scratch/`.
### RESUELTO (2026-09-11) — segunda tanda con navegador real
Resultados reales, uno por uno (código de cada prueba en
`checks.mjs`):
- **`/checkout` con carrito vacío (ítem 9) — OK.** Muestra "Tu carrito
está vacío" con link a `/catalog`, no rompe.
- **Fallback "Confirmar por WhatsApp" (ítem 10) — OK.** Abre
`api.whatsapp.com/send?phone=...` en pestaña nueva con el mensaje del
pedido armado correctamente.
- **Filtros de `/catalog` (ítem 11) — OK.** Un filtro de categoría real
("Figuras de acción") redujo los productos mostrados de 18 a 4. Nota:
estos filtros (categoría/marca/edad dentro de la barra lateral) son
**estado de cliente, no reflejado en la URL** — distinto de los
filtros por query param (`?category=...`) que sí usa la navegación
del header. Ninguno de los dos es un bug, son dos mecanismos
distintos coexistiendo; queda como nota para no confundirlos.
- **Búsqueda sin resultados (ítem 12) — BUG real encontrado y
corregido.** El dropdown de autocompletado no mostraba absolutamente
nada (ni "Buscando…" ni ningún mensaje) cuando una búsqueda de 2+
caracteres no tenía coincidencias — el usuario se quedaba sin
feedback de que su búsqueda había corrido. Corregido en
`predictive-search.tsx`: ahora muestra "No encontramos resultados
para…" con el botón de buscar en todo el catálogo.
- **Slug de producto inválido (ítem 14) — hallazgo, no corregido
todavía.** La página sí muestra el contenido correcto de "Este tesoro
no existe" (el código ya llama a `notFound()` de
`next/navigation`, como corresponde), **pero la respuesta HTTP real
es `200`, no `404`** — confirmado independientemente con `curl`, no
es un artefacto de Playwright. No se investigó a fondo en qué capa se
pierde el status real (Next.js standalone vs. alguna capa de
Cloudflare/NPM/Traefik en el medio, ver
`incidente-cloudflared-504-quic-2026-08.md` para precedente de
problemas de red en esa cadena) — bajo impacto en la experiencia del
usuario (el contenido es correcto), pero sí afecta SEO/crawlers.
Queda como pendiente de investigar, no de corregir a ciegas.
- **Zoom interactivo del producto (ítem 15) — OK.** Hover-zoom y el
modal de click-to-zoom siguen funcionando igual tras los cambios
recientes al storefront.
- **Wishlist/favoritos (ítem 17) — OK.** Agregar a favoritos +
recargar la página: persiste correctamente vía `localStorage`.
- **Otros viewports, tablet y desktop grande (ítem 19) — OK.**
Capturas guardadas, sin problemas de layout visibles en el banner ni
el header en esos anchos.
- **Página 404 genérica (ítem 20) — OK.** Una ruta que no existe cae en
`not-found.tsx` con status HTTP `404` real (a diferencia del caso de
producto inválido arriba — la diferencia de comportamiento entre
ambos casos es justamente lo que quedó como pendiente de investigar).
- **Accesibilidad básica (ítem 21) — OK, parcial.** El buscador es
alcanzable navegando solo con `Tab` desde el body, sin mouse. Falta
probar el resto del flujo de checkout por teclado.
- **Registro/login con email y contraseña (parte del ítem 16) — OK.**
Crear cuenta con nombre/apellido/email/contraseña funciona y deja la
sesión iniciada. La parte de Google OAuth sigue sin probarse (necesita
una cuenta de Google real, no algo que se pueda automatizar sin
credenciales).
### Pendiente — lo que queda sin probar
3. **Resiliencia del fallback de envío:** forzar una dirección o
producto que haga fallar la cotización real de EnvíoClick (ej. un
@@ -340,17 +402,26 @@ compartido) para que el contenedor vea los archivos de verdad.
conseguir credenciales de prueba reales de PSE (persona/clave de
algún banco del ambiente `desarrollo`), completar el login bancario
de punta a punta, y confirmar que el webhook mueve la orden a
completada sin intervención manual — hoy solo se confirmó que el
endpoint responde `200` a un `POST` sintético y que la redirección
al banco ocurre, no el ciclo completo con notificación real.
7. **Login/registro de cliente real** (Google OAuth y con contraseña) —
nunca ejercitado con un navegador real en ninguna sesión.
8. **Bug conocido de Firefox Android** (ver memoria de proyecto,
`known-bug-firefox-android-layout`): el layout se corta/desplaza
solo en Firefox Android — Playwright puede emular Android/Chrome
pero no Firefox; si se necesita reproducir esto específicamente hace
falta `playwright-firefox` o un dispositivo real.
9. **Otros viewports** (tablet, desktop grande) para el banner y el
buscador — solo se probaron mobile (iPhone 13) y desktop 1280px.
10. **Flujo de wishlist/favoritos y el diálogo de cuenta** — no
ejercitados todavía con navegador real.
completada sin intervención manual.
7. **Pago cancelado o rechazado en el banco PSE:** confirmar que la
orden no queda en un estado ambiguo ("colgada" en
`pending_authorization` para siempre).
8. **Persona jurídica + NIT** en el formulario de PSE — solo se probó
persona natural con cédula.
13. **Selección de variantes** (cuando un producto tiene más de una) y
que el precio/disponibilidad mostrado cambie según la variante
elegida — ningún producto probado hasta ahora tenía más de una
variante real.
14b. **Investigar por qué `/product/<slug-inválido>` responde HTTP 200**
en vez de 404 pese a llamar `notFound()` correctamente (ver
hallazgo arriba) — identificar la capa responsable antes de tocar
código.
16b. **Login con Google (OAuth completo)** incluyendo
`/auth/google/callback` — necesita una cuenta de Google real de
prueba.
18. **Bug conocido de Firefox Android** (ver memoria de proyecto,
`known-bug-firefox-android-layout`) — Playwright puede emular
Android/Chrome pero no Firefox; hace falta `playwright-firefox` o
un dispositivo real.
21b. **Accesibilidad del checkout completo** por teclado (no solo el
buscador) — tab order y foco visible en los 3 pasos.
@@ -25,7 +25,7 @@ spec:
runAsNonRoot: false
containers:
- name: app
image: gitea.cruzcloud.net/devops/docs-portal:v1.0.237
image: gitea.cruzcloud.net/devops/docs-portal:v1.0.244
# El base saca TODAS las capabilities. Probado en vivo y
# revertido: con drop: ALL (aunque se agregue NET_BIND_SERVICE
# de vuelta) el propio entrypoint de nginx:1.27-alpine falla al
+63
View File
@@ -0,0 +1,63 @@
import type { Metadata } from "next";
import { Mail, MapPin, MessageCircle } from "lucide-react";
import { Button } from "@/components/ui/button";
export const metadata: Metadata = { title: "Contacto | ARI Shopping" };
// Numero real confirmado en vivo (probando el boton "Confirmar por
// WhatsApp" del checkout con navegador real): mismo canal que ya usan
// los clientes para confirmar pedidos, consistencia a proposito.
const WHATSAPP_URL = "https://wa.me/573016138155";
// Correo corporativo nuevo ([email protected] -> reenviado por
// Cloudflare Email Routing a la casilla real) -- ver nota de
// implementacion en ADR 0010 para el paso manual de DNS pendiente.
const CONTACT_EMAIL = "[email protected]";
export default function ContactoPage() {
return (
<section className="mx-auto max-w-2xl px-4 py-14 text-center lg:py-20">
<span className="text-xs font-black uppercase tracking-[.18em] text-ari-coral">Ayuda</span>
<h1 className="mt-3 text-4xl font-black tracking-tight sm:text-5xl">Contacto</h1>
<p className="mt-5 text-lg leading-8 text-slate-600">
¿Tenés una pregunta sobre tu pedido, un producto o un cambio? Escribinos, te respondemos lo antes posible.
</p>
<div className="mt-10 grid gap-4 sm:grid-cols-2">
<a
href={WHATSAPP_URL}
target="_blank"
rel="noopener noreferrer"
className="flex flex-col items-center gap-3 rounded-2xl border border-slate-200 p-6 transition hover:border-ari-marino hover:bg-ari-marino/5"
>
<MessageCircle className="size-7 text-ari-marino" />
<div>
<p className="font-black">WhatsApp</p>
<p className="mt-1 text-sm text-slate-500">+57 301 613 8155</p>
</div>
</a>
<a
href={`mailto:${CONTACT_EMAIL}`}
className="flex flex-col items-center gap-3 rounded-2xl border border-slate-200 p-6 transition hover:border-ari-marino hover:bg-ari-marino/5"
>
<Mail className="size-7 text-ari-marino" />
<div>
<p className="font-black">Correo</p>
<p className="mt-1 text-sm text-slate-500">{CONTACT_EMAIL}</p>
</div>
</a>
</div>
<div className="mt-10 flex items-center justify-center gap-2 text-sm text-slate-500">
<MapPin className="size-4" />
Despachamos desde Bogotá D.C., Colombia
</div>
<Button asChild variant="primary" size="lg" className="mt-10">
<a href={WHATSAPP_URL} target="_blank" rel="noopener noreferrer">
<MessageCircle className="size-5" />
Escribirnos por WhatsApp
</a>
</Button>
</section>
);
}
+66
View File
@@ -0,0 +1,66 @@
import type { Metadata } from "next";
import { Calculator, Clock, MapPinned, Truck } from "lucide-react";
export const metadata: Metadata = { title: "Envíos | ARI Shopping" };
// ADR 0010 §2: el costo de envio se calcula en vivo con EnvioClick (peso +
// direccion), no es un valor fijo -- el copy de abajo describe ese
// comportamiento real, no un placeholder. Transportadoras reales
// confirmadas en una cotizacion en vivo contra la API de EnvioClick
// (PIBOX, COORDINADORA, ENVIA, RAPPI, TCC) -- EnvioClick cotiza entre
// ellas y el sistema toma automaticamente la mas economica por pedido.
const CARRIERS = ["Coordinadora", "Envía", "TCC", "Rappi", "Pibox"];
export default function EnviosPage() {
return (
<section className="mx-auto max-w-3xl px-4 py-14 lg:py-20">
<span className="text-xs font-black uppercase tracking-[.18em] text-ari-coral">Ayuda</span>
<h1 className="mt-3 text-4xl font-black tracking-tight sm:text-5xl">Envíos</h1>
<p className="mt-5 text-lg leading-8 text-slate-600">
Hacemos envíos a nivel nacional desde nuestra bodega en Bogotá D.C.
</p>
<div className="mt-10 grid gap-6 sm:grid-cols-2">
<div className="rounded-2xl border border-slate-200 p-6">
<Calculator className="size-6 text-ari-marino" />
<h2 className="mt-3 font-black">Costo calculado en tiempo real</h2>
<p className="mt-2 text-sm leading-6 text-slate-600">
El valor del envío se calcula automáticamente según el peso de tu pedido y la dirección de entrega —
lo ves exacto en el checkout antes de pagar, nunca es una tarifa a ciegas.
</p>
</div>
<div className="rounded-2xl border border-slate-200 p-6">
<Truck className="size-6 text-ari-marino" />
<h2 className="mt-3 font-black">Transportadoras aliadas</h2>
<p className="mt-2 text-sm leading-6 text-slate-600">
Cotizamos automáticamente entre {CARRIERS.join(", ")} y asignamos la tarifa más conveniente para cada
pedido.
</p>
</div>
<div className="rounded-2xl border border-slate-200 p-6">
<Clock className="size-6 text-ari-marino" />
<h2 className="mt-3 font-black">Tiempos de entrega</h2>
<p className="mt-2 text-sm leading-6 text-slate-600">
Varían según la transportadora asignada y tu ciudad — una vez despachado tu pedido te compartimos el
número de guía para hacerle seguimiento.
</p>
</div>
<div className="rounded-2xl border border-slate-200 p-6">
<MapPinned className="size-6 text-ari-marino" />
<h2 className="mt-3 font-black">Cobertura</h2>
<p className="mt-2 text-sm leading-6 text-slate-600">
Envíos a todo el territorio nacional colombiano desde nuestra bodega en Bogotá D.C.
</p>
</div>
</div>
<p className="mt-10 text-sm text-slate-500">
¿Tenés dudas puntuales sobre un pedido? Escribinos por{" "}
<a href="/contacto" className="font-bold text-ari-marino hover:underline">
nuestros canales de contacto
</a>
.
</p>
</section>
);
}
@@ -65,7 +65,7 @@ spec:
memory: 64Mi
- name: migrations
image: gitea.cruzcloud.net/devops/ecommerce-medusa:v1.0.234
image: gitea.cruzcloud.net/devops/ecommerce-medusa:v1.0.239
imagePullPolicy: IfNotPresent
command:
- node
@@ -86,7 +86,7 @@ spec:
containers:
- name: app
image: gitea.cruzcloud.net/devops/ecommerce-medusa:v1.0.234
image: gitea.cruzcloud.net/devops/ecommerce-medusa:v1.0.239
imagePullPolicy: IfNotPresent
envFrom:
- configMapRef:
@@ -1,10 +1,30 @@
import Link from "next/link";
import { Facebook, Instagram, MessageCircle } from "lucide-react";
// "Envíos" y "Contacto" ya tienen paginas reales (app/envios,
// app/contacto -- contenido real: transportadoras de EnvioClick,
// WhatsApp/correo reales). "Preguntas frecuentes" y "Cambios" todavia
// no tienen contenido real decidido -- quedan apuntando a /catalog
// (no rotas, pero tampoco resueltas) hasta que se defina que van a
// decir.
const HELP_LINKS = [
{ label: "Preguntas frecuentes", href: "/catalog" },
{ label: "Envíos", href: "/envios" },
{ label: "Cambios", href: "/catalog" },
{ label: "Contacto", href: "/contacto" },
];
const SHOP_LINKS = [
{ label: "Novedades", href: "/catalog" },
{ label: "Juguetes", href: "/catalog" },
{ label: "Mochilas", href: "/catalog" },
{ label: "Regalos", href: "/catalog" },
];
export function Footer() {
return <footer className="bg-ari-marino text-white"><div className="mx-auto grid max-w-7xl gap-10 px-4 py-14 sm:grid-cols-2 lg:grid-cols-4"><div><div className="flex flex-col items-start gap-3"><img src="/images/brand/logo-ari.svg" alt="ARI shopping" className="h-11 w-auto" width={200} height={64} />{/* eslint-disable-line @next/next/no-img-element -- vector propio, next/image no optimiza SVG sin habilitar dangerouslyAllowSVG */}<p className="text-xs text-white/60">Tesoros para cada aventura.</p></div><div className="mt-5 flex gap-3"><Instagram /><Facebook /><MessageCircle /></div></div><FooterColumn title="Compra" links={["Novedades", "Juguetes", "Mochilas", "Regalos"]} /><FooterColumn title="Ayuda" links={["Preguntas frecuentes", "Envíos", "Cambios", "Contacto"]} /><div><h3 className="font-black">Newsletter</h3><p className="mt-3 text-sm leading-6 text-white/60">Recibe lanzamientos y promociones especiales.</p><div className="mt-4 flex rounded-full bg-white p-1"><input className="min-w-0 flex-1 bg-transparent px-4 text-sm text-slate-950 outline-none" placeholder="Tu correo" /><button className="rounded-full bg-ari-coral px-4 text-sm font-black text-white">Unirme</button></div></div></div><div className="border-t border-white/10 py-5 text-center text-xs text-white/50">© 2026 ARI Shopping · Frontend headless v4.1 · GitOps</div></footer>;
return <footer className="bg-ari-marino text-white"><div className="mx-auto grid max-w-7xl gap-10 px-4 py-14 sm:grid-cols-2 lg:grid-cols-4"><div><div className="flex flex-col items-start gap-3"><img src="/images/brand/logo-ari.svg" alt="ARI shopping" className="h-11 w-auto" width={200} height={64} />{/* eslint-disable-line @next/next/no-img-element -- vector propio, next/image no optimiza SVG sin habilitar dangerouslyAllowSVG */}<p className="text-xs text-white/60">Tesoros para cada aventura.</p></div><div className="mt-5 flex gap-3"><Instagram /><Facebook /><MessageCircle /></div></div><FooterColumn title="Compra" links={SHOP_LINKS} /><FooterColumn title="Ayuda" links={HELP_LINKS} /><div><h3 className="font-black">Newsletter</h3><p className="mt-3 text-sm leading-6 text-white/60">Recibe lanzamientos y promociones especiales.</p><div className="mt-4 flex rounded-full bg-white p-1"><input className="min-w-0 flex-1 bg-transparent px-4 text-sm text-slate-950 outline-none" placeholder="Tu correo" /><button className="rounded-full bg-ari-coral px-4 text-sm font-black text-white">Unirme</button></div></div></div><div className="border-t border-white/10 py-5 text-center text-xs text-white/50">© 2026 ARI Shopping · Frontend headless v4.1 · GitOps</div></footer>;
}
function FooterColumn({ title, links }: { title: string; links: string[] }) {
return <div><h3 className="font-black">{title}</h3><div className="mt-4 grid gap-3 text-sm text-white/60">{links.map((link) => <Link key={link} href="/catalog" className="hover:text-ari-coral-claro">{link}</Link>)}</div></div>;
function FooterColumn({ title, links }: { title: string; links: { label: string; href: string }[] }) {
return <div><h3 className="font-black">{title}</h3><div className="mt-4 grid gap-3 text-sm text-white/60">{links.map((link) => <Link key={link.label} href={link.href} className="hover:text-ari-coral-claro">{link.label}</Link>)}</div></div>;
}
@@ -87,6 +87,18 @@ export function PredictiveSearch() {
Buscando…
</div>
)}
{/* Encontrado probando en vivo con navegador real: sin este bloque,
una busqueda de 2+ caracteres sin coincidencias no mostraba nada
(ni "buscando" ni un mensaje) -- el usuario se quedaba sin ningun
feedback de que su busqueda de verdad corrio. Se ofrece igual el
boton de buscar en todo el catalogo porque esa busqueda completa
puede usar criterios mas amplios que el autocompletado. */}
{!loading && normalized.length >= 2 && matches.length === 0 && (
<div className="absolute left-0 right-0 top-[calc(100%+10px)] z-50 rounded-2xl border border-slate-200 bg-white p-2 text-center shadow-2xl">
<p className="p-3 text-sm text-slate-500">No encontramos resultados para “{query.trim()}”.</p>
<button type="submit" className="w-full rounded-xl bg-ari-marino px-4 py-3 text-sm font-black text-white hover:brightness-110">Buscar “{query.trim()}” en todo el catálogo</button>
</div>
)}
{matches.length > 0 && (
<div className="absolute left-0 right-0 top-[calc(100%+10px)] z-50 overflow-hidden rounded-2xl border border-slate-200 bg-white p-2 shadow-2xl">
{matches.map((product) => (
@@ -25,7 +25,7 @@ spec:
runAsUser: 1001
containers:
- name: app
image: gitea.cruzcloud.net/devops/ecommerce-frontend:v1.0.238
image: gitea.cruzcloud.net/devops/ecommerce-frontend:v1.0.243
env:
- name: HEADLESS_PROVIDER
value: medusa