umfangreiche Behebung von TS-Fehlern. "npm run types" läuft nun ohne Fehler durch
This commit is contained in:
@@ -249,7 +249,7 @@ type NotificationButtonProps = {
|
||||
eventToken: string;
|
||||
open: boolean;
|
||||
onToggle: () => void;
|
||||
panelRef: React.RefObject<HTMLDivElement>;
|
||||
panelRef: React.RefObject<HTMLDivElement | null>;
|
||||
checklistItems: string[];
|
||||
taskProgress?: ReturnType<typeof useGuestTaskProgress>;
|
||||
t: TranslateFn;
|
||||
@@ -316,7 +316,7 @@ function NotificationButton({ center, eventToken, open, onToggle, panelRef, chec
|
||||
<p className="text-sm font-semibold text-slate-900">{t('header.notifications.title', 'Benachrichtigungen')}</p>
|
||||
<p className="text-xs text-slate-500">
|
||||
{center.unreadCount > 0
|
||||
? t('header.notifications.unread', '{{count}} neu', { count: center.unreadCount })
|
||||
? t('header.notifications.unread', { defaultValue: '{{count}} neu', count: center.unreadCount })
|
||||
: t('header.notifications.allRead', 'Alles gelesen')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -362,7 +362,7 @@ export const demoFixtures: DemoFixtures = {
|
||||
],
|
||||
share: {
|
||||
slug: 'demo-share',
|
||||
expires_at: null,
|
||||
expires_at: undefined,
|
||||
photo: {
|
||||
id: 8801,
|
||||
title: 'First Look',
|
||||
|
||||
@@ -104,7 +104,7 @@ export function usePushSubscription(eventToken?: string): PushSubscriptionState
|
||||
|
||||
const newSubscription = await registration.pushManager.subscribe({
|
||||
userVisibleOnly: true,
|
||||
applicationServerKey: urlBase64ToUint8Array(pushConfig.vapidPublicKey),
|
||||
applicationServerKey: urlBase64ToUint8Array(pushConfig.vapidPublicKey).buffer as ArrayBuffer,
|
||||
});
|
||||
|
||||
await registerPushSubscription(eventToken, newSubscription);
|
||||
|
||||
@@ -482,9 +482,6 @@ export const messages: Record<LocaleCode, NestedMessages> = {
|
||||
optimizedNotice: 'Wir haben dein Foto verkleinert, damit der Upload schneller klappt. Eingespart: {saved}',
|
||||
optimizedFallback: 'Optimierung nicht möglich – wir laden das Original hoch.',
|
||||
retrying: 'Verbindung holperig – neuer Versuch ({attempt}).',
|
||||
errors: {
|
||||
tooLargeHint: 'Das Foto war zu groß. Bitte erneut versuchen – wir verkleinern es automatisch.',
|
||||
},
|
||||
controls: {
|
||||
toggleGrid: 'Raster umschalten',
|
||||
toggleCountdown: 'Countdown umschalten',
|
||||
@@ -560,6 +557,7 @@ export const messages: Record<LocaleCode, NestedMessages> = {
|
||||
packageMissing: 'Dieses Event akzeptiert derzeit keine Uploads.',
|
||||
galleryExpired: 'Die Galerie ist abgelaufen. Uploads sind nicht mehr möglich.',
|
||||
generic: 'Upload fehlgeschlagen. Bitte versuche es erneut.',
|
||||
tooLargeHint: 'Das Foto war zu groß. Bitte erneut versuchen – wir verkleinern es automatisch.',
|
||||
},
|
||||
cameraInactive: 'Kamera ist nicht aktiv. {hint}',
|
||||
cameraInactiveHint: 'Tippe auf "{label}", um loszulegen.',
|
||||
@@ -1126,9 +1124,6 @@ export const messages: Record<LocaleCode, NestedMessages> = {
|
||||
optimizedNotice: 'We optimized your photo to speed up the upload. Saved: {saved}',
|
||||
optimizedFallback: 'Could not optimize – uploading the original.',
|
||||
retrying: 'Connection unstable – retrying ({attempt}).',
|
||||
errors: {
|
||||
tooLargeHint: 'The photo was too large. Please try again — we compress it automatically.',
|
||||
},
|
||||
controls: {
|
||||
toggleGrid: 'Toggle grid',
|
||||
toggleCountdown: 'Toggle countdown',
|
||||
@@ -1204,6 +1199,7 @@ export const messages: Record<LocaleCode, NestedMessages> = {
|
||||
packageMissing: 'This event is not accepting uploads right now.',
|
||||
galleryExpired: 'The gallery has expired. Uploads are no longer possible.',
|
||||
generic: 'Upload failed. Please try again.',
|
||||
tooLargeHint: 'The photo was too large. Please try again — we compress it automatically.',
|
||||
},
|
||||
cameraInactive: 'Camera is not active. {hint}',
|
||||
cameraInactiveHint: 'Tap "{label}" to get started.',
|
||||
|
||||
@@ -19,7 +19,7 @@ export default function HomePage() {
|
||||
const { name, hydrated } = useGuestIdentity();
|
||||
const stats = useEventStats();
|
||||
const { event } = useEventData();
|
||||
const { completedCount } = useGuestTaskProgress(token);
|
||||
const { completedCount } = useGuestTaskProgress(token ?? '');
|
||||
const { t, locale } = useTranslation();
|
||||
const { branding } = useEventBranding();
|
||||
|
||||
@@ -86,15 +86,16 @@ export default function HomePage() {
|
||||
async function loadMissions() {
|
||||
setMissionLoading(true);
|
||||
try {
|
||||
const response = await fetch(
|
||||
`/api/v1/events/${encodeURIComponent(token)}/tasks?locale=${encodeURIComponent(locale)}`,
|
||||
{
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'X-Locale': locale,
|
||||
},
|
||||
}
|
||||
);
|
||||
const safeToken = token ?? '';
|
||||
const response = await fetch(
|
||||
`/api/v1/events/${encodeURIComponent(safeToken)}/tasks?locale=${encodeURIComponent(locale)}`,
|
||||
{
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'X-Locale': locale,
|
||||
},
|
||||
}
|
||||
);
|
||||
if (!response.ok) throw new Error('Aufgaben konnten nicht geladen werden.');
|
||||
const payload = await response.json();
|
||||
if (cancelled) return;
|
||||
|
||||
@@ -30,7 +30,7 @@ const INITIAL_STATE: GalleryState = {
|
||||
|
||||
const GALLERY_PAGE_SIZE = 30;
|
||||
|
||||
export default function PublicGalleryPage(): JSX.Element | null {
|
||||
export default function PublicGalleryPage(): React.ReactElement | null {
|
||||
const { token } = useParams<{ token: string }>();
|
||||
const { t } = useTranslation();
|
||||
const [state, setState] = useState<GalleryState>(INITIAL_STATE);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Alert, AlertDescription } from '@/components/ui/alert';
|
||||
import { Sparkles, RefreshCw, Smile, Camera, Timer as TimerIcon, Heart, ChevronRight } from 'lucide-react';
|
||||
import { Sparkles, RefreshCw, Smile, Camera, Timer as TimerIcon, Heart, ChevronRight, CheckCircle2 } from 'lucide-react';
|
||||
import type { LucideIcon } from 'lucide-react';
|
||||
import { useGuestTaskProgress } from '../hooks/useGuestTaskProgress';
|
||||
import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group';
|
||||
|
||||
@@ -882,7 +882,7 @@ const renderWithDialog = (content: ReactNode, wrapperClassName = 'space-y-6 pb-[
|
||||
<AlertDescription>
|
||||
{t('upload.limitReached')
|
||||
.replace('{used}', `${eventPackage?.used_photos || 0}`)
|
||||
.replace('{max}', `${eventPackage?.package.max_photos || 0}`)}
|
||||
.replace('{max}', `${eventPackage?.package?.max_photos || 0}`)}
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
</>
|
||||
|
||||
@@ -147,12 +147,14 @@ export async function getHelpArticle(slug: string, locale: LocaleCode): Promise<
|
||||
locale,
|
||||
});
|
||||
const data = await requestJson<{ data?: HelpArticleDetail }>(`/api/v1/help/${encodeURIComponent(slug)}?${params.toString()}`);
|
||||
const article = data?.data ?? { slug, title: slug, summary: '' };
|
||||
writeCache(cacheKey, article);
|
||||
return { article, servedFromCache: false };
|
||||
const article: HelpArticleDetail | undefined = data?.data;
|
||||
const safeArticle: HelpArticleDetail = article ?? { slug, title: slug, summary: '' };
|
||||
writeCache(cacheKey, safeArticle);
|
||||
return { article: safeArticle, servedFromCache: false };
|
||||
} catch (error) {
|
||||
if (cached) {
|
||||
return { article: cached.data, servedFromCache: true };
|
||||
const cachedArticle: HelpArticleDetail | undefined = (cached as { data?: HelpArticleDetail } | null | undefined)?.data;
|
||||
if (cachedArticle) {
|
||||
return { article: cachedArticle, servedFromCache: true };
|
||||
}
|
||||
console.error('[HelpApi] Failed to fetch help article', error);
|
||||
throw error;
|
||||
|
||||
Reference in New Issue
Block a user