import React, { useState, useMemo, useEffect } from 'react'; import { Download, Grid, Square, LogOut, Calendar, Clock, Search, SortAsc } from 'lucide-react'; import { format, differenceInDays, parseISO } from 'date-fns'; import { useQuery } from '@tanstack/react-query'; import { Button, Input, SkeletonGalleryGrid, Skeleton } from '../common'; import { useGalleryAuth, useTheme } from '../../contexts'; import { useGalleryPhotos, useDownloadAllPhotos } from '../../hooks/useGallery'; import { PhotoGrid } from './PhotoGrid'; import { ExpirationBanner } from './ExpirationBanner'; import { CountdownTimer } from './CountdownTimer'; import { analyticsService } from '../../services/analytics.service'; import { api } from '../../config/api'; interface GalleryViewProps { slug: string; event: { id: number; event_name: string; event_type: string; event_date: string; welcome_message?: string; color_theme?: string; expires_at: string; }; } export const GalleryView: React.FC = ({ slug, event }) => { const { logout } = useGalleryAuth(); const { setTheme } = useTheme(); const [viewMode, setViewMode] = useState<'all' | 'collages' | 'individual'>('all'); const [searchTerm, setSearchTerm] = useState(''); const [sortBy, setSortBy] = useState<'date' | 'name' | 'size'>('date'); const [showSortMenu, setShowSortMenu] = useState(false); const [brandingSettings, setBrandingSettings] = useState(null); // Fetch photos const { data, isLoading, error } = useGalleryPhotos(slug); const downloadAllMutation = useDownloadAllPhotos(); // Fetch branding settings const { data: settingsData } = useQuery({ queryKey: ['gallery-settings'], queryFn: async () => { const response = await api.get('/api/public/settings'); return response.data; }, staleTime: 5 * 60 * 1000, // Cache for 5 minutes }); // Apply theme and branding settings useEffect(() => { if (settingsData) { // Apply branding settings setBrandingSettings({ company_name: settingsData.branding_company_name || '', company_tagline: settingsData.branding_company_tagline || '', support_email: settingsData.branding_support_email || '', footer_text: settingsData.branding_footer_text || '© 2024 Your Company. All rights reserved.', watermark_enabled: settingsData.branding_watermark_enabled || false, }); // Apply theme settings if (settingsData.theme_config) { setTheme(settingsData.theme_config); } } }, [settingsData, setTheme]); // Apply event-specific theme if available useEffect(() => { if (event.color_theme) { try { const eventTheme = JSON.parse(event.color_theme); console.log('Applying event-specific theme:', eventTheme); setTheme(eventTheme); } catch (e) { console.error('Failed to parse event theme:', e); } } else if (settingsData?.theme_config) { // Fall back to global theme if no event-specific theme console.log('No event theme, using global theme'); } }, [event.color_theme, setTheme, settingsData]); // Calculate days until expiration const daysUntilExpiration = differenceInDays(parseISO(event.expires_at), new Date()); const showUrgentWarning = daysUntilExpiration <= 7; // Filter and sort photos const filteredPhotos = useMemo(() => { if (!data?.photos) return []; let photos = [...data.photos]; // Apply view mode filter if (viewMode === 'collages') { photos = photos.filter(photo => photo.type === 'collage'); } else if (viewMode === 'individual') { photos = photos.filter(photo => photo.type === 'individual'); } // Apply search filter if (searchTerm) { const term = searchTerm.toLowerCase(); photos = photos.filter(photo => photo.filename.toLowerCase().includes(term) ); } // Apply sorting photos.sort((a, b) => { switch (sortBy) { case 'name': return a.filename.localeCompare(b.filename); case 'size': return b.size - a.size; case 'date': default: return new Date(b.uploaded_at).getTime() - new Date(a.uploaded_at).getTime(); } }); return photos; }, [data?.photos, viewMode, searchTerm, sortBy]); const handleDownloadAll = () => { downloadAllMutation.mutate(slug); // Track download all action analyticsService.trackGalleryEvent('bulk_download', { gallery: slug, photo_count: data?.photos.length || 0, is_download_all: true }); }; // Track search usage with debouncing useEffect(() => { if (searchTerm.length > 0) { const timer = setTimeout(() => { analyticsService.trackSearch(searchTerm, filteredPhotos.length, 'gallery'); }, 1000); // Debounce for 1 second return () => clearTimeout(timer); } }, [searchTerm, filteredPhotos.length]); // Track expiration warning views useEffect(() => { if (showUrgentWarning && daysUntilExpiration > 0) { analyticsService.trackExpirationWarning(slug, daysUntilExpiration); } }, [showUrgentWarning, daysUntilExpiration, slug]); if (isLoading) { return (
{/* Header Skeleton */}
{/* Content Skeleton */}
); } if (error || !data) { return (

Failed to load photos

); } return (
{/* Expiration Banner */} {showUrgentWarning && ( )} {/* Header */}
{/* Company branding */} {brandingSettings?.company_name && (

{brandingSettings.company_name}

{brandingSettings.company_tagline && (

{brandingSettings.company_tagline}

)}
)}

{event.event_name}

{format(parseISO(event.event_date), 'MMMM d, yyyy')} Expires {format(parseISO(event.expires_at), 'MMM d')}
{daysUntilExpiration <= 1 && daysUntilExpiration > 0 && ( )}
{/* Welcome Message */} {event.welcome_message && (

{event.welcome_message}

)} {/* Search and Filters */}
{/* Search Bar */}
} value={searchTerm} onChange={(e) => setSearchTerm(e.target.value)} />
{/* Sort Dropdown */}
{showSortMenu && (
)}
{/* View Mode Toggle */}

{filteredPhotos.length} {filteredPhotos.length === 1 ? 'photo' : 'photos'}

{/* Photo Grid */}
{/* Footer */}
); };