diff --git a/src/components/onboarding/OnboardingTour.tsx b/src/components/onboarding/OnboardingTour.tsx index 965dbe3..89dcf33 100644 --- a/src/components/onboarding/OnboardingTour.tsx +++ b/src/components/onboarding/OnboardingTour.tsx @@ -1,5 +1,5 @@ -import React, { useEffect } from 'react'; +import React from 'react'; import { Button } from '@/components/ui/button'; import { Card, CardContent } from '@/components/ui/card'; import { X } from 'lucide-react'; @@ -19,32 +19,6 @@ const OnboardingTour: React.FC = ({ onSkip, onClose }) => { - // Definir a função ANTES de usá-la - const removeHighlightStyle = () => { - const elements = document.querySelectorAll('[data-tour]') as NodeListOf; - elements.forEach(element => { - element.style.backgroundColor = ''; - element.style.color = ''; - element.style.fontWeight = ''; - element.style.boxShadow = ''; - element.style.border = ''; - element.style.borderRadius = ''; - element.style.position = ''; - element.style.zIndex = ''; - }); - }; - - // Cleanup de estilos quando o componente for desmontado ou tour fechado - useEffect(() => { - if (!isOpen) { - removeHighlightStyle(); - } - - return () => { - removeHighlightStyle(); - }; - }, [isOpen]); - if (!isOpen) return null; const steps = [ @@ -100,38 +74,6 @@ const OnboardingTour: React.FC = ({ const currentStepData = steps[currentStep]; - // Estilo para destacar o elemento com fundo branco e texto preto - const highlightElementStyle = () => { - if (!currentStepData.spotlight) return; - - const element = document.querySelector(`[data-tour="${currentStepData.spotlight}"]`) as HTMLElement; - if (!element) return; - - // Aplicar estilos diretamente no elemento - element.style.backgroundColor = '#ffffff'; - element.style.color = '#000000'; - element.style.fontWeight = '600'; - element.style.boxShadow = '0 0 20px rgba(59, 130, 246, 0.6)'; - element.style.border = '2px solid rgba(59, 130, 246, 0.8)'; - element.style.borderRadius = '8px'; - element.style.position = 'relative'; - element.style.zIndex = '9999'; - }; - - // Aplicar ou remover highlight baseado no step atual - useEffect(() => { - if (currentStepData.spotlight) { - // Primeiro remover qualquer highlight anterior - removeHighlightStyle(); - // Pequeno delay para garantir que o DOM foi renderizado - setTimeout(() => { - highlightElementStyle(); - }, 100); - } else { - removeHighlightStyle(); - } - }, [currentStep, currentStepData.spotlight]); - const getSpotlightStyle = () => { if (!currentStepData.spotlight) return {}; @@ -174,6 +116,7 @@ const OnboardingTour: React.FC = ({ const deltaX = elementCenterX - cardCenterX; const deltaY = elementCenterY - cardCenterY; const angle = Math.atan2(deltaY, deltaX) * (180 / Math.PI); + const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY); // Posicionar a seta no meio do caminho const arrowX = cardCenterX + (deltaX * 0.6); @@ -234,6 +177,56 @@ const OnboardingTour: React.FC = ({ }; }; + // Estilo para destacar o elemento com fundo branco e texto preto + const highlightElementStyle = () => { + if (!currentStepData.spotlight) return; + + const element = document.querySelector(`[data-tour="${currentStepData.spotlight}"]`) as HTMLElement; + if (!element) return; + + // Aplicar estilos diretamente no elemento + element.style.backgroundColor = '#ffffff'; + element.style.color = '#000000'; + element.style.fontWeight = '600'; + element.style.boxShadow = '0 0 20px rgba(59, 130, 246, 0.6)'; + element.style.border = '2px solid rgba(59, 130, 246, 0.8)'; + element.style.borderRadius = '8px'; + element.style.position = 'relative'; + element.style.zIndex = '9999'; + }; + + // Remover estilos quando não há spotlight + const removeHighlightStyle = () => { + const elements = document.querySelectorAll('[data-tour]') as NodeListOf; + elements.forEach(element => { + element.style.backgroundColor = ''; + element.style.color = ''; + element.style.fontWeight = ''; + element.style.boxShadow = ''; + element.style.border = ''; + element.style.borderRadius = ''; + element.style.position = ''; + element.style.zIndex = ''; + }); + }; + + // Aplicar ou remover highlight baseado no step atual + React.useEffect(() => { + if (currentStepData.spotlight) { + // Pequeno delay para garantir que o DOM foi renderizado + setTimeout(() => { + highlightElementStyle(); + }, 100); + } else { + removeHighlightStyle(); + } + + // Cleanup quando o componente for desmontado + return () => { + removeHighlightStyle(); + }; + }, [currentStep, currentStepData.spotlight]); + return ( <> {/* Overlay escuro */} diff --git a/src/hooks/useOnboardingTour.ts b/src/hooks/useOnboardingTour.ts index 9ff8163..32de93e 100644 --- a/src/hooks/useOnboardingTour.ts +++ b/src/hooks/useOnboardingTour.ts @@ -10,19 +10,11 @@ export const useOnboardingTour = () => { const [currentStep, setCurrentStep] = useState(0); const [shouldShowTour, setShouldShowTour] = useState(false); const [tourShownThisSession, setTourShownThisSession] = useState(false); - const [isCheckingConditions, setIsCheckingConditions] = useState(false); const location = useLocation(); // Verificar se o tour deve ser exibido const checkTourConditions = async () => { - // Evitar múltiplas verificações simultâneas - if (isCheckingConditions) { - console.log('🔄 [TOUR] Verificação já em andamento, ignorando...'); - return; - } - try { - setIsCheckingConditions(true); console.log('🔍 [TOUR] Iniciando verificação de condições do tour...'); // Só mostrar o tour na página inicial (dashboard) @@ -32,12 +24,6 @@ export const useOnboardingTour = () => { return; } - // Se tour já está aberto, não verificar novamente - if (isOpen) { - console.log('🚫 [TOUR] Tour já está aberto, ignorando verificação'); - return; - } - // Verificar se existe email no localStorage const userEmail = localStorage.getItem('userEmail'); console.log('📧 [TOUR] Email do usuário para verificação:', userEmail); @@ -48,7 +34,7 @@ export const useOnboardingTour = () => { return; } - // SEMPRE verificar se há grupos cadastrados + // SEMPRE verificar se há grupos cadastrados (ignorar sessionStorage inicialmente) let hasGroups = false; try { @@ -74,10 +60,10 @@ export const useOnboardingTour = () => { // Se não tem grupos, verificar se já foi mostrado nesta sessão const shownThisSession = sessionStorage.getItem(TOUR_SESSION_KEY) === 'true'; - console.log('🔍 [TOUR] Usuário SEM grupos. Tour já exibido nesta sessão:', shownThisSession); + console.log('🔍 [TOUR] Usuário SEM grupos. Verificando se tour já foi exibido nesta sessão:', shownThisSession); if (shownThisSession) { - console.log('❌ [TOUR] Tour já foi exibido nesta sessão'); + console.log('❌ [TOUR] Tour já foi exibido nesta sessão para este usuário sem grupos'); setShouldShowTour(false); setTourShownThisSession(true); return; @@ -87,32 +73,20 @@ export const useOnboardingTour = () => { console.log('🎯 [TOUR] CONDIÇÕES ATENDIDAS - Usuário sem grupos e tour não exibido ainda'); setShouldShowTour(true); - // Abrir tour automaticamente após um pequeno delay, mas apenas se não estiver já aberto - if (!isOpen) { - console.log('🚀 [TOUR] Abrindo tour automaticamente - usuário sem grupos'); - setTimeout(() => { - // Verificar novamente se não foi aberto enquanto esperava - setIsOpen(prevIsOpen => { - if (!prevIsOpen) { - console.log('🎬 [TOUR] Executando abertura do tour...'); - setCurrentStep(0); - // Marcar como exibido quando realmente abrir - sessionStorage.setItem(TOUR_SESSION_KEY, 'true'); - setTourShownThisSession(true); - return true; - } else { - console.log('🚫 [TOUR] Tour já estava aberto, não abrindo novamente'); - return prevIsOpen; - } - }); - }, 1500); - } + // Abrir tour automaticamente após um pequeno delay + console.log('🚀 [TOUR] Abrindo tour automaticamente - usuário sem grupos'); + setTimeout(() => { + console.log('🎬 [TOUR] Executando abertura do tour...'); + setIsOpen(true); + setCurrentStep(0); + // SÓ marcar como exibido quando realmente abrir + sessionStorage.setItem(TOUR_SESSION_KEY, 'true'); + setTourShownThisSession(true); + }, 2000); } catch (error) { console.error('❌ [TOUR] Erro ao verificar condições do tour:', error); setShouldShowTour(false); - } finally { - setIsCheckingConditions(false); } }; @@ -123,7 +97,6 @@ export const useOnboardingTour = () => { setShouldShowTour(false); sessionStorage.removeItem(TOUR_SESSION_KEY); setTourShownThisSession(false); - setCurrentStep(0); }; // Verificar condições quando a localização mudar ou na inicialização @@ -133,24 +106,21 @@ export const useOnboardingTour = () => { checkTourConditions(); }, 1000); - return () => { - clearTimeout(timer); - setIsCheckingConditions(false); - }; + return () => clearTimeout(timer); }, [location.pathname]); // Escutar evento customizado de login useEffect(() => { const handleUserLoggedIn = (event: CustomEvent) => { console.log('🎉 [TOUR] Evento de login recebido:', event.detail); - if (location.pathname === '/' && !isOpen) { + if (location.pathname === '/') { console.log('📧 [TOUR] Login detectado no dashboard, re-verificando condições do tour'); // Limpar sessionStorage para nova verificação após login sessionStorage.removeItem(TOUR_SESSION_KEY); setTourShownThisSession(false); setTimeout(() => { checkTourConditions(); - }, 2000); + }, 2500); } }; @@ -158,14 +128,17 @@ export const useOnboardingTour = () => { return () => { window.removeEventListener('userLoggedIn', handleUserLoggedIn as EventListener); }; - }, [location.pathname, isOpen]); + }, [location.pathname]); // Verificar também quando o email do usuário estiver disponível useEffect(() => { const userEmail = localStorage.getItem('userEmail'); console.log('📧 [TOUR] Segundo useEffect - email disponível:', userEmail); - if (userEmail && location.pathname === '/' && !isOpen && !tourShownThisSession) { + if (userEmail && location.pathname === '/') { console.log('📧 [TOUR] Email detectado, re-verificando condições do tour'); + // Limpar sessionStorage para nova verificação + sessionStorage.removeItem(TOUR_SESSION_KEY); + setTourShownThisSession(false); setTimeout(() => { checkTourConditions(); }, 1500); @@ -175,7 +148,7 @@ export const useOnboardingTour = () => { // Escutar mudanças no localStorage para detectar login useEffect(() => { const handleStorageChange = (e: StorageEvent) => { - if (e.key === 'userEmail' && e.newValue && !isOpen) { + if (e.key === 'userEmail' && e.newValue) { console.log('👤 [TOUR] Login detectado via storage event:', e.newValue); if (location.pathname === '/') { // Limpar sessionStorage para nova verificação após mudança de usuário @@ -190,7 +163,7 @@ export const useOnboardingTour = () => { window.addEventListener('storage', handleStorageChange); return () => window.removeEventListener('storage', handleStorageChange); - }, [location.pathname, isOpen]); + }, [location.pathname]); const nextStep = () => { console.log('➡️ [TOUR] Próximo step do tour:', currentStep + 1); @@ -210,8 +183,7 @@ export const useOnboardingTour = () => { console.log('❌ [TOUR] Fechando tour'); setIsOpen(false); setCurrentStep(0); - setShouldShowTour(false); - // Garantir que está marcado como exibido + // Marcar como exibido nesta sessão apenas quando fechar sessionStorage.setItem(TOUR_SESSION_KEY, 'true'); setTourShownThisSession(true); };