Add POI feature and imporve the overall backend implementation

This commit is contained in:
Urtzi Alfaro
2025-11-12 15:34:10 +01:00
parent e8096cd979
commit 5783c7ed05
173 changed files with 16862 additions and 9078 deletions

View File

@@ -13,26 +13,26 @@ export const getDemoTourSteps = (): DriveStep[] => [
{
element: '[data-tour="dashboard-stats"]',
popover: {
title: 'Tu Panel de Control',
description: 'Todo lo importante en un vistazo: ventas del día, pedidos pendientes, productos vendidos y alertas de stock crítico. Empieza tu día aquí en 30 segundos.',
title: 'Estado de Salud de Tu Panadería',
description: 'Aquí ves el estado general de tu negocio en tiempo real: órdenes pendientes, alertas de stock crítico, reducción de desperdicio y ahorro mensual. Todo lo importante en un vistazo para empezar el día en 30 segundos.',
side: 'bottom',
align: 'start',
},
},
{
element: '[data-tour="real-time-alerts"]',
popover: {
title: 'El Sistema Te Avisa de Todo',
description: 'Olvídate de vigilar el stock constantemente. El sistema te alerta automáticamente de ingredientes bajos, pedidos urgentes, predicciones de demanda y oportunidades de producción. Tu asistente 24/7.',
side: 'top',
align: 'start',
},
},
{
element: '[data-tour="pending-po-approvals"]',
popover: {
title: 'Qué Comprar Hoy (Ya Calculado)',
description: 'Cada mañana el sistema analiza automáticamente tus ventas, pronósticos y stock, y te dice exactamente qué ingredientes comprar. Solo tienes que revisar y aprobar con un clic. Adiós a Excel y cálculos manuales.',
title: '¿Qué Requiere Tu Atención?',
description: 'Aquí aparecen las acciones que necesitan tu aprobación: órdenes de compra generadas automáticamente, lotes de producción sugeridos, y otras decisiones importantes. Revisa, aprueba o modifica con un clic.',
side: 'top',
align: 'start',
},
},
{
element: '[data-tour="real-time-alerts"]',
popover: {
title: 'Lo Que el Sistema Hizo Por Ti',
description: 'El sistema trabaja 24/7 analizando datos, generando pronósticos y creando planes. Aquí ves un resumen de las decisiones automáticas que tomó: órdenes generadas, producción planificada y optimizaciones realizadas.',
side: 'top',
align: 'start',
},
@@ -114,26 +114,26 @@ export const getMobileTourSteps = (): DriveStep[] => [
{
element: '[data-tour="dashboard-stats"]',
popover: {
title: 'Tu Panel de Control',
description: 'Todo lo importante en un vistazo. Empieza tu día aquí en 30 segundos.',
title: 'Estado de Tu Panadería',
description: 'Estado de salud del negocio en tiempo real. Todo lo importante en un vistazo para empezar el día en 30 segundos.',
side: 'bottom',
align: 'start',
},
},
{
element: '[data-tour="real-time-alerts"]',
popover: {
title: 'El Sistema Te Avisa',
description: 'Olvídate de vigilar el stock. Alertas automáticas de todo lo importante. Tu asistente 24/7.',
side: 'top',
align: 'start',
},
},
{
element: '[data-tour="pending-po-approvals"]',
popover: {
title: 'Qué Comprar (Ya Calculado)',
description: 'Cada mañana el sistema calcula qué ingredientes comprar. Solo aprueba con un clic. Adiós Excel.',
title: '¿Qué Requiere Atención?',
description: 'Acciones que necesitan tu aprobación: compras, producción y decisiones. Revisa y aprueba con un clic.',
side: 'top',
align: 'start',
},
},
{
element: '[data-tour="real-time-alerts"]',
popover: {
title: 'Lo Que el Sistema Hizo',
description: 'Resumen de decisiones automáticas: órdenes generadas, producción planificada, optimizaciones. Tu asistente 24/7.',
side: 'top',
align: 'start',
},

View File

@@ -71,8 +71,8 @@ export const useDemoTour = () => {
}, 500);
}, [navigate]);
const startTour = useCallback((fromStep: number = 0) => {
console.log('[useDemoTour] startTour called with fromStep:', fromStep);
const startTour = useCallback((fromStep: number = 0, retryCount: number = 0) => {
console.log('[useDemoTour] startTour called with fromStep:', fromStep, 'retry:', retryCount);
// Check if we're already on the dashboard
const currentPath = window.location.pathname;
@@ -81,7 +81,7 @@ export const useDemoTour = () => {
// Store tour intent in sessionStorage before navigation
sessionStorage.setItem('demo_tour_should_start', 'true');
sessionStorage.setItem('demo_tour_start_step', fromStep.toString());
// Navigate to dashboard
navigate(ROUTES.DASHBOARD);
return;
@@ -90,20 +90,41 @@ export const useDemoTour = () => {
const steps = isMobile ? getMobileTourSteps() : getDemoTourSteps();
console.log('[useDemoTour] Using', isMobile ? 'mobile' : 'desktop', 'steps, total:', steps.length);
// Check if first element exists (only if we're on the dashboard)
// Check if critical tour elements exist (only if we're on the dashboard)
if (currentPath === ROUTES.DASHBOARD) {
const firstElement = steps[0]?.element;
if (firstElement) {
const selector = typeof firstElement === 'string' ? firstElement : String(firstElement);
// Validate critical dashboard elements
const criticalSelectors = [
'[data-tour="demo-banner"]',
'[data-tour="dashboard-stats"]'
];
let missingElement = null;
for (const selector of criticalSelectors) {
const el = document.querySelector(selector);
console.log('[useDemoTour] First element exists:', !!el, 'selector:', selector);
if (!el) {
console.warn('[useDemoTour] First tour element not found in DOM! Delaying tour start...');
// Retry after DOM is ready
setTimeout(() => startTour(fromStep), 500);
missingElement = selector;
break;
}
}
if (missingElement) {
// Retry up to 5 times with exponential backoff
if (retryCount < 5) {
const delay = Math.min(500 * Math.pow(1.5, retryCount), 3000);
console.warn(`[useDemoTour] Critical tour element "${missingElement}" not found! Retrying in ${delay}ms (attempt ${retryCount + 1}/5)...`);
setTimeout(() => startTour(fromStep, retryCount + 1), delay);
return;
} else {
console.error(`[useDemoTour] Failed to find critical element "${missingElement}" after 5 retries. Tour cannot start.`);
// Clear the tour start flag to prevent infinite retry loops
sessionStorage.removeItem('demo_tour_should_start');
sessionStorage.removeItem('demo_tour_start_step');
clearTourStartPending();
return;
}
}
console.log('[useDemoTour] All critical tour elements found, starting tour...');
}
const config = getDriverConfig(handleStepComplete);