import React, { useState, useEffect } from 'react'; import { useDevToolsProtection } from '../../hooks/useDevToolsProtection'; import { X, ChevronLeft, ChevronRight, Download, ZoomIn, ZoomOut, MessageSquare } from 'lucide-react'; import type { Photo } from '../../types'; import { useDownloadPhoto } from '../../hooks/useGallery'; import { AuthenticatedImage } from '../common'; import { PhotoFeedback } from './PhotoFeedback'; interface PhotoLightboxProps { photos: Photo[]; initialIndex: number; onClose: () => void; slug: string; feedbackEnabled?: boolean; allowDownloads?: boolean; protectionLevel?: 'basic' | 'standard' | 'enhanced' | 'maximum'; useEnhancedProtection?: boolean; } export const PhotoLightbox: React.FC = ({ photos, initialIndex, onClose, slug, feedbackEnabled = false, allowDownloads = true, protectionLevel = 'standard', useEnhancedProtection = false, }) => { const [currentIndex, setCurrentIndex] = useState(initialIndex); const [zoom, setZoom] = useState(1); const [isDragging, setIsDragging] = useState(false); const [dragStart, setDragStart] = useState({ x: 0, y: 0 }); const [dragOffset, setDragOffset] = useState({ x: 0, y: 0 }); const [touchDistance, setTouchDistance] = useState(null); const [showFeedback, setShowFeedback] = useState(false); const downloadPhotoMutation = useDownloadPhoto(); const currentPhoto = photos[currentIndex]; // DevTools protection for the lightbox when enhanced protection is enabled useDevToolsProtection({ enabled: useEnhancedProtection && (protectionLevel === 'enhanced' || protectionLevel === 'maximum'), detectionSensitivity: protectionLevel === 'maximum' ? 'high' : 'medium', onDevToolsDetected: () => { console.warn('DevTools detected in photo lightbox'); // Track analytics if (typeof window !== 'undefined' && (window as any).umami) { (window as any).umami.track('lightbox_devtools_detected', { photoId: currentPhoto.id, protectionLevel, zoom, gallery: slug }); } // Close lightbox immediately for maximum protection if (protectionLevel === 'maximum') { onClose(); } }, redirectOnDetection: false, // Don't redirect, just close lightbox }); useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { switch (e.key) { case 'Escape': onClose(); break; case 'ArrowLeft': goToPrevious(); break; case 'ArrowRight': goToNext(); break; case '+': case '=': handleZoomIn(); break; case '-': case '_': handleZoomOut(); break; case 'd': case 'D': if (allowDownloads) { handleDownload(); } break; } }; document.addEventListener('keydown', handleKeyDown); document.body.style.overflow = 'hidden'; // Add protection class to body for maximum security if (protectionLevel === 'maximum') { document.body.classList.add('protection-maximum'); } else if (protectionLevel === 'enhanced') { document.body.classList.add('protection-enhanced'); } return () => { document.removeEventListener('keydown', handleKeyDown); document.body.style.overflow = ''; // Remove protection classes from body document.body.classList.remove('protection-maximum', 'protection-enhanced'); }; }, [currentIndex]); const goToPrevious = () => { setCurrentIndex((prev) => (prev > 0 ? prev - 1 : photos.length - 1)); resetZoom(); }; const goToNext = () => { setCurrentIndex((prev) => (prev < photos.length - 1 ? prev + 1 : 0)); resetZoom(); }; const resetZoom = () => { setZoom(1); setDragOffset({ x: 0, y: 0 }); }; const handleZoomIn = () => { setZoom((prev) => Math.min(prev + 0.5, 3)); }; const handleZoomOut = () => { setZoom((prev) => Math.max(prev - 0.5, 1)); if (zoom - 0.5 <= 1) { setDragOffset({ x: 0, y: 0 }); } }; const handleDownload = () => { if (!allowDownloads) return; downloadPhotoMutation.mutate({ slug, photoId: currentPhoto.id, filename: currentPhoto.filename, }); }; const handleMouseDown = (e: React.MouseEvent) => { if (zoom > 1) { setIsDragging(true); setDragStart({ x: e.clientX - dragOffset.x, y: e.clientY - dragOffset.y }); } }; const handleMouseMove = (e: React.MouseEvent) => { if (isDragging && zoom > 1) { setDragOffset({ x: e.clientX - dragStart.x, y: e.clientY - dragStart.y, }); } }; const handleMouseUp = () => { setIsDragging(false); }; const handleImageClick = (e: React.MouseEvent) => { // Only close if clicking the background, not the image if (e.target === e.currentTarget) { onClose(); } }; // Touch event handlers for pinch-to-zoom const handleTouchStart = (e: React.TouchEvent) => { if (e.touches.length === 2) { const touch1 = e.touches[0]; const touch2 = e.touches[1]; const distance = Math.hypot( touch2.clientX - touch1.clientX, touch2.clientY - touch1.clientY ); setTouchDistance(distance); } }; const handleTouchMove = (e: React.TouchEvent) => { if (e.touches.length === 2 && touchDistance !== null) { const touch1 = e.touches[0]; const touch2 = e.touches[1]; const newDistance = Math.hypot( touch2.clientX - touch1.clientX, touch2.clientY - touch1.clientY ); const scale = newDistance / touchDistance; const newZoom = Math.max(1, Math.min(3, zoom * scale)); setZoom(newZoom); setTouchDistance(newDistance); } }; const handleTouchEnd = () => { setTouchDistance(null); }; // Apply protection class to the lightbox container const lightboxClass = useEnhancedProtection ? `fixed inset-0 bg-black z-50 flex items-center justify-center protected-image protection-${protectionLevel}` : 'fixed inset-0 bg-black z-50 flex items-center justify-center'; return (
{/* Close button */} {/* Navigation buttons */} {/* Bottom toolbar */}

{currentIndex + 1} / {photos.length}

{Math.round(zoom * 100)}%
{allowDownloads && ( )} {/* Feedback button with indicator */} {feedbackEnabled && ( )}
{/* Image container */}
1 ? (isDragging ? 'grabbing' : 'grab') : 'default' }} > { console.warn(`Protection violation in lightbox for photo ${currentPhoto.id}: ${violationType}`); // Track analytics if (typeof window !== 'undefined' && (window as any).umami) { (window as any).umami.track('lightbox_protection_violation', { photoId: currentPhoto.id, violationType, protectionLevel, zoom }); } // For maximum protection, close lightbox on violation if (protectionLevel === 'maximum' && ['devtools_detected', 'print_screen_detected', 'canvas_access_blocked'].includes(violationType)) { onClose(); } }} />
{/* Touch/swipe indicators for mobile */}
Swipe to navigate
{/* Feedback Panel */} {showFeedback && (

Photo Feedback

)}
); };