Improve the demo feature of the project

This commit is contained in:
Urtzi Alfaro
2025-10-12 18:47:33 +02:00
parent dbc7f2fa0d
commit 7556a00db7
168 changed files with 10102 additions and 18869 deletions

View File

@@ -0,0 +1,170 @@
import { useState, useCallback, useEffect } from 'react';
import { driver, Driver } from 'driver.js';
import { useNavigate } from 'react-router-dom';
import { getDriverConfig } from '../config/driver-config';
import { getDemoTourSteps, getMobileTourSteps } from '../config/tour-steps';
import { getTourState, saveTourState, clearTourState, clearTourStartPending } from '../utils/tour-state';
import { trackTourEvent } from '../utils/tour-analytics';
import '../styles.css';
export const useDemoTour = () => {
const navigate = useNavigate();
const [tourActive, setTourActive] = useState(false);
const [driverInstance, setDriverInstance] = useState<Driver | null>(null);
const isMobile = window.innerWidth < 768;
const handleTourDestroy = useCallback(() => {
const state = getTourState();
const currentStep = driverInstance?.getActiveIndex() || 0;
if (state && !state.completed) {
saveTourState({
currentStep,
dismissed: true,
});
trackTourEvent({
event: 'tour_dismissed',
step: currentStep,
timestamp: Date.now(),
});
}
setTourActive(false);
clearTourStartPending();
}, [driverInstance]);
const handleStepComplete = useCallback((stepIndex: number) => {
saveTourState({
currentStep: stepIndex + 1,
});
trackTourEvent({
event: 'tour_step_completed',
step: stepIndex,
timestamp: Date.now(),
});
}, []);
const handleTourComplete = useCallback(() => {
saveTourState({
completed: true,
currentStep: 0,
});
trackTourEvent({
event: 'tour_completed',
timestamp: Date.now(),
});
setTourActive(false);
clearTourStartPending();
setTimeout(() => {
trackTourEvent({
event: 'conversion_cta_clicked',
timestamp: Date.now(),
});
navigate('/register?from=demo_tour');
}, 500);
}, [navigate]);
const startTour = useCallback((fromStep: number = 0) => {
console.log('[useDemoTour] startTour called with fromStep:', fromStep);
const steps = isMobile ? getMobileTourSteps() : getDemoTourSteps();
console.log('[useDemoTour] Using', isMobile ? 'mobile' : 'desktop', 'steps, total:', steps.length);
// Check if first element exists
const firstElement = steps[0]?.element;
if (firstElement) {
const el = document.querySelector(firstElement);
console.log('[useDemoTour] First element exists:', !!el, 'selector:', firstElement);
if (!el) {
console.warn('[useDemoTour] First tour element not found in DOM! Delaying tour start...');
// Retry after DOM is ready
setTimeout(() => startTour(fromStep), 500);
return;
}
}
const config = getDriverConfig(handleStepComplete);
const driverObj = driver({
...config,
onDestroyed: (element, step, options) => {
const activeIndex = options.state?.activeIndex || 0;
const isLastStep = activeIndex === steps.length - 1;
console.log('[useDemoTour] Tour destroyed, activeIndex:', activeIndex, 'isLastStep:', isLastStep);
if (isLastStep) {
handleTourComplete();
} else {
handleTourDestroy();
}
},
});
driverObj.setSteps(steps);
setDriverInstance(driverObj);
console.log('[useDemoTour] Driver instance created, starting tour...');
if (fromStep > 0 && fromStep < steps.length) {
driverObj.drive(fromStep);
} else {
driverObj.drive();
}
setTourActive(true);
trackTourEvent({
event: 'tour_started',
timestamp: Date.now(),
});
saveTourState({
currentStep: fromStep,
completed: false,
dismissed: false,
});
clearTourStartPending();
}, [isMobile, handleTourDestroy, handleStepComplete, handleTourComplete]);
const resumeTour = useCallback(() => {
const state = getTourState();
if (state && state.currentStep > 0) {
startTour(state.currentStep);
} else {
startTour();
}
}, [startTour]);
const resetTour = useCallback(() => {
clearTourState();
if (driverInstance) {
driverInstance.destroy();
setDriverInstance(null);
}
setTourActive(false);
}, [driverInstance]);
useEffect(() => {
return () => {
if (driverInstance) {
driverInstance.destroy();
}
};
}, [driverInstance]);
return {
startTour,
resumeTour,
resetTour,
tourActive,
tourState: getTourState(),
};
};