mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-22 14:51:45 +00:00
fix(journey): remove photo upload count limit and surface upload errors (#997)
Removes the arbitrary 10-file cap on journey entry photo uploads and 20-file cap on gallery uploads. MulterErrors now return proper 4xx responses instead of 500, and the client surfaces the server error message via toast rather than silently trapping the user in the post editor overlay.
This commit is contained in:
@@ -1674,6 +1674,7 @@ const ar: Record<string, string | { name: string; category: string }[]> = {
|
|||||||
'journey.settings.failedToDelete': 'فشل في الحذف',
|
'journey.settings.failedToDelete': 'فشل في الحذف',
|
||||||
'journey.entries.deleteTitle': 'حذف الإدخال',
|
'journey.entries.deleteTitle': 'حذف الإدخال',
|
||||||
'journey.photosUploaded': 'تم رفع {count} صورة',
|
'journey.photosUploaded': 'تم رفع {count} صورة',
|
||||||
|
'journey.photosUploadFailed': 'فشل رفع بعض الصور',
|
||||||
'journey.photosAdded': 'تمت إضافة {count} صورة',
|
'journey.photosAdded': 'تمت إضافة {count} صورة',
|
||||||
'journey.picker.tripPeriod': 'فترة الرحلة',
|
'journey.picker.tripPeriod': 'فترة الرحلة',
|
||||||
'journey.picker.dateRange': 'نطاق التاريخ',
|
'journey.picker.dateRange': 'نطاق التاريخ',
|
||||||
@@ -1705,6 +1706,7 @@ const ar: Record<string, string | { name: string; category: string }[]> = {
|
|||||||
|
|
||||||
// Journey Entry Editor
|
// Journey Entry Editor
|
||||||
'journey.editor.discardChangesConfirm': 'لديك تغييرات غير محفوظة. هل تريد تجاهلها؟',
|
'journey.editor.discardChangesConfirm': 'لديك تغييرات غير محفوظة. هل تريد تجاهلها؟',
|
||||||
|
'journey.editor.uploadFailed': 'فشل رفع الصور',
|
||||||
'journey.editor.uploadPhotos': 'رفع صور',
|
'journey.editor.uploadPhotos': 'رفع صور',
|
||||||
'journey.editor.uploading': '...جارٍ الرفع',
|
'journey.editor.uploading': '...جارٍ الرفع',
|
||||||
'journey.editor.fromGallery': 'من المعرض',
|
'journey.editor.fromGallery': 'من المعرض',
|
||||||
|
|||||||
@@ -2077,6 +2077,7 @@ const br: Record<string, string | { name: string; category: string }[]> = {
|
|||||||
'journey.synced.places': 'lugares',
|
'journey.synced.places': 'lugares',
|
||||||
'journey.synced.synced': 'sincronizado',
|
'journey.synced.synced': 'sincronizado',
|
||||||
'journey.editor.discardChangesConfirm': 'Você tem alterações não salvas. Descartá-las?',
|
'journey.editor.discardChangesConfirm': 'Você tem alterações não salvas. Descartá-las?',
|
||||||
|
'journey.editor.uploadFailed': 'Falha ao enviar fotos',
|
||||||
'journey.editor.uploadPhotos': 'Enviar fotos',
|
'journey.editor.uploadPhotos': 'Enviar fotos',
|
||||||
'journey.editor.uploading': 'Enviando...',
|
'journey.editor.uploading': 'Enviando...',
|
||||||
'journey.editor.fromGallery': 'Da galeria',
|
'journey.editor.fromGallery': 'Da galeria',
|
||||||
@@ -2169,6 +2170,7 @@ const br: Record<string, string | { name: string; category: string }[]> = {
|
|||||||
'journey.settings.failedToDelete': 'Falha ao excluir',
|
'journey.settings.failedToDelete': 'Falha ao excluir',
|
||||||
'journey.entries.deleteTitle': 'Excluir entrada',
|
'journey.entries.deleteTitle': 'Excluir entrada',
|
||||||
'journey.photosUploaded': '{count} fotos enviadas',
|
'journey.photosUploaded': '{count} fotos enviadas',
|
||||||
|
'journey.photosUploadFailed': 'Algumas fotos não foram enviadas',
|
||||||
'journey.photosAdded': '{count} fotos adicionadas',
|
'journey.photosAdded': '{count} fotos adicionadas',
|
||||||
'journey.public.notFound': 'Não encontrado',
|
'journey.public.notFound': 'Não encontrado',
|
||||||
'journey.public.notFoundMessage': 'Esta jornada não existe ou o link expirou.',
|
'journey.public.notFoundMessage': 'Esta jornada não existe ou o link expirou.',
|
||||||
|
|||||||
@@ -2082,6 +2082,7 @@ const cs: Record<string, string | { name: string; category: string }[]> = {
|
|||||||
'journey.synced.places': 'místa',
|
'journey.synced.places': 'místa',
|
||||||
'journey.synced.synced': 'synchronizováno',
|
'journey.synced.synced': 'synchronizováno',
|
||||||
'journey.editor.discardChangesConfirm': 'Máte neuložené změny. Zahodit?',
|
'journey.editor.discardChangesConfirm': 'Máte neuložené změny. Zahodit?',
|
||||||
|
'journey.editor.uploadFailed': 'Nahrávání fotek selhalo',
|
||||||
'journey.editor.uploadPhotos': 'Nahrát fotky',
|
'journey.editor.uploadPhotos': 'Nahrát fotky',
|
||||||
'journey.editor.uploading': 'Nahrávání...',
|
'journey.editor.uploading': 'Nahrávání...',
|
||||||
'journey.editor.fromGallery': 'Z galerie',
|
'journey.editor.fromGallery': 'Z galerie',
|
||||||
@@ -2174,6 +2175,7 @@ const cs: Record<string, string | { name: string; category: string }[]> = {
|
|||||||
'journey.settings.failedToDelete': 'Smazání se nezdařilo',
|
'journey.settings.failedToDelete': 'Smazání se nezdařilo',
|
||||||
'journey.entries.deleteTitle': 'Smazat záznam',
|
'journey.entries.deleteTitle': 'Smazat záznam',
|
||||||
'journey.photosUploaded': '{count} fotografií nahráno',
|
'journey.photosUploaded': '{count} fotografií nahráno',
|
||||||
|
'journey.photosUploadFailed': 'Některé fotky se nepodařilo nahrát',
|
||||||
'journey.photosAdded': '{count} fotografií přidáno',
|
'journey.photosAdded': '{count} fotografií přidáno',
|
||||||
'journey.public.notFound': 'Nenalezeno',
|
'journey.public.notFound': 'Nenalezeno',
|
||||||
'journey.public.notFoundMessage': 'Tento cestovní deník neexistuje nebo odkaz vypršel.',
|
'journey.public.notFoundMessage': 'Tento cestovní deník neexistuje nebo odkaz vypršel.',
|
||||||
|
|||||||
@@ -2085,6 +2085,7 @@ const de: Record<string, string | { name: string; category: string }[]> = {
|
|||||||
'journey.synced.places': 'Orte',
|
'journey.synced.places': 'Orte',
|
||||||
'journey.synced.synced': 'synchronisiert',
|
'journey.synced.synced': 'synchronisiert',
|
||||||
'journey.editor.discardChangesConfirm': 'Du hast ungespeicherte Änderungen. Verwerfen?',
|
'journey.editor.discardChangesConfirm': 'Du hast ungespeicherte Änderungen. Verwerfen?',
|
||||||
|
'journey.editor.uploadFailed': 'Foto-Upload fehlgeschlagen',
|
||||||
'journey.editor.uploadPhotos': 'Fotos hochladen',
|
'journey.editor.uploadPhotos': 'Fotos hochladen',
|
||||||
'journey.editor.uploading': 'Hochladen...',
|
'journey.editor.uploading': 'Hochladen...',
|
||||||
'journey.editor.fromGallery': 'Aus Galerie',
|
'journey.editor.fromGallery': 'Aus Galerie',
|
||||||
@@ -2181,6 +2182,7 @@ const de: Record<string, string | { name: string; category: string }[]> = {
|
|||||||
'journey.settings.failedToDelete': 'Löschen fehlgeschlagen',
|
'journey.settings.failedToDelete': 'Löschen fehlgeschlagen',
|
||||||
'journey.entries.deleteTitle': 'Eintrag löschen',
|
'journey.entries.deleteTitle': 'Eintrag löschen',
|
||||||
'journey.photosUploaded': '{count} Fotos hochgeladen',
|
'journey.photosUploaded': '{count} Fotos hochgeladen',
|
||||||
|
'journey.photosUploadFailed': 'Einige Fotos konnten nicht hochgeladen werden',
|
||||||
'journey.photosAdded': '{count} Fotos hinzugefügt',
|
'journey.photosAdded': '{count} Fotos hinzugefügt',
|
||||||
'journey.public.notFound': 'Nicht gefunden',
|
'journey.public.notFound': 'Nicht gefunden',
|
||||||
'journey.public.notFoundMessage': 'Diese Journey existiert nicht oder der Link ist abgelaufen.',
|
'journey.public.notFoundMessage': 'Diese Journey existiert nicht oder der Link ist abgelaufen.',
|
||||||
|
|||||||
@@ -2111,6 +2111,7 @@ const en: Record<string, string | { name: string; category: string }[]> = {
|
|||||||
|
|
||||||
// Journey Entry Editor
|
// Journey Entry Editor
|
||||||
'journey.editor.discardChangesConfirm': 'You have unsaved changes. Discard them?',
|
'journey.editor.discardChangesConfirm': 'You have unsaved changes. Discard them?',
|
||||||
|
'journey.editor.uploadFailed': 'Photo upload failed',
|
||||||
'journey.editor.uploadPhotos': 'Upload photos',
|
'journey.editor.uploadPhotos': 'Upload photos',
|
||||||
'journey.editor.uploading': 'Uploading...',
|
'journey.editor.uploading': 'Uploading...',
|
||||||
'journey.editor.fromGallery': 'From Gallery',
|
'journey.editor.fromGallery': 'From Gallery',
|
||||||
@@ -2219,6 +2220,7 @@ const en: Record<string, string | { name: string; category: string }[]> = {
|
|||||||
'journey.settings.failedToDelete': 'Failed to delete',
|
'journey.settings.failedToDelete': 'Failed to delete',
|
||||||
'journey.entries.deleteTitle': 'Delete Entry',
|
'journey.entries.deleteTitle': 'Delete Entry',
|
||||||
'journey.photosUploaded': '{count} photos uploaded',
|
'journey.photosUploaded': '{count} photos uploaded',
|
||||||
|
'journey.photosUploadFailed': 'Some photos failed to upload',
|
||||||
'journey.photosAdded': '{count} photos added',
|
'journey.photosAdded': '{count} photos added',
|
||||||
|
|
||||||
// Journey — Public Page
|
// Journey — Public Page
|
||||||
|
|||||||
@@ -2084,6 +2084,7 @@ const es: Record<string, string> = {
|
|||||||
'journey.synced.places': 'lugares',
|
'journey.synced.places': 'lugares',
|
||||||
'journey.synced.synced': 'sincronizado',
|
'journey.synced.synced': 'sincronizado',
|
||||||
'journey.editor.discardChangesConfirm': 'Tienes cambios sin guardar. ¿Descartarlos?',
|
'journey.editor.discardChangesConfirm': 'Tienes cambios sin guardar. ¿Descartarlos?',
|
||||||
|
'journey.editor.uploadFailed': 'Error al subir fotos',
|
||||||
'journey.editor.uploadPhotos': 'Subir fotos',
|
'journey.editor.uploadPhotos': 'Subir fotos',
|
||||||
'journey.editor.uploading': 'Subiendo...',
|
'journey.editor.uploading': 'Subiendo...',
|
||||||
'journey.editor.fromGallery': 'Desde galería',
|
'journey.editor.fromGallery': 'Desde galería',
|
||||||
@@ -2176,6 +2177,7 @@ const es: Record<string, string> = {
|
|||||||
'journey.settings.failedToDelete': 'Error al eliminar',
|
'journey.settings.failedToDelete': 'Error al eliminar',
|
||||||
'journey.entries.deleteTitle': 'Eliminar entrada',
|
'journey.entries.deleteTitle': 'Eliminar entrada',
|
||||||
'journey.photosUploaded': '{count} fotos subidas',
|
'journey.photosUploaded': '{count} fotos subidas',
|
||||||
|
'journey.photosUploadFailed': 'Algunas fotos no se pudieron subir',
|
||||||
'journey.photosAdded': '{count} fotos añadidas',
|
'journey.photosAdded': '{count} fotos añadidas',
|
||||||
'journey.public.notFound': 'No encontrado',
|
'journey.public.notFound': 'No encontrado',
|
||||||
'journey.public.notFoundMessage': 'Esta travesía no existe o el enlace ha expirado.',
|
'journey.public.notFoundMessage': 'Esta travesía no existe o el enlace ha expirado.',
|
||||||
|
|||||||
@@ -2078,6 +2078,7 @@ const fr: Record<string, string> = {
|
|||||||
'journey.synced.places': 'lieux',
|
'journey.synced.places': 'lieux',
|
||||||
'journey.synced.synced': 'synchronisé',
|
'journey.synced.synced': 'synchronisé',
|
||||||
'journey.editor.discardChangesConfirm': 'Vous avez des modifications non enregistrées. Les ignorer ?',
|
'journey.editor.discardChangesConfirm': 'Vous avez des modifications non enregistrées. Les ignorer ?',
|
||||||
|
'journey.editor.uploadFailed': 'Échec du téléversement des photos',
|
||||||
'journey.editor.uploadPhotos': 'Téléverser des photos',
|
'journey.editor.uploadPhotos': 'Téléverser des photos',
|
||||||
'journey.editor.uploading': 'Envoi...',
|
'journey.editor.uploading': 'Envoi...',
|
||||||
'journey.editor.fromGallery': 'Depuis la galerie',
|
'journey.editor.fromGallery': 'Depuis la galerie',
|
||||||
@@ -2170,6 +2171,7 @@ const fr: Record<string, string> = {
|
|||||||
'journey.settings.failedToDelete': 'Échec de la suppression',
|
'journey.settings.failedToDelete': 'Échec de la suppression',
|
||||||
'journey.entries.deleteTitle': "Supprimer l'entrée",
|
'journey.entries.deleteTitle': "Supprimer l'entrée",
|
||||||
'journey.photosUploaded': '{count} photos téléversées',
|
'journey.photosUploaded': '{count} photos téléversées',
|
||||||
|
'journey.photosUploadFailed': "Certaines photos n'ont pas pu être téléversées",
|
||||||
'journey.photosAdded': '{count} photos ajoutées',
|
'journey.photosAdded': '{count} photos ajoutées',
|
||||||
'journey.public.notFound': 'Introuvable',
|
'journey.public.notFound': 'Introuvable',
|
||||||
'journey.public.notFoundMessage': 'Ce journal n\'existe pas ou le lien a expiré.',
|
'journey.public.notFoundMessage': 'Ce journal n\'existe pas ou le lien a expiré.',
|
||||||
|
|||||||
@@ -2079,6 +2079,7 @@ const hu: Record<string, string | { name: string; category: string }[]> = {
|
|||||||
'journey.synced.places': 'helyszín',
|
'journey.synced.places': 'helyszín',
|
||||||
'journey.synced.synced': 'szinkronizálva',
|
'journey.synced.synced': 'szinkronizálva',
|
||||||
'journey.editor.discardChangesConfirm': 'Mentetlen módosításaid vannak. Elveted?',
|
'journey.editor.discardChangesConfirm': 'Mentetlen módosításaid vannak. Elveted?',
|
||||||
|
'journey.editor.uploadFailed': 'A fotók feltöltése sikertelen',
|
||||||
'journey.editor.uploadPhotos': 'Fotók feltöltése',
|
'journey.editor.uploadPhotos': 'Fotók feltöltése',
|
||||||
'journey.editor.uploading': 'Feltöltés...',
|
'journey.editor.uploading': 'Feltöltés...',
|
||||||
'journey.editor.fromGallery': 'Galériából',
|
'journey.editor.fromGallery': 'Galériából',
|
||||||
@@ -2171,6 +2172,7 @@ const hu: Record<string, string | { name: string; category: string }[]> = {
|
|||||||
'journey.settings.failedToDelete': 'Törlés sikertelen',
|
'journey.settings.failedToDelete': 'Törlés sikertelen',
|
||||||
'journey.entries.deleteTitle': 'Bejegyzés törlése',
|
'journey.entries.deleteTitle': 'Bejegyzés törlése',
|
||||||
'journey.photosUploaded': '{count} fotó feltöltve',
|
'journey.photosUploaded': '{count} fotó feltöltve',
|
||||||
|
'journey.photosUploadFailed': 'Néhány fotót nem sikerült feltölteni',
|
||||||
'journey.photosAdded': '{count} fotó hozzáadva',
|
'journey.photosAdded': '{count} fotó hozzáadva',
|
||||||
'journey.public.notFound': 'Nem található',
|
'journey.public.notFound': 'Nem található',
|
||||||
'journey.public.notFoundMessage': 'Ez az útinapló nem létezik vagy a link lejárt.',
|
'journey.public.notFoundMessage': 'Ez az útinapló nem létezik vagy a link lejárt.',
|
||||||
|
|||||||
@@ -2094,6 +2094,7 @@ const id: Record<string, string | { name: string; category: string }[]> = {
|
|||||||
|
|
||||||
// Journey Entry Editor
|
// Journey Entry Editor
|
||||||
'journey.editor.discardChangesConfirm': 'Anda memiliki perubahan yang belum disimpan. Buang?',
|
'journey.editor.discardChangesConfirm': 'Anda memiliki perubahan yang belum disimpan. Buang?',
|
||||||
|
'journey.editor.uploadFailed': 'Gagal mengunggah foto',
|
||||||
'journey.editor.uploadPhotos': 'Unggah foto',
|
'journey.editor.uploadPhotos': 'Unggah foto',
|
||||||
'journey.editor.uploading': 'Mengunggah...',
|
'journey.editor.uploading': 'Mengunggah...',
|
||||||
'journey.editor.fromGallery': 'Dari Galeri',
|
'journey.editor.fromGallery': 'Dari Galeri',
|
||||||
@@ -2198,6 +2199,7 @@ const id: Record<string, string | { name: string; category: string }[]> = {
|
|||||||
'journey.settings.failedToDelete': 'Gagal menghapus',
|
'journey.settings.failedToDelete': 'Gagal menghapus',
|
||||||
'journey.entries.deleteTitle': 'Hapus Entri',
|
'journey.entries.deleteTitle': 'Hapus Entri',
|
||||||
'journey.photosUploaded': '{count} foto diunggah',
|
'journey.photosUploaded': '{count} foto diunggah',
|
||||||
|
'journey.photosUploadFailed': 'Beberapa foto gagal diunggah',
|
||||||
'journey.photosAdded': '{count} foto ditambahkan',
|
'journey.photosAdded': '{count} foto ditambahkan',
|
||||||
|
|
||||||
// Journey — Public Page
|
// Journey — Public Page
|
||||||
|
|||||||
@@ -2079,6 +2079,7 @@ const it: Record<string, string | { name: string; category: string }[]> = {
|
|||||||
'journey.synced.places': 'luoghi',
|
'journey.synced.places': 'luoghi',
|
||||||
'journey.synced.synced': 'sincronizzato',
|
'journey.synced.synced': 'sincronizzato',
|
||||||
'journey.editor.discardChangesConfirm': 'Hai modifiche non salvate. Vuoi scartarle?',
|
'journey.editor.discardChangesConfirm': 'Hai modifiche non salvate. Vuoi scartarle?',
|
||||||
|
'journey.editor.uploadFailed': 'Caricamento foto non riuscito',
|
||||||
'journey.editor.uploadPhotos': 'Carica foto',
|
'journey.editor.uploadPhotos': 'Carica foto',
|
||||||
'journey.editor.uploading': 'Caricamento...',
|
'journey.editor.uploading': 'Caricamento...',
|
||||||
'journey.editor.fromGallery': 'Dalla galleria',
|
'journey.editor.fromGallery': 'Dalla galleria',
|
||||||
@@ -2171,6 +2172,7 @@ const it: Record<string, string | { name: string; category: string }[]> = {
|
|||||||
'journey.settings.failedToDelete': 'Eliminazione non riuscita',
|
'journey.settings.failedToDelete': 'Eliminazione non riuscita',
|
||||||
'journey.entries.deleteTitle': 'Elimina voce',
|
'journey.entries.deleteTitle': 'Elimina voce',
|
||||||
'journey.photosUploaded': '{count} foto caricate',
|
'journey.photosUploaded': '{count} foto caricate',
|
||||||
|
'journey.photosUploadFailed': 'Alcune foto non sono state caricate',
|
||||||
'journey.photosAdded': '{count} foto aggiunte',
|
'journey.photosAdded': '{count} foto aggiunte',
|
||||||
'journey.public.notFound': 'Non trovato',
|
'journey.public.notFound': 'Non trovato',
|
||||||
'journey.public.notFoundMessage': 'Questo diario non esiste o il link è scaduto.',
|
'journey.public.notFoundMessage': 'Questo diario non esiste o il link è scaduto.',
|
||||||
|
|||||||
@@ -2078,6 +2078,7 @@ const nl: Record<string, string> = {
|
|||||||
'journey.synced.places': 'plaatsen',
|
'journey.synced.places': 'plaatsen',
|
||||||
'journey.synced.synced': 'gesynchroniseerd',
|
'journey.synced.synced': 'gesynchroniseerd',
|
||||||
'journey.editor.discardChangesConfirm': 'Je hebt niet-opgeslagen wijzigingen. Verwerpen?',
|
'journey.editor.discardChangesConfirm': 'Je hebt niet-opgeslagen wijzigingen. Verwerpen?',
|
||||||
|
'journey.editor.uploadFailed': 'Foto uploaden mislukt',
|
||||||
'journey.editor.uploadPhotos': 'Foto\'s uploaden',
|
'journey.editor.uploadPhotos': 'Foto\'s uploaden',
|
||||||
'journey.editor.uploading': 'Uploaden...',
|
'journey.editor.uploading': 'Uploaden...',
|
||||||
'journey.editor.fromGallery': 'Uit galerij',
|
'journey.editor.fromGallery': 'Uit galerij',
|
||||||
@@ -2170,6 +2171,7 @@ const nl: Record<string, string> = {
|
|||||||
'journey.settings.failedToDelete': 'Verwijderen mislukt',
|
'journey.settings.failedToDelete': 'Verwijderen mislukt',
|
||||||
'journey.entries.deleteTitle': 'Vermelding verwijderen',
|
'journey.entries.deleteTitle': 'Vermelding verwijderen',
|
||||||
'journey.photosUploaded': "{count} foto's geüpload",
|
'journey.photosUploaded': "{count} foto's geüpload",
|
||||||
|
'journey.photosUploadFailed': "Sommige foto's konden niet worden geüpload",
|
||||||
'journey.photosAdded': "{count} foto's toegevoegd",
|
'journey.photosAdded': "{count} foto's toegevoegd",
|
||||||
'journey.public.notFound': 'Niet gevonden',
|
'journey.public.notFound': 'Niet gevonden',
|
||||||
'journey.public.notFoundMessage': 'Dit reisverslag bestaat niet of de link is verlopen.',
|
'journey.public.notFoundMessage': 'Dit reisverslag bestaat niet of de link is verlopen.',
|
||||||
|
|||||||
@@ -2071,6 +2071,7 @@ const pl: Record<string, string | { name: string; category: string }[]> = {
|
|||||||
'journey.synced.places': 'miejsca',
|
'journey.synced.places': 'miejsca',
|
||||||
'journey.synced.synced': 'zsynchronizowane',
|
'journey.synced.synced': 'zsynchronizowane',
|
||||||
'journey.editor.discardChangesConfirm': 'Masz niezapisane zmiany. Odrzucić?',
|
'journey.editor.discardChangesConfirm': 'Masz niezapisane zmiany. Odrzucić?',
|
||||||
|
'journey.editor.uploadFailed': 'Przesyłanie zdjęć nie powiodło się',
|
||||||
'journey.editor.uploadPhotos': 'Prześlij zdjęcia',
|
'journey.editor.uploadPhotos': 'Prześlij zdjęcia',
|
||||||
'journey.editor.uploading': 'Przesyłanie...',
|
'journey.editor.uploading': 'Przesyłanie...',
|
||||||
'journey.editor.fromGallery': 'Z galerii',
|
'journey.editor.fromGallery': 'Z galerii',
|
||||||
@@ -2163,6 +2164,7 @@ const pl: Record<string, string | { name: string; category: string }[]> = {
|
|||||||
'journey.settings.failedToDelete': 'Nie udało się usunąć',
|
'journey.settings.failedToDelete': 'Nie udało się usunąć',
|
||||||
'journey.entries.deleteTitle': 'Usuń wpis',
|
'journey.entries.deleteTitle': 'Usuń wpis',
|
||||||
'journey.photosUploaded': '{count} zdjęć przesłanych',
|
'journey.photosUploaded': '{count} zdjęć przesłanych',
|
||||||
|
'journey.photosUploadFailed': 'Nie udało się przesłać niektórych zdjęć',
|
||||||
'journey.photosAdded': '{count} zdjęć dodanych',
|
'journey.photosAdded': '{count} zdjęć dodanych',
|
||||||
'journey.public.notFound': 'Nie znaleziono',
|
'journey.public.notFound': 'Nie znaleziono',
|
||||||
'journey.public.notFoundMessage': 'Ten dziennik podróży nie istnieje lub link wygasł.',
|
'journey.public.notFoundMessage': 'Ten dziennik podróży nie istnieje lub link wygasł.',
|
||||||
|
|||||||
@@ -2078,6 +2078,7 @@ const ru: Record<string, string> = {
|
|||||||
'journey.synced.places': 'мест',
|
'journey.synced.places': 'мест',
|
||||||
'journey.synced.synced': 'синхронизировано',
|
'journey.synced.synced': 'синхронизировано',
|
||||||
'journey.editor.discardChangesConfirm': 'У вас есть несохранённые изменения. Отменить?',
|
'journey.editor.discardChangesConfirm': 'У вас есть несохранённые изменения. Отменить?',
|
||||||
|
'journey.editor.uploadFailed': 'Не удалось загрузить фото',
|
||||||
'journey.editor.uploadPhotos': 'Загрузить фото',
|
'journey.editor.uploadPhotos': 'Загрузить фото',
|
||||||
'journey.editor.uploading': 'Загрузка...',
|
'journey.editor.uploading': 'Загрузка...',
|
||||||
'journey.editor.fromGallery': 'Из галереи',
|
'journey.editor.fromGallery': 'Из галереи',
|
||||||
@@ -2170,6 +2171,7 @@ const ru: Record<string, string> = {
|
|||||||
'journey.settings.failedToDelete': 'Не удалось удалить',
|
'journey.settings.failedToDelete': 'Не удалось удалить',
|
||||||
'journey.entries.deleteTitle': 'Удалить запись',
|
'journey.entries.deleteTitle': 'Удалить запись',
|
||||||
'journey.photosUploaded': '{count} фото загружено',
|
'journey.photosUploaded': '{count} фото загружено',
|
||||||
|
'journey.photosUploadFailed': 'Некоторые фото не удалось загрузить',
|
||||||
'journey.photosAdded': '{count} фото добавлено',
|
'journey.photosAdded': '{count} фото добавлено',
|
||||||
'journey.public.notFound': 'Не найдено',
|
'journey.public.notFound': 'Не найдено',
|
||||||
'journey.public.notFoundMessage': 'Это путешествие не существует или ссылка устарела.',
|
'journey.public.notFoundMessage': 'Это путешествие не существует или ссылка устарела.',
|
||||||
|
|||||||
@@ -2078,6 +2078,7 @@ const zh: Record<string, string> = {
|
|||||||
'journey.synced.places': '个地点',
|
'journey.synced.places': '个地点',
|
||||||
'journey.synced.synced': '已同步',
|
'journey.synced.synced': '已同步',
|
||||||
'journey.editor.discardChangesConfirm': '您有未保存的更改。要放弃吗?',
|
'journey.editor.discardChangesConfirm': '您有未保存的更改。要放弃吗?',
|
||||||
|
'journey.editor.uploadFailed': '照片上传失败',
|
||||||
'journey.editor.uploadPhotos': '上传照片',
|
'journey.editor.uploadPhotos': '上传照片',
|
||||||
'journey.editor.uploading': '上传中...',
|
'journey.editor.uploading': '上传中...',
|
||||||
'journey.editor.fromGallery': '从相册',
|
'journey.editor.fromGallery': '从相册',
|
||||||
@@ -2170,6 +2171,7 @@ const zh: Record<string, string> = {
|
|||||||
'journey.settings.failedToDelete': '删除失败',
|
'journey.settings.failedToDelete': '删除失败',
|
||||||
'journey.entries.deleteTitle': '删除条目',
|
'journey.entries.deleteTitle': '删除条目',
|
||||||
'journey.photosUploaded': '{count} 张照片已上传',
|
'journey.photosUploaded': '{count} 张照片已上传',
|
||||||
|
'journey.photosUploadFailed': '部分照片上传失败',
|
||||||
'journey.photosAdded': '{count} 张照片已添加',
|
'journey.photosAdded': '{count} 张照片已添加',
|
||||||
'journey.public.notFound': '未找到',
|
'journey.public.notFound': '未找到',
|
||||||
'journey.public.notFoundMessage': '此旅程不存在或链接已过期。',
|
'journey.public.notFoundMessage': '此旅程不存在或链接已过期。',
|
||||||
|
|||||||
@@ -2036,6 +2036,7 @@ const zhTw: Record<string, string> = {
|
|||||||
'journey.synced.places': '個地點',
|
'journey.synced.places': '個地點',
|
||||||
'journey.synced.synced': '已同步',
|
'journey.synced.synced': '已同步',
|
||||||
'journey.editor.discardChangesConfirm': '您有未儲存的變更。要放棄嗎?',
|
'journey.editor.discardChangesConfirm': '您有未儲存的變更。要放棄嗎?',
|
||||||
|
'journey.editor.uploadFailed': '照片上傳失敗',
|
||||||
'journey.editor.uploadPhotos': '上傳照片',
|
'journey.editor.uploadPhotos': '上傳照片',
|
||||||
'journey.editor.uploading': '上傳中...',
|
'journey.editor.uploading': '上傳中...',
|
||||||
'journey.editor.fromGallery': '從相簿',
|
'journey.editor.fromGallery': '從相簿',
|
||||||
@@ -2128,6 +2129,7 @@ const zhTw: Record<string, string> = {
|
|||||||
'journey.settings.failedToDelete': '刪除失敗',
|
'journey.settings.failedToDelete': '刪除失敗',
|
||||||
'journey.entries.deleteTitle': '刪除條目',
|
'journey.entries.deleteTitle': '刪除條目',
|
||||||
'journey.photosUploaded': '{count} 張照片已上傳',
|
'journey.photosUploaded': '{count} 張照片已上傳',
|
||||||
|
'journey.photosUploadFailed': '部分照片上傳失敗',
|
||||||
'journey.photosAdded': '{count} 張照片已新增',
|
'journey.photosAdded': '{count} 張照片已新增',
|
||||||
'journey.public.notFound': '未找到',
|
'journey.public.notFound': '未找到',
|
||||||
'journey.public.notFoundMessage': '此旅程不存在或連結已過期。',
|
'journey.public.notFoundMessage': '此旅程不存在或連結已過期。',
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import MobileEntryView from '../components/Journey/MobileEntryView'
|
|||||||
import { useIsMobile } from '../hooks/useIsMobile'
|
import { useIsMobile } from '../hooks/useIsMobile'
|
||||||
import type { JourneyEntry, JourneyPhoto, GalleryPhoto, JourneyTrip, JourneyDetail } from '../store/journeyStore'
|
import type { JourneyEntry, JourneyPhoto, GalleryPhoto, JourneyTrip, JourneyDetail } from '../store/journeyStore'
|
||||||
import { computeJourneyLifecycle } from '../utils/journeyLifecycle'
|
import { computeJourneyLifecycle } from '../utils/journeyLifecycle'
|
||||||
|
import { getApiErrorMessage } from '../types'
|
||||||
|
|
||||||
const GRADIENTS = [
|
const GRADIENTS = [
|
||||||
'linear-gradient(135deg, #0F172A 0%, #6366F1 45%, #EC4899 100%)',
|
'linear-gradient(135deg, #0F172A 0%, #6366F1 45%, #EC4899 100%)',
|
||||||
@@ -1034,8 +1035,8 @@ function GalleryView({ entries, gallery, journeyId, userId, trips, onPhotoClick,
|
|||||||
await journeyApi.uploadGalleryPhotos(journeyId, formData)
|
await journeyApi.uploadGalleryPhotos(journeyId, formData)
|
||||||
toast.success(t('journey.photosUploaded', { count: files.length }))
|
toast.success(t('journey.photosUploaded', { count: files.length }))
|
||||||
onRefresh()
|
onRefresh()
|
||||||
} catch {
|
} catch (err) {
|
||||||
toast.error(t('journey.settings.coverFailed'))
|
toast.error(getApiErrorMessage(err, t('journey.photosUploadFailed')))
|
||||||
} finally {
|
} finally {
|
||||||
setGalleryUploading(false)
|
setGalleryUploading(false)
|
||||||
}
|
}
|
||||||
@@ -2175,6 +2176,7 @@ function EntryEditor({ entry, journeyId, tripDates, galleryPhotos, onClose, onSa
|
|||||||
onDone: () => void
|
onDone: () => void
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
const toast = useToast()
|
||||||
const isMobile = useIsMobile()
|
const isMobile = useIsMobile()
|
||||||
const [title, setTitle] = useState(entry.title || '')
|
const [title, setTitle] = useState(entry.title || '')
|
||||||
const [story, setStory] = useState(entry.story || '')
|
const [story, setStory] = useState(entry.story || '')
|
||||||
@@ -2248,7 +2250,11 @@ function EntryEditor({ entry, journeyId, tripDates, galleryPhotos, onClose, onSa
|
|||||||
if (pendingFiles.length > 0 && entryId) {
|
if (pendingFiles.length > 0 && entryId) {
|
||||||
const formData = new FormData()
|
const formData = new FormData()
|
||||||
for (const f of pendingFiles) formData.append('photos', f)
|
for (const f of pendingFiles) formData.append('photos', f)
|
||||||
await onUploadPhotos(entryId, formData)
|
try {
|
||||||
|
await onUploadPhotos(entryId, formData)
|
||||||
|
} catch (err) {
|
||||||
|
toast.error(getApiErrorMessage(err, t('journey.editor.uploadFailed')))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// link gallery photos that were picked before save
|
// link gallery photos that were picked before save
|
||||||
if (pendingLinkIds.length > 0 && entryId) {
|
if (pendingLinkIds.length > 0 && entryId) {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import cookieParser from 'cookie-parser';
|
|||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
|
|
||||||
|
import multer from 'multer';
|
||||||
import { logDebug, logWarn, logError } from './services/auditLog';
|
import { logDebug, logWarn, logError } from './services/auditLog';
|
||||||
import { enforceGlobalMfaPolicy } from './middleware/mfaPolicy';
|
import { enforceGlobalMfaPolicy } from './middleware/mfaPolicy';
|
||||||
import { authenticate, verifyJwtAndLoadUser } from './middleware/auth';
|
import { authenticate, verifyJwtAndLoadUser } from './middleware/auth';
|
||||||
@@ -507,6 +508,10 @@ export function createApp(): express.Application {
|
|||||||
} else {
|
} else {
|
||||||
console.error('Unhandled error:', err);
|
console.error('Unhandled error:', err);
|
||||||
}
|
}
|
||||||
|
if (err instanceof multer.MulterError) {
|
||||||
|
const status = err.code === 'LIMIT_FILE_SIZE' ? 413 : 400;
|
||||||
|
return res.status(status).json({ error: err.message });
|
||||||
|
}
|
||||||
const status = err.statusCode || err.status || 500;
|
const status = err.statusCode || err.status || 500;
|
||||||
// Expose the message for client errors (4xx); keep 'Internal server error' for 5xx.
|
// Expose the message for client errors (4xx); keep 'Internal server error' for 5xx.
|
||||||
const message = status < 500 ? err.message : 'Internal server error';
|
const message = status < 500 ? err.message : 'Internal server error';
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ router.delete('/entries/:entryId', authenticate, (req: Request, res: Response) =
|
|||||||
|
|
||||||
// ── Photos (prefix /photos and /entries — before /:id) ───────────────────
|
// ── Photos (prefix /photos and /entries — before /:id) ───────────────────
|
||||||
|
|
||||||
router.post('/entries/:entryId/photos', authenticate, upload.array('photos', 10), async (req: Request, res: Response) => {
|
router.post('/entries/:entryId/photos', authenticate, upload.array('photos'), async (req: Request, res: Response) => {
|
||||||
const authReq = req as AuthRequest;
|
const authReq = req as AuthRequest;
|
||||||
const files = req.files as Express.Multer.File[];
|
const files = req.files as Express.Multer.File[];
|
||||||
if (!files?.length) return res.status(400).json({ error: 'No files uploaded' });
|
if (!files?.length) return res.status(400).json({ error: 'No files uploaded' });
|
||||||
@@ -201,7 +201,7 @@ router.delete('/photos/:photoId', authenticate, async (req: Request, res: Respon
|
|||||||
// ── Gallery (prefix /:id/gallery — before /:id) ──────────────────────────
|
// ── Gallery (prefix /:id/gallery — before /:id) ──────────────────────────
|
||||||
|
|
||||||
// Upload photos directly to the journey gallery (no entry association)
|
// Upload photos directly to the journey gallery (no entry association)
|
||||||
router.post('/:id/gallery/photos', authenticate, upload.array('photos', 20), async (req: Request, res: Response) => {
|
router.post('/:id/gallery/photos', authenticate, upload.array('photos'), async (req: Request, res: Response) => {
|
||||||
const authReq = req as AuthRequest;
|
const authReq = req as AuthRequest;
|
||||||
const files = req.files as Express.Multer.File[];
|
const files = req.files as Express.Multer.File[];
|
||||||
if (!files?.length) return res.status(400).json({ error: 'No files uploaded' });
|
if (!files?.length) return res.status(400).json({ error: 'No files uploaded' });
|
||||||
|
|||||||
Reference in New Issue
Block a user