refactor: move onboarding animation state into event handlers

Remove useEffect that watched stepIndex to drive shouldAnimate/contentKey.
stepIndex only changes from handleNext/handlePrev, so set shouldAnimate
directly in those handlers. Replace contentKey state (always equal to
stepIndex) with stepIndex as the animation key.

Fixes #1017
This commit is contained in:
qorexdev 2026-03-28 04:01:49 +05:00
parent dfe3e7b43f
commit 3b33a3efdb

View file

@ -160,6 +160,8 @@ function TourTooltip({
onPrev, onPrev,
onSkip, onSkip,
isDarkMode, isDarkMode,
shouldAnimate,
onAnimationEnd,
}: { }: {
step: TourStep; step: TourStep;
stepIndex: number; stepIndex: number;
@ -170,23 +172,12 @@ function TourTooltip({
onPrev: () => void; onPrev: () => void;
onSkip: () => void; onSkip: () => void;
isDarkMode: boolean; isDarkMode: boolean;
shouldAnimate: boolean;
onAnimationEnd: () => void;
}) { }) {
const [contentKey, setContentKey] = useState(stepIndex);
const [shouldAnimate, setShouldAnimate] = useState(false);
const prevStepIndexRef = useRef(stepIndex);
const isLastStep = stepIndex === totalSteps - 1; const isLastStep = stepIndex === totalSteps - 1;
const isFirstStep = stepIndex === 0; const isFirstStep = stepIndex === 0;
// Update content key when step changes to trigger animation
// Only animate if stepIndex actually changes (not on initial mount)
useEffect(() => {
if (prevStepIndexRef.current !== stepIndex) {
setShouldAnimate(true);
setContentKey(stepIndex);
prevStepIndexRef.current = stepIndex;
}
}, [stepIndex]);
const bgColor = isDarkMode ? "#27272a" : "#ffffff"; const bgColor = isDarkMode ? "#27272a" : "#ffffff";
const textColor = isDarkMode ? "#ffffff" : "#18181b"; const textColor = isDarkMode ? "#ffffff" : "#18181b";
const mutedTextColor = isDarkMode ? "#a1a1aa" : "#71717a"; const mutedTextColor = isDarkMode ? "#a1a1aa" : "#71717a";
@ -358,11 +349,11 @@ function TourTooltip({
> >
{/* Content */} {/* Content */}
<div <div
key={contentKey} key={stepIndex}
style={{ style={{
animation: shouldAnimate ? "fadeInSlide 0.3s ease-out" : "none", animation: shouldAnimate ? "fadeInSlide 0.3s ease-out" : "none",
}} }}
onAnimationEnd={() => setShouldAnimate(false)} onAnimationEnd={onAnimationEnd}
> >
<h3 id="tour-title" className="text-sm font-semibold mb-1.5" style={{ color: textColor }}> <h3 id="tour-title" className="text-sm font-semibold mb-1.5" style={{ color: textColor }}>
{step.title} {step.title}
@ -427,6 +418,7 @@ export function OnboardingTour() {
const isMobile = useIsMobile(); const isMobile = useIsMobile();
const [isActive, setIsActive] = useState(false); const [isActive, setIsActive] = useState(false);
const [stepIndex, setStepIndex] = useState(0); const [stepIndex, setStepIndex] = useState(0);
const [shouldAnimate, setShouldAnimate] = useState(false);
const [targetEl, setTargetEl] = useState<Element | null>(null); const [targetEl, setTargetEl] = useState<Element | null>(null);
const [spotlightTargetEl, setSpotlightTargetEl] = useState<Element | null>(null); const [spotlightTargetEl, setSpotlightTargetEl] = useState<Element | null>(null);
const [spotlightStepTarget, setSpotlightStepTarget] = useState<string | null>(null); const [spotlightStepTarget, setSpotlightStepTarget] = useState<string | null>(null);
@ -664,6 +656,7 @@ export function OnboardingTour() {
const handleNext = useCallback(() => { const handleNext = useCallback(() => {
if (stepIndex < TOUR_STEPS.length - 1) { if (stepIndex < TOUR_STEPS.length - 1) {
retryCountRef.current = 0; retryCountRef.current = 0;
setShouldAnimate(true);
setStepIndex(stepIndex + 1); setStepIndex(stepIndex + 1);
} else { } else {
// Tour completed - save to localStorage // Tour completed - save to localStorage
@ -678,6 +671,7 @@ export function OnboardingTour() {
const handlePrev = useCallback(() => { const handlePrev = useCallback(() => {
if (stepIndex > 0) { if (stepIndex > 0) {
retryCountRef.current = 0; retryCountRef.current = 0;
setShouldAnimate(true);
setStepIndex(stepIndex - 1); setStepIndex(stepIndex - 1);
} }
}, [stepIndex]); }, [stepIndex]);
@ -772,6 +766,8 @@ export function OnboardingTour() {
onPrev={handlePrev} onPrev={handlePrev}
onSkip={handleSkip} onSkip={handleSkip}
isDarkMode={isDarkMode} isDarkMode={isDarkMode}
shouldAnimate={shouldAnimate}
onAnimationEnd={() => setShouldAnimate(false)}
/> />
</> </>
)} )}