Compare commits

...

6 Commits

Author SHA1 Message Date
Gitea Actions Bot f7e1d067f4 chore: bump frontend version to 1.0.90
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is failing
2025-07-24 10:05:36 +00:00
paul d8d7b500ad fix: auto-convert old date formats to new date-fns syntax
Mirror to GitHub / mirror (push) Successful in 51s
Test and Lint / backend-test (push) Successful in 1m42s
continuous-integration/drone/push Build is passing
Test and Lint / frontend-test (push) Successful in 2m8s
Version and Release / version-bump (push) Successful in 55s
Version and Release / trigger-drone (push) Successful in 3s
- Add convertDateFormat function to automatically fix DD->dd, YYYY->yyyy
- Handles existing database values with old format strings
- Prevents RangeError when using old formats stored in settings
- Ensures backward compatibility without requiring database updates

This fix converts formats on-the-fly so existing production data
with old formats like 'DD.MM.YYYY' will work correctly.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-24 11:59:20 +02:00
Gitea Actions Bot 250fb93021 chore: bump frontend version to 1.0.89
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is failing
2025-07-24 09:50:52 +00:00
paul c0bb2aa5d1 fix: resolve date formatting error in event creation
Mirror to GitHub / mirror (push) Successful in 38s
Test and Lint / backend-test (push) Successful in 1m31s
continuous-integration/drone/push Build is passing
Test and Lint / frontend-test (push) Successful in 2m3s
Version and Release / version-bump (push) Successful in 37s
Version and Release / trigger-drone (push) Successful in 3s
- Fix TypeError "e.match is not a function" when creating events
- Update useLocalizedDate hook to handle both string and object date formats
- Add type safety for date format configuration
- Fix date format strings to use correct date-fns format (lowercase)
- Ensure backward compatibility with existing date settings

The issue was caused by SettingsPage saving date formats as objects
while useLocalizedDate expected strings. This fix handles both formats
gracefully and prevents the error page redirect.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-24 11:45:47 +02:00
Gitea Actions Bot 8b0c1655a1 chore: bump frontend version to 1.0.88
continuous-integration/drone/push Build is failing
continuous-integration/drone/tag Build is failing
2025-07-23 10:10:42 +00:00
paul ff950244d5 fix: complete restore page translations and fix structure
Mirror to GitHub / mirror (push) Successful in 39s
Test and Lint / backend-test (push) Successful in 1m23s
Test and Lint / frontend-test (push) Successful in 2m0s
Version and Release / version-bump (push) Successful in 45s
Version and Release / trigger-drone (push) Successful in 3s
continuous-integration/drone/push Build is passing
- Fix restoreTypes translation structure (was under options.types)
- Add missing restore.messages.restoreStarted translation
- Ensure all restore wizard strings use translations
- Add corresponding German translations for restore section
- Fix translation key structure to match component expectations

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-23 12:05:48 +02:00
9 changed files with 74 additions and 34 deletions
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "picpeak-frontend",
"version": "1.0.87",
"version": "1.0.90",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "picpeak-frontend",
"version": "1.0.87",
"version": "1.0.90",
"dependencies": {
"@tanstack/react-query": "^5.0.0",
"@tiptap/extension-character-count": "^2.26.1",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "picpeak-frontend",
"private": true,
"version": "1.0.87",
"version": "1.0.90",
"type": "module",
"scripts": {
"dev": "vite",
@@ -187,8 +187,8 @@ export const RestoreWizard = () => {
const renderSourceSelection = () => (
<div className="space-y-6">
<div>
<h3 className="text-lg font-semibold text-gray-900 mb-2">Select Backup Source</h3>
<p className="text-sm text-gray-600">Choose where to restore the backup from</p>
<h3 className="text-lg font-semibold text-gray-900 mb-2">{t('backup.restore.source.title')}</h3>
<p className="text-sm text-gray-600">{t('backup.restore.source.subtitle')}</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
@@ -203,8 +203,8 @@ export const RestoreWizard = () => {
<HardDrive className={`h-12 w-12 mb-3 mx-auto ${
restoreData.source === 'local' ? 'text-primary' : 'text-gray-400'
}`} />
<h4 className="font-medium text-gray-900">Local Backup</h4>
<p className="text-xs text-gray-500 mt-1">Restore from local filesystem</p>
<h4 className="font-medium text-gray-900">{t('backup.restore.source.local.name')}</h4>
<p className="text-xs text-gray-500 mt-1">{t('backup.restore.source.local.description')}</p>
</button>
<button
@@ -218,8 +218,8 @@ export const RestoreWizard = () => {
<Cloud className={`h-12 w-12 mb-3 mx-auto ${
restoreData.source === 's3' ? 'text-primary' : 'text-gray-400'
}`} />
<h4 className="font-medium text-gray-900">S3 Storage</h4>
<p className="text-xs text-gray-500 mt-1">Restore from S3 bucket</p>
<h4 className="font-medium text-gray-900">{t('backup.restore.source.s3.name')}</h4>
<p className="text-xs text-gray-500 mt-1">{t('backup.restore.source.s3.description')}</p>
</button>
<button
@@ -233,8 +233,8 @@ export const RestoreWizard = () => {
<Upload className={`h-12 w-12 mb-3 mx-auto ${
restoreData.source === 'upload' ? 'text-primary' : 'text-gray-400'
}`} />
<h4 className="font-medium text-gray-900">Upload Backup</h4>
<p className="text-xs text-gray-500 mt-1">Upload a backup file</p>
<h4 className="font-medium text-gray-900">{t('backup.restore.source.upload.name')}</h4>
<p className="text-xs text-gray-500 mt-1">{t('backup.restore.source.upload.description')}</p>
</button>
</div>
+27 -2
View File
@@ -4,6 +4,14 @@ import { de, enUS } from 'date-fns/locale';
import { useQuery } from '@tanstack/react-query';
import { publicSettingsService } from '../services/publicSettings.service';
// Convert old date format strings to new date-fns format
const convertDateFormat = (format: string): string => {
return format
.replace(/DD/g, 'dd') // Days: DD -> dd
.replace(/YYYY/g, 'yyyy') // Years: YYYY -> yyyy
.replace(/YY/g, 'yy'); // Short years: YY -> yy
};
export const useLocalizedDate = () => {
const { i18n } = useTranslation();
@@ -22,7 +30,18 @@ export const useLocalizedDate = () => {
const format = (date: Date | string, formatStr?: string) => {
const dateObj = typeof date === 'string' ? new Date(date) : date;
// Use admin-configured date format if available and no format string provided
const dateFormat = formatStr || settings?.general_date_format || 'PPP';
let dateFormat = formatStr;
if (!dateFormat && settings?.general_date_format) {
// Handle both string and object formats
dateFormat = typeof settings.general_date_format === 'string'
? settings.general_date_format
: settings.general_date_format.format || 'PPP';
}
dateFormat = dateFormat || 'PPP';
// Convert old format to new format
dateFormat = convertDateFormat(dateFormat);
return dateFnsFormat(dateObj, dateFormat, { locale: getLocale() });
};
@@ -35,6 +54,12 @@ export const useLocalizedDate = () => {
format,
formatDistanceToNow,
locale: getLocale(),
dateFormat: settings?.general_date_format || 'PPP'
dateFormat: settings?.general_date_format
? convertDateFormat(
typeof settings.general_date_format === 'string'
? settings.general_date_format
: settings.general_date_format.format || 'PPP'
)
: 'PPP'
};
};
+8 -5
View File
@@ -1198,10 +1198,7 @@
"enterPassphrase": "Verschlüsselungs-Passphrase eingeben",
"at": "um"
},
"options": {
"title": "Wiederherstellungsoptionen",
"subtitle": "Wählen Sie, was wiederhergestellt werden soll",
"types": {
"restoreTypes": {
"full": {
"name": "Vollständige Wiederherstellung",
"description": "Alles wiederherstellen, einschließlich Datenbank, Fotos und Archive",
@@ -1222,7 +1219,10 @@
"description": "Bestimmte Elemente zur Wiederherstellung auswählen",
"warning": "Nur ausgewählte Elemente werden wiederhergestellt"
}
},
},
"options": {
"title": "Wiederherstellungsoptionen",
"subtitle": "Wählen Sie, was wiederhergestellt werden soll",
"additionalOptions": {
"title": "Zusätzliche Optionen",
"skipPreBackup": "Vor-Wiederherstellungs-Backup überspringen",
@@ -1285,6 +1285,9 @@
"starting": "Starte...",
"validating": "Validiere...",
"startNewRestore": "Neue Wiederherstellung starten"
},
"messages": {
"restoreStarted": "Wiederherstellung erfolgreich gestartet"
}
},
"messages": {
+8 -5
View File
@@ -1254,10 +1254,7 @@
"enterPassphrase": "Enter encryption passphrase",
"at": "at"
},
"options": {
"title": "Restore Options",
"subtitle": "Choose what to restore",
"types": {
"restoreTypes": {
"full": {
"name": "Full Restore",
"description": "Restore everything including database, photos, and archives",
@@ -1278,7 +1275,10 @@
"description": "Choose specific items to restore",
"warning": "Only selected items will be restored"
}
},
},
"options": {
"title": "Restore Options",
"subtitle": "Choose what to restore",
"additionalOptions": {
"title": "Additional Options",
"skipPreBackup": "Skip Pre-Restore Backup",
@@ -1341,6 +1341,9 @@
"starting": "Starting...",
"validating": "Validating...",
"startNewRestore": "Start New Restore"
},
"messages": {
"restoreStarted": "Restore started successfully"
}
},
"messages": {
@@ -84,7 +84,7 @@ export const CreateEventPageEnhanced: React.FC = () => {
const [formData, setFormData] = useState<FormData>({
event_type: 'wedding',
event_name: '',
event_date: format(new Date(), 'yyyy-MM-dd'),
event_date: new Date().toISOString().split('T')[0], // Initialize with ISO date format
host_name: '',
host_email: '',
admin_email: '',
+18 -9
View File
@@ -57,7 +57,7 @@ export const SettingsPage: React.FC = () => {
enable_registration: false,
maintenance_mode: false,
default_language: 'en',
date_format: { format: 'DD/MM/YYYY', locale: 'en-GB' }
date_format: { format: 'dd/MM/yyyy', locale: 'en-GB' }
});
// Security settings state
@@ -99,7 +99,11 @@ export const SettingsPage: React.FC = () => {
enable_registration: settings.general_enable_registration || false,
maintenance_mode: settings.general_maintenance_mode || false,
default_language: settings.general_default_language || 'en',
date_format: settings.general_date_format || { format: 'DD/MM/YYYY', locale: 'en-GB' }
date_format: settings.general_date_format
? (typeof settings.general_date_format === 'string'
? { format: settings.general_date_format, locale: settings.general_date_format.includes('MM/dd') ? 'en-US' : 'en-GB' }
: settings.general_date_format)
: { format: 'dd/MM/yyyy', locale: 'en-GB' }
});
// Extract security settings
@@ -130,7 +134,12 @@ export const SettingsPage: React.FC = () => {
// Convert to the format expected by the API
const settingsData: Record<string, any> = {};
Object.entries(generalSettings).forEach(([key, value]) => {
settingsData[`general_${key}`] = value;
// Special handling for date_format - only send the format string
if (key === 'date_format' && typeof value === 'object' && value.format) {
settingsData[`general_${key}`] = value.format;
} else {
settingsData[`general_${key}`] = value;
}
});
return settingsService.updateSettings(settingsData);
},
@@ -395,10 +404,10 @@ export const SettingsPage: React.FC = () => {
{t('settings.general.dateFormat')}
</label>
<select
value={generalSettings.date_format?.format || 'DD/MM/YYYY'}
value={generalSettings.date_format?.format || 'dd/MM/yyyy'}
onChange={(e) => {
const format = e.target.value;
const locale = format === 'MM/DD/YYYY' ? 'en-US' : 'en-GB';
const locale = format === 'MM/dd/yyyy' ? 'en-US' : 'en-GB';
setGeneralSettings(prev => ({
...prev,
date_format: { format, locale }
@@ -406,10 +415,10 @@ export const SettingsPage: React.FC = () => {
}}
className="w-full px-3 py-2 border border-neutral-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
>
<option value="DD/MM/YYYY">DD/MM/YYYY (European)</option>
<option value="MM/DD/YYYY">MM/DD/YYYY (US)</option>
<option value="YYYY-MM-DD">YYYY-MM-DD (ISO)</option>
<option value="DD.MM.YYYY">DD.MM.YYYY (German)</option>
<option value="dd/MM/yyyy">DD/MM/YYYY (European)</option>
<option value="MM/dd/yyyy">MM/DD/YYYY (US)</option>
<option value="yyyy-MM-dd">YYYY-MM-DD (ISO)</option>
<option value="dd.MM.yyyy">DD.MM.YYYY (German)</option>
</select>
<p className="text-xs text-neutral-500 mt-1">
{t('settings.general.dateFormatHelp')}
@@ -15,7 +15,7 @@ export interface PublicSettings {
theme_config: any;
default_language: string;
enable_analytics: boolean;
general_date_format: string;
general_date_format: string | { format: string; locale: string };
enable_recaptcha: boolean;
recaptcha_site_key: string | null;
maintenance_mode: boolean;