Fix gallery mobile view issues

- Make logout button show only icon on mobile (no text)
- Move upload button from top bar to sidebar menu on mobile
- Fix top bar layout with proper structure:
  - Logo on left
  - Gallery title centered
  - Event date and expiration date shown below title on mobile
- Improve responsive design for header elements
- Ensure upload button only appears in menu when uploads are enabled

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-07-11 08:30:07 +02:00
parent 5328b4f73a
commit 9006b754a8
11 changed files with 357 additions and 122 deletions
+47
View File
@@ -0,0 +1,47 @@
# TODO - Open Items Before Release
## Priority Items
- [ ] **Gallery Mobile View**
- Logout button should only show logo icon (no text)
- If photo upload is enabled, move upload button inside menu (not on top bar)
- Top bar should show: logo (left), gallery title (center), event date + expiration date
- [ ] **Gallery Preview**
- Preview should correctly reflect the selected grid layout style
- Add grid style selector above current top bar
- Selector should match the style of event template settings grid selector
- [ ] **Hero Grid Layout**
- Top bar: only menu and logout buttons
- Title + logo displayed centered on hero photo
- Event date and expiration date also on hero photo
- No logo/title in top bar
- [ ] **Logo Testing** - Test new PicPeak logos across all grid styles
- [ ] **Welcome Message**
- Add welcome message to email template when creating new event
- Use as personal message in the email
- [ ] **Gallery Upload Function**
- Fix scrolling in upload popup when multiple images selected
- Save/Cancel buttons unreachable due to incorrect scroll formatting
- [ ] **Watermarks** - Test watermark functionality, styling, and image application
- [ ] **Dashboard Activities** - Remove "show all" link from latest activities widget
- [ ] **Security Audit** - Perform security review and code audit
- [ ] **Drone CI/CD** - Update drone.yaml configuration
- [ ] **Version Management** - Implement automatic version updates on commits/builds
## Completed Items
_(Move completed items here with date)_
---
Last updated: 2025-07-10
@@ -0,0 +1,59 @@
import React from 'react';
import { X } from 'lucide-react';
import { Button } from '../common';
import { PhotoUpload } from './PhotoUpload';
import { useTranslation } from 'react-i18next';
interface PhotoUploadModalProps {
isOpen: boolean;
onClose: () => void;
eventId: number;
onUploadComplete?: () => void;
}
export const PhotoUploadModal: React.FC<PhotoUploadModalProps> = ({
isOpen,
onClose,
eventId,
onUploadComplete
}) => {
const { t } = useTranslation();
if (!isOpen) return null;
const handleUploadComplete = () => {
if (onUploadComplete) {
onUploadComplete();
}
onClose();
};
return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4">
<div className="bg-white rounded-lg shadow-xl w-full max-w-2xl flex flex-col max-h-[90vh]">
{/* Fixed Header */}
<div className="flex items-center justify-between p-6 border-b border-neutral-200">
<h2 className="text-xl font-semibold text-neutral-900">{t('events.uploadPhotos')}</h2>
<Button
variant="ghost"
size="sm"
onClick={onClose}
className="!p-1"
>
<X className="w-5 h-5" />
</Button>
</div>
{/* Scrollable Content */}
<div className="flex-1 overflow-y-auto p-6">
<PhotoUpload
eventId={eventId}
onUploadComplete={handleUploadComplete}
/>
</div>
</div>
</div>
);
};
PhotoUploadModal.displayName = 'PhotoUploadModal';
+1
View File
@@ -20,3 +20,4 @@ export { ThemeCustomizerEnhanced } from './ThemeCustomizerEnhanced';
export { ThemeDisplay } from './ThemeDisplay'; export { ThemeDisplay } from './ThemeDisplay';
export { ThemeEditorModal } from './ThemeEditorModal'; export { ThemeEditorModal } from './ThemeEditorModal';
export { HeroPhotoSelector } from './HeroPhotoSelector'; export { HeroPhotoSelector } from './HeroPhotoSelector';
export { PhotoUploadModal } from './PhotoUploadModal';
@@ -91,8 +91,9 @@ export const GalleryLayout: React.FC<GalleryLayoutProps> = ({
size="sm" size="sm"
leftIcon={<LogOut className="w-4 h-4" />} leftIcon={<LogOut className="w-4 h-4" />}
onClick={onLogout} onClick={onLogout}
className="sm:min-w-0"
> >
{t('common.logout')} <span className="hidden sm:inline">{t('common.logout')}</span>
</Button> </Button>
)} )}
</div> </div>
@@ -101,17 +102,12 @@ export const GalleryLayout: React.FC<GalleryLayoutProps> = ({
</div> </div>
)} )}
{/* For grid and hero layouts - everything in one bar */} {/* For grid layout - everything in one bar */}
{(!isNonGridLayout || theme.galleryLayout === 'hero') && ( {!isNonGridLayout && theme.galleryLayout !== 'hero' && (
<div className="container py-3"> <div className="container py-3">
<div className="flex items-center justify-between gap-4"> <div className="flex items-center justify-between gap-2 sm:gap-4">
{/* Left side - Logo, Title, and Dates */} {/* Left side - Logo and menu button on mobile */}
<div className="flex items-center gap-4 flex-1 min-w-0"> <div className="flex items-center gap-2 sm:gap-4 flex-shrink-0">
{/* Menu button */}
<div className="flex-shrink-0">
{headerExtra}
</div>
{/* Logo - Show custom logo or fallback to PicPeak logo */} {/* Logo - Show custom logo or fallback to PicPeak logo */}
<div className="flex-shrink-0"> <div className="flex-shrink-0">
<img <img
@@ -120,20 +116,26 @@ export const GalleryLayout: React.FC<GalleryLayoutProps> = ({
'/picpeak-logo-transparent.png' '/picpeak-logo-transparent.png'
} }
alt={brandingSettings?.company_name || 'PicPeak'} alt={brandingSettings?.company_name || 'PicPeak'}
className="h-10 sm:h-12 w-auto object-contain" className="h-8 sm:h-10 lg:h-12 w-auto object-contain"
/> />
</div> </div>
{/* Event info */} {/* Menu button on mobile */}
<div className="flex-1 min-w-0"> <div className="flex-shrink-0 sm:hidden">
{headerExtra}
</div>
</div>
{/* Center - Event info */}
<div className="flex-1 min-w-0 text-center sm:text-left">
<h1 <h1
className="text-lg sm:text-xl lg:text-2xl font-bold text-neutral-900 leading-tight truncate" className="text-base sm:text-lg lg:text-xl font-bold text-neutral-900 leading-tight truncate"
style={{ fontFamily: headingFontFamily }} style={{ fontFamily: headingFontFamily }}
> >
{event.event_name} {event.event_name}
</h1> </h1>
{(event.event_date || event.expires_at) && ( {(event.event_date || event.expires_at) && (
<div className="flex flex-wrap gap-x-3 gap-y-1 mt-1 text-xs sm:text-sm text-neutral-600"> <div className="hidden sm:flex flex-wrap gap-x-3 gap-y-1 mt-1 text-xs sm:text-sm text-neutral-600">
{event.event_date && ( {event.event_date && (
<span className="flex items-center"> <span className="flex items-center">
<Calendar className="w-3 h-3 sm:w-4 sm:h-4 mr-1 flex-shrink-0" /> <Calendar className="w-3 h-3 sm:w-4 sm:h-4 mr-1 flex-shrink-0" />
@@ -149,6 +151,71 @@ export const GalleryLayout: React.FC<GalleryLayoutProps> = ({
</div> </div>
)} )}
</div> </div>
{/* Right side - Action buttons */}
<div className="flex items-center gap-2 sm:gap-3 flex-shrink-0">
{/* Menu button on desktop */}
<div className="hidden sm:block">
{headerExtra}
</div>
{/* Download all button - hidden on mobile when sidebar is shown */}
{showDownloadAll && onDownloadAll && (
<Button
variant="primary"
size="sm"
leftIcon={<Download className="w-4 h-4" />}
onClick={onDownloadAll}
isLoading={isDownloading}
className="hidden sm:flex"
>
<span className="hidden sm:inline">{t('gallery.downloadAll')}</span>
<span className="sm:hidden">{t('common.download')}</span>
</Button>
)}
{/* Logout button */}
{showLogout && onLogout && (
<Button
variant="outline"
size="sm"
leftIcon={<LogOut className="w-4 h-4" />}
onClick={onLogout}
className="sm:min-w-0"
>
<span className="hidden sm:inline">{t('common.logout')}</span>
</Button>
)}
</div>
</div>
{/* Mobile dates row */}
{(event.event_date || event.expires_at) && (
<div className="flex sm:hidden justify-center gap-x-3 mt-2 text-xs text-neutral-600">
{event.event_date && (
<span className="flex items-center">
<Calendar className="w-3 h-3 mr-1 flex-shrink-0" />
<span>{format(parseISO(event.event_date), 'PP')}</span>
</span>
)}
{event.expires_at && (
<span className="flex items-center">
<Clock className="w-3 h-3 mr-1 flex-shrink-0" />
<span>{t('gallery.expires')} {format(parseISO(event.expires_at), 'PP')}</span>
</span>
)}
</div>
)}
</div>
)}
{/* For hero layout - minimal header with just menu and logout */}
{theme.galleryLayout === 'hero' && (
<div className="container py-3">
<div className="flex items-center justify-between">
{/* Left side - Menu button */}
<div className="flex-shrink-0">
{headerExtra}
</div> </div>
{/* Right side - Action buttons */} {/* Right side - Action buttons */}
@@ -174,8 +241,9 @@ export const GalleryLayout: React.FC<GalleryLayoutProps> = ({
size="sm" size="sm"
leftIcon={<LogOut className="w-4 h-4" />} leftIcon={<LogOut className="w-4 h-4" />}
onClick={onLogout} onClick={onLogout}
className="sm:min-w-0"
> >
{t('common.logout')} <span className="hidden sm:inline">{t('common.logout')}</span>
</Button> </Button>
)} )}
</div> </div>
@@ -1,5 +1,5 @@
import React, { useEffect, useRef } from 'react'; import React, { useEffect, useRef } from 'react';
import { X, Download, Filter, SortAsc, Search, Calendar, Type, HardDrive, Check } from 'lucide-react'; import { X, Download, Filter, SortAsc, Search, Calendar, Type, HardDrive, Check, Upload } from 'lucide-react';
import { Button } from '../common'; import { Button } from '../common';
import { PhotoCategory } from '../../types'; import { PhotoCategory } from '../../types';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@@ -24,6 +24,8 @@ interface GallerySidebarProps {
totalPhotos: number; totalPhotos: number;
isMobile: boolean; isMobile: boolean;
galleryLayout?: string; galleryLayout?: string;
allowUploads?: boolean;
onUploadClick?: () => void;
} }
export const GallerySidebar: React.FC<GallerySidebarProps> = ({ export const GallerySidebar: React.FC<GallerySidebarProps> = ({
@@ -45,7 +47,9 @@ export const GallerySidebar: React.FC<GallerySidebarProps> = ({
photoCounts = {}, photoCounts = {},
totalPhotos, totalPhotos,
isMobile, isMobile,
galleryLayout galleryLayout,
allowUploads,
onUploadClick
}) => { }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const sidebarRef = useRef<HTMLDivElement>(null); const sidebarRef = useRef<HTMLDivElement>(null);
@@ -113,6 +117,24 @@ export const GallerySidebar: React.FC<GallerySidebarProps> = ({
{/* Content */} {/* Content */}
<div className="flex-1 overflow-y-auto"> <div className="flex-1 overflow-y-auto">
{/* Upload Section - Only show on mobile when uploads are allowed */}
{isMobile && allowUploads && onUploadClick && (
<div className="p-4 border-b border-neutral-200">
<Button
variant="outline"
size="sm"
leftIcon={<Upload className="w-4 h-4" />}
onClick={() => {
onUploadClick();
onClose();
}}
className="w-full"
>
{t('upload.uploadPhotos')}
</Button>
</div>
)}
{/* Search Section - Hidden for carousel layout */} {/* Search Section - Hidden for carousel layout */}
{galleryLayout !== 'carousel' && ( {galleryLayout !== 'carousel' && (
<div className="p-4 border-b border-neutral-200"> <div className="p-4 border-b border-neutral-200">
@@ -307,6 +307,8 @@ export const GalleryView: React.FC<GalleryViewProps> = ({ slug, event }) => {
totalPhotos={data?.photos.length || 0} totalPhotos={data?.photos.length || 0}
isMobile={isMobile} isMobile={isMobile}
galleryLayout={theme.galleryLayout} galleryLayout={theme.galleryLayout}
allowUploads={event.allow_user_uploads}
onUploadClick={() => setShowUploadModal(true)}
/> />
) : null} ) : null}
@@ -331,7 +333,7 @@ export const GalleryView: React.FC<GalleryViewProps> = ({ slug, event }) => {
onClick={() => setSidebarOpen(!sidebarOpen)} onClick={() => setSidebarOpen(!sidebarOpen)}
aria-label={t('gallery.toggleMenu')} aria-label={t('gallery.toggleMenu')}
> >
{t('common.menu')} <span className="hidden sm:inline">{t('common.menu')}</span>
</Button> </Button>
); );
} }
@@ -342,7 +344,23 @@ export const GalleryView: React.FC<GalleryViewProps> = ({ slug, event }) => {
); );
} }
if (event.allow_user_uploads) { // Upload button only on desktop when sidebar is shown
if (event.allow_user_uploads && showSidebar && !isMobile) {
items.push(
<Button
key="upload-button"
variant="outline"
size="sm"
leftIcon={<Upload className="w-4 h-4" />}
onClick={() => setShowUploadModal(true)}
>
{t('upload.uploadPhotos')}
</Button>
);
}
// Upload button for non-sidebar layouts
if (event.allow_user_uploads && !showSidebar) {
items.push( items.push(
<Button <Button
key="upload-button" key="upload-button"
@@ -396,6 +414,8 @@ export const GalleryView: React.FC<GalleryViewProps> = ({ slug, event }) => {
showSelectionControls={!showSidebar} showSelectionControls={!showSidebar}
eventName={event.event_name} eventName={event.event_name}
eventLogo={brandingSettings?.logo_url} eventLogo={brandingSettings?.logo_url}
eventDate={event.event_date}
expiresAt={event.expires_at}
/> />
</div> </div>
@@ -32,6 +32,8 @@ interface PhotoGridWithLayoutsProps {
showSelectionControls?: boolean; showSelectionControls?: boolean;
eventName?: string; eventName?: string;
eventLogo?: string | null; eventLogo?: string | null;
eventDate?: string;
expiresAt?: string;
} }
export const PhotoGridWithLayouts: React.FC<PhotoGridWithLayoutsProps> = ({ export const PhotoGridWithLayouts: React.FC<PhotoGridWithLayoutsProps> = ({
@@ -44,7 +46,9 @@ export const PhotoGridWithLayouts: React.FC<PhotoGridWithLayoutsProps> = ({
onToggleSelectionMode: parentToggleSelectionMode, onToggleSelectionMode: parentToggleSelectionMode,
showSelectionControls = true, showSelectionControls = true,
eventName, eventName,
eventLogo eventLogo,
eventDate,
expiresAt
}) => { }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { theme } = useTheme(); const { theme } = useTheme();
@@ -160,6 +164,8 @@ export const PhotoGridWithLayouts: React.FC<PhotoGridWithLayoutsProps> = ({
onPhotoSelect: handlePhotoSelect, onPhotoSelect: handlePhotoSelect,
eventName, eventName,
eventLogo, eventLogo,
eventDate,
expiresAt,
}; };
let LayoutComponent; let LayoutComponent;
@@ -113,11 +113,10 @@ export const UserPhotoUpload: React.FC<UserPhotoUploadProps> = ({
}; };
return ( return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-end sm:items-center justify-center z-50"> <div className="fixed inset-0 bg-black bg-opacity-50 flex items-end sm:items-center justify-center z-50 p-0 sm:p-4">
<Card className="w-full sm:max-w-2xl max-h-[100vh] sm:max-h-[90vh] overflow-hidden sm:mx-4 rounded-t-2xl sm:rounded-2xl"> <div className="w-full sm:max-w-2xl bg-white flex flex-col max-h-[100vh] sm:max-h-[90vh] rounded-t-2xl sm:rounded-2xl shadow-xl">
<CardContent className="p-0"> {/* Fixed Header */}
{/* Header */} <div className="flex items-center justify-between p-4 sm:p-6 border-b border-neutral-200 flex-shrink-0">
<div className="flex items-center justify-between p-4 sm:p-6 border-b border-neutral-200">
<h2 className="text-lg sm:text-xl font-semibold text-neutral-900">{t('upload.uploadPhotos')}</h2> <h2 className="text-lg sm:text-xl font-semibold text-neutral-900">{t('upload.uploadPhotos')}</h2>
<button <button
onClick={onClose} onClick={onClose}
@@ -127,8 +126,8 @@ export const UserPhotoUpload: React.FC<UserPhotoUploadProps> = ({
</button> </button>
</div> </div>
{/* Content */} {/* Scrollable Content */}
<div className="p-4 sm:p-6 overflow-y-auto" style={{ maxHeight: 'calc(100vh - 160px)', minHeight: '300px' }}> <div className="flex-1 p-4 sm:p-6 overflow-y-auto min-h-0">
{/* Upload Area */} {/* Upload Area */}
<div className="mb-4 sm:mb-6"> <div className="mb-4 sm:mb-6">
<label className="block"> <label className="block">
@@ -201,8 +200,8 @@ export const UserPhotoUpload: React.FC<UserPhotoUploadProps> = ({
)} )}
</div> </div>
{/* Footer */} {/* Fixed Footer */}
<div className="flex items-center justify-end gap-2 sm:gap-3 p-4 sm:p-6 border-t border-neutral-200 bg-white"> <div className="flex items-center justify-end gap-2 sm:gap-3 p-4 sm:p-6 border-t border-neutral-200 bg-white flex-shrink-0">
<Button <Button
variant="outline" variant="outline"
onClick={onClose} onClick={onClose}
@@ -221,8 +220,7 @@ export const UserPhotoUpload: React.FC<UserPhotoUploadProps> = ({
{uploading ? t('upload.uploading') : t('common.upload')} ({files.length}) {uploading ? t('upload.uploading') : t('common.upload')} ({files.length})
</Button> </Button>
</div> </div>
</CardContent> </div>
</Card>
</div> </div>
); );
}; };
@@ -11,6 +11,8 @@ export interface BaseGalleryLayoutProps {
onPhotoSelect?: (photoId: number) => void; onPhotoSelect?: (photoId: number) => void;
eventName?: string; eventName?: string;
eventLogo?: string | null; eventLogo?: string | null;
eventDate?: string;
expiresAt?: string;
} }
export abstract class BaseGalleryLayout<T extends BaseGalleryLayoutProps = BaseGalleryLayoutProps> extends React.Component<T> { export abstract class BaseGalleryLayout<T extends BaseGalleryLayoutProps = BaseGalleryLayoutProps> extends React.Component<T> {
@@ -1,5 +1,8 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { Download, Maximize2, Check, ChevronDown } from 'lucide-react'; import { Download, Maximize2, Check, ChevronDown, Calendar, Clock } from 'lucide-react';
import { parseISO } from 'date-fns';
import { useTranslation } from 'react-i18next';
import { useLocalizedDate } from '../../../hooks/useLocalizedDate';
import { useTheme } from '../../../contexts/ThemeContext'; import { useTheme } from '../../../contexts/ThemeContext';
import { AuthenticatedImage } from '../../common'; import { AuthenticatedImage } from '../../common';
import type { BaseGalleryLayoutProps } from './BaseGalleryLayout'; import type { BaseGalleryLayoutProps } from './BaseGalleryLayout';
@@ -8,6 +11,8 @@ import type { Photo } from '../../../types';
interface HeroGalleryLayoutProps extends BaseGalleryLayoutProps { interface HeroGalleryLayoutProps extends BaseGalleryLayoutProps {
eventName?: string; eventName?: string;
eventLogo?: string | null; eventLogo?: string | null;
eventDate?: string;
expiresAt?: string;
} }
export const HeroGalleryLayout: React.FC<HeroGalleryLayoutProps> = ({ export const HeroGalleryLayout: React.FC<HeroGalleryLayoutProps> = ({
@@ -18,8 +23,12 @@ export const HeroGalleryLayout: React.FC<HeroGalleryLayoutProps> = ({
isSelectionMode = false, isSelectionMode = false,
onPhotoSelect, onPhotoSelect,
eventName, eventName,
eventLogo eventLogo,
eventDate,
expiresAt
}) => { }) => {
const { t } = useTranslation();
const { format } = useLocalizedDate();
const { theme } = useTheme(); const { theme } = useTheme();
const [heroPhoto, setHeroPhoto] = useState<Photo | null>(null); const [heroPhoto, setHeroPhoto] = useState<Photo | null>(null);
const gallerySettings = theme.gallerySettings || {}; const gallerySettings = theme.gallerySettings || {};
@@ -72,10 +81,28 @@ export const HeroGalleryLayout: React.FC<HeroGalleryLayoutProps> = ({
{/* Event Title */} {/* Event Title */}
{eventName && ( {eventName && (
<h1 className="text-3xl sm:text-4xl lg:text-5xl xl:text-6xl font-bold text-white drop-shadow-lg"> <h1 className="text-3xl sm:text-4xl lg:text-5xl xl:text-6xl font-bold text-white drop-shadow-lg mb-4">
{eventName} {eventName}
</h1> </h1>
)} )}
{/* Event Dates */}
{(eventDate || expiresAt) && (
<div className="flex flex-wrap items-center justify-center gap-4 sm:gap-6 text-white/90">
{eventDate && (
<span className="flex items-center text-lg sm:text-xl">
<Calendar className="w-5 h-5 sm:w-6 sm:h-6 mr-2" />
{format(parseISO(eventDate), 'PP')}
</span>
)}
{expiresAt && (
<span className="flex items-center text-lg sm:text-xl">
<Clock className="w-5 h-5 sm:w-6 sm:h-6 mr-2" />
{t('gallery.expires')} {format(parseISO(expiresAt), 'PP')}
</span>
)}
</div>
)}
</div> </div>
</div> </div>
+5 -20
View File
@@ -24,7 +24,7 @@ import { toast } from 'react-toastify';
import { useLocalizedDate } from '../../hooks/useLocalizedDate'; import { useLocalizedDate } from '../../hooks/useLocalizedDate';
import { Button, Input, Card, Loading } from '../../components/common'; import { Button, Input, Card, Loading } from '../../components/common';
import { PhotoUpload, EventCategoryManager, AdminPhotoGrid, AdminPhotoViewer, PhotoFilters, PasswordResetModal, ThemeDisplay, ThemeCustomizerEnhanced, ThemeEditorModal, HeroPhotoSelector } from '../../components/admin'; import { PhotoUpload, EventCategoryManager, AdminPhotoGrid, AdminPhotoViewer, PhotoFilters, PasswordResetModal, ThemeDisplay, ThemeCustomizerEnhanced, ThemeEditorModal, HeroPhotoSelector, PhotoUploadModal } from '../../components/admin';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { eventsService } from '../../services/events.service'; import { eventsService } from '../../services/events.service';
import { archiveService } from '../../services/archive.service'; import { archiveService } from '../../services/archive.service';
@@ -887,31 +887,18 @@ export const EventDetailsPage: React.FC = () => {
{/* Photos Tab */} {/* Photos Tab */}
{activeTab === 'photos' && ( {activeTab === 'photos' && (
<div> <div>
{/* Photo Upload */} {/* Photo Upload Modal */}
{showPhotoUpload && ( <PhotoUploadModal
<Card padding="md" className="mb-6"> isOpen={showPhotoUpload}
<div className="flex items-center justify-between mb-4"> onClose={() => setShowPhotoUpload(false)}
<h2 className="text-lg font-semibold text-neutral-900">{t('events.uploadPhotos')}</h2>
<Button
variant="ghost"
size="sm"
onClick={() => setShowPhotoUpload(false)}
>
<X className="w-4 h-4" />
</Button>
</div>
<PhotoUpload
eventId={parseInt(id!)} eventId={parseInt(id!)}
onUploadComplete={() => { onUploadComplete={() => {
queryClient.invalidateQueries({ queryKey: ['admin-event', id] }); queryClient.invalidateQueries({ queryKey: ['admin-event', id] });
queryClient.invalidateQueries({ queryKey: ['admin-event-photos', id] }); queryClient.invalidateQueries({ queryKey: ['admin-event-photos', id] });
toast.success(t('toast.uploadSuccess')); toast.success(t('toast.uploadSuccess'));
setShowPhotoUpload(false);
refetchPhotos(); refetchPhotos();
}} }}
/> />
</Card>
)}
{/* Photo Filters */} {/* Photo Filters */}
<PhotoFilters <PhotoFilters
@@ -926,7 +913,6 @@ export const EventDetailsPage: React.FC = () => {
/> />
{/* Actions Bar */} {/* Actions Bar */}
{!showPhotoUpload && (
<div className="mb-4 flex justify-between items-center"> <div className="mb-4 flex justify-between items-center">
<Button <Button
variant="primary" variant="primary"
@@ -937,7 +923,6 @@ export const EventDetailsPage: React.FC = () => {
{t('events.uploadPhotos')} {t('events.uploadPhotos')}
</Button> </Button>
</div> </div>
)}
{/* Photo Grid */} {/* Photo Grid */}
{photosLoading ? ( {photosLoading ? (