import React from 'react'; import { Download, Maximize2, Check, Heart, MessageSquare } from 'lucide-react'; // import { useTheme } from '../../../contexts/ThemeContext'; import { AuthenticatedImage } from '../../common'; import { FeedbackIdentityModal } from '../../gallery/FeedbackIdentityModal'; import { feedbackService } from '../../../services/feedback.service'; import type { BaseGalleryLayoutProps } from './BaseGalleryLayout'; import type { Photo } from '../../../types'; interface MosaicPhotoProps { photo: Photo; isSelected: boolean; isSelectionMode: boolean; onClick: (e: React.MouseEvent) => void; onDownload: (e: React.MouseEvent) => void; onToggleSelect: () => void; className?: string; allowDownloads?: boolean; slug?: string; feedbackEnabled?: boolean; feedbackOptions?: { allowLikes?: boolean; allowComments?: boolean; requireNameEmail?: boolean; }; onQuickComment?: () => void; } const MosaicPhoto: React.FC = ({ photo, isSelected, isSelectionMode, onClick, onDownload, onToggleSelect, className = '', allowDownloads = true, slug, feedbackEnabled = false, feedbackOptions, onQuickComment }) => { const [showIdentityModal, setShowIdentityModal] = React.useState(false); const [pendingAction, setPendingAction] = React.useState(null); const [savedIdentity, setSavedIdentity] = React.useState<{ name: string; email: string } | null>(null); const [likedLocal, setLikedLocal] = React.useState(false); const canComment = Boolean(feedbackEnabled && feedbackOptions?.allowComments && onQuickComment); return ( <>
{ e.stopPropagation(); onClick(e); }} >
{!isSelectionMode && ( <> {allowDownloads && ( )} {feedbackOptions?.allowLikes && ( )} {canComment && ( )} )}
{/* Feedback Indicators (bottom-left) */} {((photo.like_count ?? 0) > 0 || likedLocal) && (
)} {/* Selection Checkbox (visible on hover or when selected) */} {photo.type === 'collage' && (
Collage
)}
{ setShowIdentityModal(false); setPendingAction(null); }} onSubmit={async (name, email) => { setSavedIdentity({ name, email }); setShowIdentityModal(false); if (pendingAction) { await feedbackService.submitFeedback(slug!, String(pendingAction.photoId), { feedback_type: pendingAction.type, guest_name: name, guest_email: email, }); setPendingAction(null); } }} feedbackType="like" /> ); }; export const MosaicGalleryLayout: React.FC = ({ photos, slug, onPhotoClick, onOpenPhotoWithFeedback, onDownload, selectedPhotos = new Set(), isSelectionMode = false, onPhotoSelect, allowDownloads = true, feedbackEnabled = false, feedbackOptions }) => { // const { theme } = useTheme(); // const gallerySettings = theme.gallerySettings || {}; // const pattern = gallerySettings.mosaicPattern || 'structured'; const handlePhotoClick = (index: number, photoId: number) => { if (isSelectionMode && onPhotoSelect) { onPhotoSelect(photoId); } else { onPhotoClick(index); } }; // Create a more structured mosaic layout const renderMosaicLayout = () => { const elements = []; let photoIndex = 0; let patternIndex = 0; while (photoIndex < photos.length) { const remainingPhotos = photos.length - photoIndex; // Choose pattern based on rotation and remaining photos if (patternIndex % 3 === 0 && remainingPhotos >= 3) { // Pattern 1: Large left, 2 small right // Capture indices immediately to avoid closure issues const idx0 = photoIndex; const idx1 = photoIndex + 1; const idx2 = photoIndex + 2; const photo0 = photos[idx0]; const photo1 = photos[idx1]; const photo2 = photos[idx2]; elements.push(
{photo0 && ( onPhotoClick(idx0)} onDownload={(e) => onDownload(photo0, e)} onToggleSelect={() => onPhotoSelect && onPhotoSelect(photo0.id)} className="col-span-1" allowDownloads={allowDownloads} slug={slug} feedbackEnabled={feedbackEnabled} feedbackOptions={feedbackOptions} onQuickComment={() => { if (typeof onOpenPhotoWithFeedback !== 'undefined' && onOpenPhotoWithFeedback) onOpenPhotoWithFeedback(idx0); }} /> )}
{photo1 && ( onPhotoClick(idx1)} onDownload={(e) => onDownload(photo1, e)} onToggleSelect={() => onPhotoSelect && onPhotoSelect(photo1.id)} className="" allowDownloads={allowDownloads} slug={slug} feedbackEnabled={feedbackEnabled} feedbackOptions={feedbackOptions} onQuickComment={() => { if (typeof onOpenPhotoWithFeedback !== 'undefined' && onOpenPhotoWithFeedback) onOpenPhotoWithFeedback(idx1); }} /> )} {photo2 && ( onPhotoClick(idx2)} onDownload={(e) => onDownload(photo2, e)} onToggleSelect={() => onPhotoSelect && onPhotoSelect(photo2.id)} className="" allowDownloads={allowDownloads} slug={slug} feedbackEnabled={feedbackEnabled} feedbackOptions={feedbackOptions} onQuickComment={() => { if (typeof onOpenPhotoWithFeedback !== 'undefined' && onOpenPhotoWithFeedback) onOpenPhotoWithFeedback(idx2); }} /> )}
); photoIndex += 3; } else if (patternIndex % 3 === 1 && remainingPhotos >= 3) { // Pattern 2: 3 equal columns elements.push(
{[0, 1, 2].map(offset => { const currentIndex = photoIndex + offset; const photo = photos[currentIndex]; return photo ? ( handlePhotoClick(currentIndex, photo.id)} onDownload={(e) => onDownload(photo, e)} onToggleSelect={() => onPhotoSelect && onPhotoSelect(photo.id)} className="" allowDownloads={allowDownloads} slug={slug} feedbackEnabled={feedbackEnabled} feedbackOptions={feedbackOptions} onQuickComment={() => { if (typeof onOpenPhotoWithFeedback !== 'undefined' && onOpenPhotoWithFeedback) onOpenPhotoWithFeedback(currentIndex); }} /> ) : null; })}
); photoIndex += 3; } else if (patternIndex % 3 === 2 && remainingPhotos >= 3) { // Pattern 3: Large span-2 with 2 small on right // Capture indices immediately to avoid closure issues const idx0 = photoIndex; const idx1 = photoIndex + 1; const idx2 = photoIndex + 2; const photo0 = photos[idx0]; const photo1 = photos[idx1]; const photo2 = photos[idx2]; elements.push(
{photo0 && ( onPhotoClick(idx0)} onDownload={(e) => onDownload(photo0, e)} onToggleSelect={() => onPhotoSelect && onPhotoSelect(photo0.id)} className="col-span-2" allowDownloads={allowDownloads} slug={slug} feedbackEnabled={feedbackEnabled} feedbackOptions={feedbackOptions} onQuickComment={() => { if (typeof onOpenPhotoWithFeedback !== 'undefined' && onOpenPhotoWithFeedback) onOpenPhotoWithFeedback(idx0); }} /> )}
{photo1 && ( onPhotoClick(idx1)} onDownload={(e) => onDownload(photo1, e)} onToggleSelect={() => onPhotoSelect && onPhotoSelect(photo1.id)} className="" allowDownloads={allowDownloads} slug={slug} feedbackEnabled={feedbackEnabled} feedbackOptions={feedbackOptions} onQuickComment={() => { if (typeof onOpenPhotoWithFeedback !== 'undefined' && onOpenPhotoWithFeedback) onOpenPhotoWithFeedback(idx1); }} /> )} {photo2 && ( onPhotoClick(idx2)} onDownload={(e) => onDownload(photo2, e)} onToggleSelect={() => onPhotoSelect && onPhotoSelect(photo2.id)} className="" allowDownloads={allowDownloads} slug={slug} feedbackEnabled={feedbackEnabled} feedbackOptions={feedbackOptions} onQuickComment={() => { if (typeof onOpenPhotoWithFeedback !== 'undefined' && onOpenPhotoWithFeedback) onOpenPhotoWithFeedback(idx2); }} /> )}
); photoIndex += 3; } else { // Handle remaining photos that don't fit patterns break; } patternIndex++; } // Add remaining photos in a regular grid if (photoIndex < photos.length) { const remainingPhotos = photos.slice(photoIndex); elements.push(
{remainingPhotos.map((photo, idx) => { const index = photoIndex + idx; return ( onPhotoClick(index)} onDownload={(e) => onDownload(photo, e)} onToggleSelect={() => onPhotoSelect && onPhotoSelect(photo.id)} className="aspect-square" allowDownloads={allowDownloads} slug={slug} feedbackEnabled={feedbackEnabled} feedbackOptions={feedbackOptions} onQuickComment={() => { if (typeof onOpenPhotoWithFeedback !== 'undefined' && onOpenPhotoWithFeedback) onOpenPhotoWithFeedback(index); }} /> ); })}
); } return elements; }; return (
{renderMosaicLayout()}
); };