feat: decouple hero header from gallery layouts (#158)
- Add separate header_style setting (hero/standard/minimal/none) that can be combined with any layout type (grid/masonry/carousel/timeline/mosaic) - Create HeroHeader and HeroDivider components for reusable hero section - Add hero_divider_style setting (wave/straight/angle/curve/none) - Add database migration for header_style and hero_divider_style columns - Remove deprecated HeroGalleryLayout component - Fix various TypeScript errors across the codebase: - Add missing type properties (css_template_id, updatedAt, justified settings) - Fix null handling for event_date and expires_at fields - Fix translation function calls and i18n config - Remove unused imports and variables
This commit is contained in:
@@ -195,7 +195,7 @@ export const AdminDashboard: React.FC = () => {
|
||||
) : (
|
||||
<div className="space-y-3">
|
||||
{expiringEvents.slice(0, 5).map((event) => {
|
||||
const daysLeft = differenceInDays(parseISO(event.expires_at), new Date());
|
||||
const daysLeft = differenceInDays(parseISO(event.expires_at!), new Date());
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -216,7 +216,7 @@ export const AdminDashboard: React.FC = () => {
|
||||
{t('admin.daysLeft', { count: daysLeft })}
|
||||
</p>
|
||||
<p className="text-xs text-neutral-500">
|
||||
{t('gallery.expires')} {format(parseISO(event.expires_at), 'PP')}
|
||||
{t('gallery.expires')} {format(parseISO(event.expires_at!), 'PP')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -20,6 +20,7 @@ import { eventsService } from '../../services/events.service';
|
||||
import { useLocalizedDate } from '../../hooks/useLocalizedDate';
|
||||
import { categoriesService } from '../../services/categories.service';
|
||||
import { settingsService } from '../../services/settings.service';
|
||||
import { publicSettingsService } from '../../services/publicSettings.service';
|
||||
import { cssTemplatesService } from '../../services/cssTemplates.service';
|
||||
import { eventTypesService } from '../../services/eventTypes.service';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -152,7 +153,7 @@ export const CreateEventPage: React.FC = () => {
|
||||
// Fetch public settings for field requirements
|
||||
const { data: publicSettings } = useQuery({
|
||||
queryKey: ['public-settings'],
|
||||
queryFn: () => settingsService.getPublicSettings()
|
||||
queryFn: () => publicSettingsService.getPublicSettings()
|
||||
});
|
||||
|
||||
// Get field requirements (default to true if not set)
|
||||
|
||||
@@ -60,7 +60,7 @@ import { buildResourceUrl } from '../../utils/url';
|
||||
import { isGalleryPublic, normalizeRequirePassword } from '../../utils/accessControl';
|
||||
import { archiveService } from '../../services/archive.service';
|
||||
import { externalMediaService } from '../../services/externalMedia.service';
|
||||
import { photosService, AdminPhoto, type PhotoFilters as PhotoFilterParams, type FeedbackFilters, type FilterSummary } from '../../services/photos.service';
|
||||
import { photosService, AdminPhoto, type PhotoFilters as PhotoFilterParams, type FeedbackFilters } from '../../services/photos.service';
|
||||
import { feedbackService, FeedbackSettings as FeedbackSettingsType } from '../../services/feedback.service';
|
||||
import { cssTemplatesService, type EnabledTemplate } from '../../services/cssTemplates.service';
|
||||
import { ThemeConfig, GALLERY_THEME_PRESETS } from '../../types/theme.types';
|
||||
@@ -337,28 +337,6 @@ export const EventDetailsPage: React.FC = () => {
|
||||
},
|
||||
});
|
||||
|
||||
const applyThemeMutation = useMutation({
|
||||
mutationFn: async ({ theme, presetName }: { theme: ThemeConfig; presetName: string }) => {
|
||||
if (!id) {
|
||||
throw new Error('Missing event identifier');
|
||||
}
|
||||
|
||||
const colorThemeValue = presetName && presetName !== 'custom'
|
||||
? presetName
|
||||
: JSON.stringify(theme);
|
||||
|
||||
return eventsService.updateEvent(parseInt(id), { color_theme: colorThemeValue });
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['admin-event', id] });
|
||||
toast.success(t('branding.themeApplied', 'Theme updated'));
|
||||
},
|
||||
onError: (error: any) => {
|
||||
const message = error?.response?.data?.error || t('branding.themeApplyError', 'Failed to apply theme');
|
||||
toast.error(message);
|
||||
}
|
||||
});
|
||||
|
||||
// Archive mutation
|
||||
const archiveMutation = useMutation({
|
||||
mutationFn: () => eventsService.archiveEvent(parseInt(id!)),
|
||||
@@ -470,7 +448,7 @@ export const EventDetailsPage: React.FC = () => {
|
||||
try {
|
||||
const formData = new FormData();
|
||||
formData.append('logo', file);
|
||||
const response = await api.post(`/admin/events/${id}/logo`, formData, {
|
||||
await api.post(`/admin/events/${id}/logo`, formData, {
|
||||
headers: { 'Content-Type': 'multipart/form-data' }
|
||||
});
|
||||
toast.success(t('events.eventLogoUploaded', 'Event logo uploaded successfully'));
|
||||
@@ -1745,6 +1723,7 @@ export const EventDetailsPage: React.FC = () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['admin-event', id] });
|
||||
}}
|
||||
onSelectionChange={setSelectedPhotoIds}
|
||||
categories={categories}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
@@ -277,7 +277,7 @@ export const EventTypesPage: React.FC = () => {
|
||||
{showCreateModal && (
|
||||
<EventTypeModal
|
||||
onClose={() => setShowCreateModal(false)}
|
||||
onSubmit={(data) => createMutation.mutate(data)}
|
||||
onSubmit={(data) => createMutation.mutate(data as CreateEventTypeData)}
|
||||
isLoading={createMutation.isPending}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -30,7 +30,7 @@ const mockCategories = [
|
||||
export const PreviewPage: React.FC = () => {
|
||||
const { setTheme } = useTheme();
|
||||
const [brandingSettings, setBrandingSettings] = useState<any>(null);
|
||||
const [selectedCategoryId, setSelectedCategoryId] = useState<number | null>(null);
|
||||
const [selectedCategoryId, setSelectedCategoryId] = useState<number | string | null>(null);
|
||||
const [searchTerm, setSearchTerm] = useState('');
|
||||
const [sortBy, setSortBy] = useState<'date' | 'name' | 'size' | 'rating'>('date');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user