Migrate guest v2 achievements and refresh share page
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (push) Has been cancelled
tests / ui (push) Has been cancelled

This commit is contained in:
Codex Agent
2026-02-05 16:46:15 +01:00
parent fa630e335d
commit 4e0d156065
22 changed files with 1142 additions and 1902 deletions

View File

@@ -75,6 +75,7 @@ export default function GalleryScreen() {
const numberFormatter = React.useMemo(() => new Intl.NumberFormat(locale), [locale]);
const [lightboxPhoto, setLightboxPhoto] = React.useState<LightboxPhoto | null>(null);
const [lightboxLoading, setLightboxLoading] = React.useState(false);
const [lightboxError, setLightboxError] = React.useState<'notFound' | 'loadFailed' | null>(null);
const [likesById, setLikesById] = React.useState<Record<number, number>>({});
const [shareSheet, setShareSheet] = React.useState<{ url: string | null; loading: boolean }>({
url: null,
@@ -82,6 +83,7 @@ export default function GalleryScreen() {
});
const [likedIds, setLikedIds] = React.useState<Set<number>>(new Set());
const touchStartX = React.useRef<number | null>(null);
const fallbackAttemptedRef = React.useRef(false);
React.useEffect(() => {
if (!token) {
@@ -182,6 +184,23 @@ export default function GalleryScreen() {
setFilter('latest');
}
}, [filter, photos]);
React.useEffect(() => {
fallbackAttemptedRef.current = false;
}, [selectedPhotoId]);
React.useEffect(() => {
if (!lightboxOpen || !selectedPhotoId) {
return;
}
if (lightboxIndex >= 0) {
return;
}
if (filter !== 'latest' && !fallbackAttemptedRef.current) {
fallbackAttemptedRef.current = true;
setFilter('latest');
}
}, [filter, lightboxIndex, lightboxOpen, selectedPhotoId]);
const newUploads = React.useMemo(() => {
if (delta.photos.length === 0) {
return 0;
@@ -275,6 +294,7 @@ export default function GalleryScreen() {
if (!lightboxOpen) {
setLightboxPhoto(null);
setLightboxLoading(false);
setLightboxError(null);
return;
}
@@ -287,6 +307,7 @@ export default function GalleryScreen() {
let active = true;
setLightboxLoading(true);
setLightboxError(null);
fetchPhoto(selectedPhotoId, locale)
.then((photo) => {
if (!active || !photo) return;
@@ -298,6 +319,8 @@ export default function GalleryScreen() {
})
.catch((error) => {
console.error('Lightbox photo load failed', error);
if (!active) return;
setLightboxError(error?.status === 404 ? 'notFound' : 'loadFailed');
})
.finally(() => {
if (active) {
@@ -328,6 +351,19 @@ export default function GalleryScreen() {
};
}, [lightboxOpen]);
React.useEffect(() => {
if (!lightboxOpen || !lightboxError) {
return;
}
pushGuestToast({
text: lightboxError === 'notFound'
? t('lightbox.errors.notFound', 'Photo not found')
: t('lightbox.errors.loadFailed', 'Failed to load photo'),
type: 'warning',
});
closeLightbox();
}, [closeLightbox, lightboxError, lightboxOpen, t]);
const goPrev = React.useCallback(() => {
if (lightboxIndex <= 0) return;
const prevId = displayPhotos[lightboxIndex - 1]?.id;