diff --git a/frontend/src/components/gallery/PhotoLightbox.tsx b/frontend/src/components/gallery/PhotoLightbox.tsx index 259107e4..d59fdf7f 100644 --- a/frontend/src/components/gallery/PhotoLightbox.tsx +++ b/frontend/src/components/gallery/PhotoLightbox.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, useRef } from 'react'; import { useDevToolsProtection } from '../../hooks/useDevToolsProtection'; import { X, ChevronLeft, ChevronRight, Download, ZoomIn, ZoomOut, MessageSquare, Heart, Star, Loader2 } from 'lucide-react'; import type { Photo } from '../../types'; @@ -47,7 +47,9 @@ export const PhotoLightbox: React.FC = ({ const [dragStart, setDragStart] = useState({ x: 0, y: 0 }); const [dragOffset, setDragOffset] = useState({ x: 0, y: 0 }); const [touchDistance, setTouchDistance] = useState(null); - const [swipeStart, setSwipeStart] = useState<{ x: number; y: number; t: number } | null>(null); + // Ref (not state) so handleTouchEnd reads the value set by handleTouchStart + // even when both fire in the same render batch. + const swipeStartRef = useRef<{ x: number; y: number; t: number } | null>(null); const [showFeedback, setShowFeedback] = useState(initialShowFeedback); const [isSmallScreen, setIsSmallScreen] = useState(typeof window !== 'undefined' ? window.innerWidth < 640 : false); const [feedbackSettings, setFeedbackSettings] = useState<{ @@ -374,10 +376,10 @@ export const PhotoLightbox: React.FC = ({ touch2.clientY - touch1.clientY ); setTouchDistance(distance); - setSwipeStart(null); + swipeStartRef.current = null; } else if (e.touches.length === 1 && zoom <= 1) { const t = e.touches[0]; - setSwipeStart({ x: t.clientX, y: t.clientY, t: Date.now() }); + swipeStartRef.current = { x: t.clientX, y: t.clientY, t: Date.now() }; } }; @@ -399,18 +401,19 @@ export const PhotoLightbox: React.FC = ({ const handleTouchEnd = (e: React.TouchEvent) => { setTouchDistance(null); - if (swipeStart && e.changedTouches.length > 0) { + const start = swipeStartRef.current; + if (start && e.changedTouches.length > 0) { const t = e.changedTouches[0]; - const dx = t.clientX - swipeStart.x; - const dy = t.clientY - swipeStart.y; - const dt = Date.now() - swipeStart.t; + const dx = t.clientX - start.x; + const dy = t.clientY - start.y; + const dt = Date.now() - start.t; // Horizontal swipe: > 50px and dominant over vertical, completed in < 600ms. if (Math.abs(dx) > 50 && Math.abs(dx) > Math.abs(dy) * 1.2 && dt < 600) { if (dx > 0) goToPrevious(); else goToNext(); } } - setSwipeStart(null); + swipeStartRef.current = null; }; // Apply protection class to the lightbox container