Producto y favoritos
El SDK puede mostrar una tarjeta de producto en el visor y mantener una lista de favoritos en localStorage. Ambas funciones son opcionales y se configuran en vto.start().
Card de producto por tono
Cuando el usuario elige un tono, el visor puede mostrar una tarjeta con el producto asociado: miniatura, nombre, variante y un CTA «VER EL PRODUCTO».
Interfaz Product
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
name | string | Sí | Nombre del producto (p.ej. 'AURA Color Gloss'). |
tone | string | No | Nombre de la variante o tono (p.ej. 'Cobrizo Rubí'). |
imageUrl | string | No | URL de la miniatura del producto. |
url | string | No | URL de destino del CTA «VER EL PRODUCTO». |
sku | string | No | SKU del producto (se usa como clave de favorito cuando está disponible). |
Tabla exhaustiva de tipos en 10-referencia-de-tipos.md.
Orden de resolución de producto
El SDK actualiza la card en cada cambio de tono según la primera fuente definida (no es una cascada por valor: si defines resolveProduct, se usa esa y no se consultan las siguientes, aunque devuelva null/undefined, en cuyo caso la card mantiene el producto anterior):
resolveProduct(color)— función async del cliente; se llama siempre que esté definida.products[color.id]— mapa estático indexado poriddel tono; se consulta si no hayresolveProduct.color.product— producto incrustado en el propio objetoColor; prioridad más baja.
Si resolveProduct está definida y lanza un error, la card mantiene el producto anterior (el SDK absorbe el error silenciosamente).
Ejemplo con mapa estático
await vto.start({
module: 'hair-color',
colors: TONOS,
ui: { branding: { name: 'AURA' } },
products: {
cobrizo: { name: 'AURA Color Gloss', tone: 'Cobrizo Rubí', url: 'https://ejemplo.com/cobrizo' },
cobre: { name: 'AURA Color Gloss', tone: 'Cobre', url: 'https://ejemplo.com/cobre' },
},
onProductClick: (p) => window.open(p.url, '_blank'),
})
Ejemplo con resolveProduct (API async)
await vto.start({
module: 'hair-color',
colors: TONOS,
ui: { branding: { name: 'AURA' } },
resolveProduct: async (color) => {
const res = await fetch(`/api/productos/${color.id}`)
if (!res.ok) return null
return res.json()
},
onProductClick: (p) => window.open(p.url, '_blank'),
})
onProductClick
onProductClick?: (p: Product) => void
Se invoca al pulsar «VER EL PRODUCTO» en la card. Recibe el objeto Product activo. Si no se pasa, el CTA no aparece.
Favoritos (♥)
El visor incluye un panel de favoritos que el usuario puede abrir pulsando el botón ♥ de la barra. El SDK persiste los favoritos en localStorage y expone callbacks para sincronización con la API del cliente.
Persistencia en localStorage
El campo favoritesStorageKey de StartOptions controla la clave de almacenamiento:
| Valor | Comportamiento |
|---|---|
undefined (omitido) | Usa la clave por defecto 'vto:favorites'. |
Cadena no vacía (p.ej. 'aura:favs') | Usa esa cadena como clave de localStorage. |
'' (cadena vacía) | Desactiva la persistencia; los favoritos viven solo en memoria. |
Semilla inicial
initialFavorites?: Product[]
Si localStorage está vacío al arrancar (primera visita o clave nueva), el SDK carga initialFavorites como lista de partida. Útil para precargar favoritos desde la API del cliente.
Callbacks
onFavorite?: (p: Product) => void // el usuario añadió un producto
onUnfavorite?: (p: Product) => void // el usuario quitó un producto
Se invocan en tiempo real con el objeto Product afectado. Úsalos para sincronizar con tu backend o registrar analíticas.
Ejemplo completo
await vto.start({
module: 'hair-color',
colors: TONOS,
ui: { branding: { name: 'AURA' } },
products: {
cobrizo: { name: 'AURA Color Gloss', tone: 'Cobrizo Rubí', url: 'https://ejemplo.com/cobrizo' },
},
favoritesStorageKey: 'aura:favs',
initialFavorites: await fetchFavoritesFromApi(userId),
onFavorite: (p) => api.saveFavorite(userId, p),
onUnfavorite: (p) => api.removeFavorite(userId, p),
onProductClick: (p) => window.open(p.url, '_blank'),
})
Para desactivar el botón ♥ en la barra consulta 06-controles.md.