diff --git a/client/src/pages/JourneyDetailPage.tsx b/client/src/pages/JourneyDetailPage.tsx index f8e3db24..4c2c3643 100644 --- a/client/src/pages/JourneyDetailPage.tsx +++ b/client/src/pages/JourneyDetailPage.tsx @@ -1010,9 +1010,16 @@ function GalleryView({ entries, journeyId, userId, trips, onPhotoClick, onRefres }, []) const allPhotos: { photo: JourneyPhoto; entry: JourneyEntry }[] = [] + const seenPhotoIds = new Map() // photo_id → index in allPhotos for (const e of entries) { for (const p of e.photos) { - allPhotos.push({ photo: p, entry: e }) + const existing = seenPhotoIds.get(p.photo_id) + if (existing === undefined) { + seenPhotoIds.set(p.photo_id, allPhotos.length) + allPhotos.push({ photo: p, entry: e }) + } else if (e.title === 'Gallery' && allPhotos[existing].entry.title !== 'Gallery') { + allPhotos[existing] = { photo: p, entry: e } + } } } @@ -1057,23 +1064,27 @@ function GalleryView({ entries, journeyId, userId, trips, onPhotoClick, onRefres } const handleDeletePhoto = async (photoId: number) => { - // Optimistic update — remove photo from local state immediately const store = useJourneyStore.getState() - if (store.current) { - const updated = { - ...store.current, - entries: store.current.entries.map(e => ({ - ...e, - photos: e.photos.filter(p => p.id !== photoId), - })).filter(e => e.type !== 'entry' || e.title !== 'Gallery' || e.photos.length > 0 || e.story), - } - useJourneyStore.setState({ current: updated }) + if (!store.current) return + const target = store.current.entries.flatMap(e => e.photos).find(p => p.id === photoId) + if (!target) return + const siblingIds = store.current.entries.flatMap(e => e.photos).filter(p => p.photo_id === target.photo_id).map(p => p.id) + + // Optimistic update — remove every row with this photo_id + const updated = { + ...store.current, + entries: store.current.entries.map(e => ({ + ...e, + photos: e.photos.filter(p => p.photo_id !== target.photo_id), + })).filter(e => e.type !== 'entry' || e.title !== 'Gallery' || e.photos.length > 0 || e.story), } + useJourneyStore.setState({ current: updated }) + try { - await journeyApi.deletePhoto(photoId) + await Promise.all(siblingIds.map(id => journeyApi.deletePhoto(id))) } catch { toast.error(t('common.error')) - onRefresh() // Revert on error + onRefresh() } } @@ -1793,11 +1804,11 @@ function ProviderPicker({ provider, userId, entries, trips, existingAssetIds, on : t('journey.picker.newGallery') return ( -
-
+
{ if (e.target === e.currentTarget) e.preventDefault() }}> +
e.stopPropagation()}> {/* Header */} -
+

{provider === 'immich' ? 'Immich' : 'Synology Photos'}

@@ -1807,7 +1818,7 @@ function ProviderPicker({ provider, userId, entries, trips, existingAssetIds, on
{/* Filter bar */} -
+
{/* Tabs */}
{[ @@ -1893,7 +1904,7 @@ function ProviderPicker({ provider, userId, entries, trips, existingAssetIds, on
{/* Add-to entry selector */} -
+
{t('journey.picker.addTo')}