refactor: rename project from wedding-photo-sharing to PicPeak
- Update Docker image names and network configurations - Rename package.json project names to picpeak-backend/frontend - Update CI/CD configurations (Drone CI and GitHub Actions) - Update documentation and setup scripts - Update application branding in source code - Change default database name to picpeak - Update PM2 ecosystem config 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
This commit is contained in:
@@ -15,16 +15,14 @@ import {
|
||||
CheckCircle,
|
||||
Upload,
|
||||
Image,
|
||||
Key,
|
||||
Palette,
|
||||
Settings
|
||||
Key
|
||||
} from 'lucide-react';
|
||||
import { parseISO, differenceInDays } from 'date-fns';
|
||||
import { toast } from 'react-toastify';
|
||||
import { useLocalizedDate } from '../../hooks/useLocalizedDate';
|
||||
|
||||
import { Button, Input, Card, Loading } from '../../components/common';
|
||||
import { PhotoUpload, EventCategoryManager, AdminPhotoGrid, AdminPhotoViewer, PhotoFilters, PasswordResetModal, ThemeDisplay, ThemeCustomizerEnhanced, ThemeEditorModal, HeroPhotoSelector, PhotoUploadModal } from '../../components/admin';
|
||||
import { EventCategoryManager, AdminPhotoGrid, AdminPhotoViewer, PhotoFilters, PasswordResetModal, ThemeCustomizerEnhanced, ThemeDisplay, HeroPhotoSelector, PhotoUploadModal } from '../../components/admin';
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { eventsService } from '../../services/events.service';
|
||||
import { archiveService } from '../../services/archive.service';
|
||||
@@ -60,10 +58,8 @@ export const EventDetailsPage: React.FC = () => {
|
||||
const [activeTab, setActiveTab] = useState<'overview' | 'photos' | 'categories'>('overview');
|
||||
const [selectedPhoto, setSelectedPhoto] = useState<{ photo: AdminPhoto; index: number } | null>(null);
|
||||
const [showPasswordReset, setShowPasswordReset] = useState(false);
|
||||
const [showThemeCustomizer, setShowThemeCustomizer] = useState(false);
|
||||
const [currentTheme, setCurrentTheme] = useState<ThemeConfig | null>(null);
|
||||
const [currentPresetName, setCurrentPresetName] = useState<string>('default');
|
||||
const [showThemeEditorModal, setShowThemeEditorModal] = useState(false);
|
||||
|
||||
// Photo filters state
|
||||
const [photoFilters, setPhotoFilters] = useState({
|
||||
@@ -203,7 +199,7 @@ export const EventDetailsPage: React.FC = () => {
|
||||
const handleSaveEdit = () => {
|
||||
// Prepare color_theme - if we have a custom theme, serialize it
|
||||
let themeToSave = editForm.color_theme;
|
||||
if (currentTheme && (currentPresetName === 'custom' || showThemeCustomizer)) {
|
||||
if (currentTheme && currentPresetName === 'custom') {
|
||||
themeToSave = JSON.stringify(currentTheme);
|
||||
} else if (currentPresetName && currentPresetName !== 'custom') {
|
||||
// Use preset name for non-custom themes
|
||||
@@ -256,34 +252,6 @@ export const EventDetailsPage: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleThemeModalSave = async (theme: ThemeConfig, presetName: string) => {
|
||||
// Prepare theme for saving
|
||||
let themeToSave: string;
|
||||
if (presetName !== 'custom' && GALLERY_THEME_PRESETS[presetName]) {
|
||||
// Save preset name for standard presets
|
||||
themeToSave = presetName;
|
||||
} else {
|
||||
// Save full theme config for custom themes
|
||||
themeToSave = JSON.stringify(theme);
|
||||
}
|
||||
|
||||
try {
|
||||
// Update the event with new theme
|
||||
await eventsService.updateEvent(parseInt(id!), {
|
||||
color_theme: themeToSave
|
||||
});
|
||||
|
||||
// Invalidate queries to refresh the data
|
||||
await queryClient.invalidateQueries({ queryKey: ['admin-event', id] });
|
||||
|
||||
// Close modal and show success
|
||||
setShowThemeEditorModal(false);
|
||||
toast.success(t('toast.themeUpdated'));
|
||||
} catch (error) {
|
||||
console.error('Failed to save theme:', error);
|
||||
toast.error(t('toast.saveError'));
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -492,73 +460,6 @@ export const EventDetailsPage: React.FC = () => {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-neutral-700 mb-1">
|
||||
{t('events.galleryTheme')}
|
||||
</label>
|
||||
{!showThemeCustomizer ? (
|
||||
<div className="space-y-2">
|
||||
<select
|
||||
value={currentPresetName}
|
||||
onChange={(e) => {
|
||||
const presetName = e.target.value;
|
||||
setCurrentPresetName(presetName);
|
||||
if (presetName !== 'custom') {
|
||||
const preset = GALLERY_THEME_PRESETS[presetName];
|
||||
if (preset) {
|
||||
setCurrentTheme(preset.config);
|
||||
setEditForm(prev => ({ ...prev, color_theme: presetName }));
|
||||
}
|
||||
}
|
||||
}}
|
||||
className="w-full px-3 py-2 border border-neutral-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
|
||||
>
|
||||
{Object.entries(GALLERY_THEME_PRESETS).map(([key, preset]) => (
|
||||
<option key={key} value={key}>
|
||||
{preset.name}
|
||||
</option>
|
||||
))}
|
||||
<option value="custom">{t('branding.customTheme')}</option>
|
||||
</select>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
leftIcon={<Settings className="w-4 h-4" />}
|
||||
onClick={() => setShowThemeCustomizer(true)}
|
||||
className="w-full"
|
||||
>
|
||||
{t('branding.customizeTheme')}
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm text-neutral-600">{t('branding.customizingTheme')}</span>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => setShowThemeCustomizer(false)}
|
||||
>
|
||||
{t('common.hide')}
|
||||
</Button>
|
||||
</div>
|
||||
<ThemeCustomizerEnhanced
|
||||
value={currentTheme || GALLERY_THEME_PRESETS.default.config}
|
||||
onChange={setCurrentTheme}
|
||||
presetName={currentPresetName}
|
||||
onPresetChange={(presetName) => {
|
||||
setCurrentPresetName(presetName);
|
||||
if (presetName !== 'custom') {
|
||||
setEditForm(prev => ({ ...prev, color_theme: presetName }));
|
||||
}
|
||||
}}
|
||||
isPreviewMode={false}
|
||||
showGalleryLayouts={true}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Hero Photo Selection */}
|
||||
<HeroPhotoSelector
|
||||
photos={photos || []}
|
||||
@@ -822,28 +723,44 @@ export const EventDetailsPage: React.FC = () => {
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{/* Gallery Theme */}
|
||||
<Card padding="md">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<h2 className="text-lg font-semibold text-neutral-900">{t('events.galleryTheme')}</h2>
|
||||
{!event.is_archived && (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
leftIcon={<Palette className="w-4 h-4" />}
|
||||
onClick={() => setShowThemeEditorModal(true)}
|
||||
>
|
||||
{t('events.customizeTheme')}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<ThemeDisplay
|
||||
theme={event.color_theme || GALLERY_THEME_PRESETS.default.config}
|
||||
presetName={event.color_theme && !event.color_theme.startsWith('{') ? event.color_theme : undefined}
|
||||
showDetails={true}
|
||||
/>
|
||||
</Card>
|
||||
{/* Theme & Style */}
|
||||
{isEditing && !event.is_archived && (
|
||||
<Card padding="md">
|
||||
<h2 className="text-lg font-semibold text-neutral-900 mb-4">{t('branding.themeAndStyle')}</h2>
|
||||
<ThemeCustomizerEnhanced
|
||||
value={currentTheme || GALLERY_THEME_PRESETS.default.config}
|
||||
onChange={(theme) => {
|
||||
setCurrentTheme(theme);
|
||||
setEditForm(prev => ({ ...prev, color_theme: JSON.stringify(theme) }));
|
||||
}}
|
||||
presetName={currentPresetName}
|
||||
onPresetChange={(presetName) => {
|
||||
setCurrentPresetName(presetName);
|
||||
if (presetName !== 'custom') {
|
||||
const preset = GALLERY_THEME_PRESETS[presetName];
|
||||
if (preset) {
|
||||
setCurrentTheme(preset.config);
|
||||
setEditForm(prev => ({ ...prev, color_theme: presetName }));
|
||||
}
|
||||
}
|
||||
}}
|
||||
isPreviewMode={false}
|
||||
showGalleryLayouts={true}
|
||||
/>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{/* Theme Display (when not editing) */}
|
||||
{!isEditing && !event.is_archived && (
|
||||
<Card padding="md">
|
||||
<h2 className="text-lg font-semibold text-neutral-900 mb-4">{t('events.galleryTheme')}</h2>
|
||||
<ThemeDisplay
|
||||
theme={event.color_theme || GALLERY_THEME_PRESETS.default.config}
|
||||
presetName={event.color_theme && !event.color_theme.startsWith('{') ? event.color_theme : undefined}
|
||||
showDetails={true}
|
||||
/>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{/* Archive Status */}
|
||||
{event.is_archived ? (
|
||||
@@ -995,16 +912,6 @@ export const EventDetailsPage: React.FC = () => {
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Theme Editor Modal */}
|
||||
{showThemeEditorModal && (
|
||||
<ThemeEditorModal
|
||||
isOpen={showThemeEditorModal}
|
||||
onClose={() => setShowThemeEditorModal(false)}
|
||||
onSave={handleThemeModalSave}
|
||||
currentTheme={event.color_theme || 'default'}
|
||||
eventName={event.event_name}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user