diff --git a/backend/src/services/fileWatcher.js b/backend/src/services/fileWatcher.js index 62ba370..847f8a4 100644 --- a/backend/src/services/fileWatcher.js +++ b/backend/src/services/fileWatcher.js @@ -63,17 +63,26 @@ async function processNewPhoto(filePath) { // Calculate relative thumbnail path const relativeThumbPath = thumbnailPath; // thumbnailPath is already relative to storage root - // Add to database - await db('photos').insert({ - event_id: event.id, - filename: path.basename(filePath), - path: relativePath, - thumbnail_path: relativeThumbPath, - type: photoType, - size_bytes: stats.size - }); + // Check if photo already exists + const existingPhoto = await db('photos') + .where({ event_id: event.id, filename: path.basename(filePath) }) + .first(); - logger.info(`Added new photo: ${relativePath}`); + if (!existingPhoto) { + // Add to database + await db('photos').insert({ + event_id: event.id, + filename: path.basename(filePath), + path: relativePath, + thumbnail_path: relativeThumbPath, + type: photoType, + size_bytes: stats.size + }); + + logger.info(`Added new photo: ${relativePath}`); + } else { + logger.debug(`Photo already exists: ${relativePath}`); + } } async function removePhoto(filePath) { diff --git a/frontend/src/components/common/AuthenticatedImage.tsx b/frontend/src/components/common/AuthenticatedImage.tsx index 357a579..8a98cc6 100644 --- a/frontend/src/components/common/AuthenticatedImage.tsx +++ b/frontend/src/components/common/AuthenticatedImage.tsx @@ -5,6 +5,7 @@ interface AuthenticatedImageProps extends React.ImgHTMLAttributes = ({ @@ -12,6 +13,7 @@ export const AuthenticatedImage: React.FC = ({ fallbackSrc, alt, useWatermark = false, + isGallery = false, ...props }) => { const [imageSrc, setImageSrc] = useState(''); @@ -21,7 +23,20 @@ export const AuthenticatedImage: React.FC = ({ useEffect(() => { let objectUrl: string | null = null; - const token = getAuthToken(); + // Determine which token to use based on context + let token: string | undefined; + + if (isGallery) { + // For gallery images, get the gallery-specific token + const pathParts = window.location.pathname.split('/'); + if (pathParts[1] === 'gallery' && pathParts[2]) { + const gallerySlug = pathParts[2]; + token = localStorage.getItem(`gallery_token_${gallerySlug}`) || undefined; + } + } else { + // For admin images, use the admin token + token = getAuthToken(true); + } if (!src) { setImageSrc(fallbackSrc || ''); @@ -89,7 +104,7 @@ export const AuthenticatedImage: React.FC = ({ URL.revokeObjectURL(objectUrl); } }; - }, [src, fallbackSrc, useWatermark]); + }, [src, fallbackSrc, useWatermark, isGallery]); if (isLoading) { return ( diff --git a/frontend/src/components/gallery/PhotoGrid.tsx b/frontend/src/components/gallery/PhotoGrid.tsx index 336764c..5eb3557 100644 --- a/frontend/src/components/gallery/PhotoGrid.tsx +++ b/frontend/src/components/gallery/PhotoGrid.tsx @@ -237,6 +237,7 @@ const PhotoThumbnail: React.FC = ({ alt={photo.filename} className="w-full h-full object-cover rounded-lg transition-transform duration-200 group-hover:scale-105" loading="lazy" + isGallery={true} /> {/* Overlay on hover */} diff --git a/frontend/src/components/gallery/PhotoLightbox.tsx b/frontend/src/components/gallery/PhotoLightbox.tsx index ef73c26..928d274 100644 --- a/frontend/src/components/gallery/PhotoLightbox.tsx +++ b/frontend/src/components/gallery/PhotoLightbox.tsx @@ -252,6 +252,7 @@ export const PhotoLightbox: React.FC = ({ }} draggable={false} useWatermark={true} + isGallery={true} />