feat: localize guest endpoints and caching
This commit is contained in:
@@ -8,6 +8,7 @@ import { useGuestTaskProgress } from '../hooks/useGuestTaskProgress';
|
||||
import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
||||
import EmotionPicker from '../components/EmotionPicker';
|
||||
import { useEventBranding } from '../context/EventBrandingContext';
|
||||
import { useTranslation, type TranslateFn } from '../i18n/useTranslation';
|
||||
|
||||
@@ -168,7 +169,7 @@ export default function TaskPickerPage() {
|
||||
const navigate = useNavigate();
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const { branding } = useEventBranding();
|
||||
const { t } = useTranslation();
|
||||
const { t, locale } = useTranslation();
|
||||
|
||||
const { completedCount, isCompleted } = useGuestTaskProgress(eventKey);
|
||||
|
||||
@@ -194,31 +195,61 @@ export default function TaskPickerPage() {
|
||||
}), [branding.primaryColor, branding.secondaryColor]);
|
||||
|
||||
const recentTaskIdsRef = React.useRef<number[]>([]);
|
||||
const tasksCacheRef = React.useRef<Map<string, { data: Task[]; etag?: string | null }>>(new Map());
|
||||
const initialEmotionRef = React.useRef(false);
|
||||
|
||||
const fetchTasks = React.useCallback(async () => {
|
||||
if (!eventKey) return;
|
||||
const cacheKey = `${eventKey}:${locale}`;
|
||||
const cached = tasksCacheRef.current.get(cacheKey);
|
||||
setIsFetching(true);
|
||||
setLoading(true);
|
||||
setLoading(!cached);
|
||||
setError(null);
|
||||
|
||||
if (cached) {
|
||||
setTasks(cached.data);
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/v1/events/${encodeURIComponent(eventKey)}/tasks`);
|
||||
const headers: HeadersInit = {
|
||||
Accept: 'application/json',
|
||||
'X-Locale': locale,
|
||||
};
|
||||
|
||||
if (cached?.etag) {
|
||||
headers['If-None-Match'] = cached.etag;
|
||||
}
|
||||
|
||||
const response = await fetch(
|
||||
`/api/v1/events/${encodeURIComponent(eventKey)}/tasks?locale=${encodeURIComponent(locale)}`,
|
||||
{ headers }
|
||||
);
|
||||
|
||||
if (response.status === 304 && cached) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!response.ok) throw new Error('Aufgaben konnten nicht geladen werden.');
|
||||
const payload = await response.json();
|
||||
if (Array.isArray(payload)) {
|
||||
const entry = { data: payload, etag: response.headers.get('ETag') };
|
||||
tasksCacheRef.current.set(cacheKey, entry);
|
||||
setTasks(payload);
|
||||
} else {
|
||||
tasksCacheRef.current.set(cacheKey, { data: [], etag: response.headers.get('ETag') });
|
||||
setTasks([]);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Failed to load tasks', err);
|
||||
setError(err instanceof Error ? err.message : 'Unbekannter Fehler');
|
||||
setTasks([]);
|
||||
if (!cached) {
|
||||
setTasks([]);
|
||||
}
|
||||
} finally {
|
||||
setIsFetching(false);
|
||||
setLoading(false);
|
||||
}
|
||||
}, [eventKey]);
|
||||
}, [eventKey, locale]);
|
||||
|
||||
React.useEffect(() => {
|
||||
fetchTasks();
|
||||
@@ -348,8 +379,12 @@ export default function TaskPickerPage() {
|
||||
const controller = new AbortController();
|
||||
setPhotoPoolLoading(true);
|
||||
setPhotoPoolError(null);
|
||||
fetch(`/api/v1/events/${encodeURIComponent(eventKey)}/photos?locale=de`, {
|
||||
fetch(`/api/v1/events/${encodeURIComponent(eventKey)}/photos?locale=${encodeURIComponent(locale)}`, {
|
||||
signal: controller.signal,
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'X-Locale': locale,
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
if (!res.ok) {
|
||||
@@ -373,7 +408,7 @@ export default function TaskPickerPage() {
|
||||
});
|
||||
|
||||
return () => controller.abort();
|
||||
}, [eventKey, photoPool.length, t]);
|
||||
}, [eventKey, photoPool.length, t, locale]);
|
||||
|
||||
const similarPhotos = React.useMemo(() => {
|
||||
if (!currentTask) return [];
|
||||
|
||||
Reference in New Issue
Block a user