Ir al contenido

Banner de Características Clave

Beneficios a nivel tienda con ícono, del estilo “envío gratis / cuotas sin interés / cambios sin cargo”.

En el paneltipo en el JSONToken de la clave
Banner de Características ClaveKEY_FEATURES_BANNERkey_features_banner

La respuesta es más simple que la del bundle: solo sections, sin page ni identificador de entidad.

{
sections: Record<string, Seccion>;
}

Como no hay page, no puedes derivar el placement de la respuesta. Si necesitas saber dónde ubicó el comerciante cada banner, léelo del segundo segmento de la clave.

{
titulo: string | null;
texto: string | null;
imagen: { url: string; alt: string | null } | null; // imagen de la sección
items: Array<{
imagen: { url: string; alt: string | null } | null;
titulo: string | null; // nullable, a diferencia de SPECS
descripcion: string | null; // nullable, a diferencia de SPECS
orden: number;
}>;
}

Los items son casi idénticos a los de Carrusel de Especificaciones, con una diferencia que importa: aquí titulo y descripcion pueden ser null. El panel permite guardar una característica con el encabezado o el cuerpo vacío, y esos casos llegan como null en vez de omitirse.

{
"sections": {
"key_features_banner-home-general-cmr9p2xkd0004hs5bn3wq7t1e": {
"titulo": "Por qué comprarnos",
"nombre_personalizado": "Banner home",
"texto": "Tres razones para elegirnos.",
"imagen": null,
"items": [
{
"imagen": { "url": "https://cdn.example.com/envio.svg", "alt": "Envío" },
"titulo": "Envío gratis",
"descripcion": "En compras superiores a $50.000",
"orden": 0
},
{
"imagen": { "url": "https://cdn.example.com/cuotas.svg", "alt": null },
"titulo": "12 cuotas sin interés",
"descripcion": null,
"orden": 1
}
],
"estado": { "lifecycle": "active", "storefrontVisible": true },
"orden": 0
}
}
}

La respuesta no trae page, así que el helper seccionesDeTipo no aplica tal cual. Filtra directo sobre sections, con la misma regla de render:

const res = await fetch(
`https://sectionfy.codefy-apps.com/api/public/key-features-banner/${TOKEN}`,
);
const { sections } = await res.json();
const banners = Object.entries(sections)
.filter(([, s]) => s.estado.lifecycle === 'active' && s.estado.storefrontVisible)
.sort(([, a], [, b]) => a.orden - b.orden);
for (const [key, banner] of banners) {
const caracteristicas = banner.items
.slice()
.sort((a, b) => a.orden - b.orden)
// Una característica sin título ni descripción no aporta nada: omitirla.
.filter((item) => item.titulo || item.descripcion)
.map(
(item) => `
<li class="sectionfy-kfb__item">
${
item.imagen
? `<img src="${item.imagen.url}" alt="${escapar(item.imagen.alt ?? '')}"
width="40" height="40" loading="lazy">`
: ''
}
${item.titulo ? `<h3>${escapar(item.titulo)}</h3>` : ''}
${item.descripcion ? `<p>${escapar(item.descripcion)}</p>` : ''}
</li>
`,
)
.join('');
contenedor.insertAdjacentHTML(
'beforeend',
`<section class="sectionfy-kfb" data-block="${key}">
${banner.titulo ? `<h2>${escapar(banner.titulo)}</h2>` : ''}
${banner.texto ? `<p>${escapar(banner.texto)}</p>` : ''}
<ul class="sectionfy-kfb__lista">${caracteristicas}</ul>
</section>`,
);
}
  • Filtra los items vacíos. Un item con titulo y descripcion en null renderiza una tarjeta en blanco.
  • Es una llamada más, aparte del bundle. Si tu página necesita las dos cosas, dispáralas en paralelo — ver recetas de fetch.