Aufgabenkarten in der Gäste-pwa als swipe-barer Stapel umgesetzt. Sofortiges Freigeben von Foto-Uploads als Event-Einstellung implementiert.

This commit is contained in:
Codex Agent
2025-12-16 15:30:52 +01:00
parent f2473c6f6d
commit 9e4e9a0d87
19 changed files with 22590 additions and 21687 deletions

View File

@@ -39,6 +39,7 @@ import { useEventStats } from '../context/EventStatsContext';
import { useEventBranding } from '../context/EventBrandingContext';
import { compressPhoto, formatBytes } from '../lib/image';
import { useGuestIdentity } from '../context/GuestIdentityContext';
import { useEventData } from '../hooks/useEventData';
interface Task {
id: number;
@@ -120,10 +121,13 @@ export default function UploadPage() {
const { t, locale } = useTranslation();
const stats = useEventStats();
const { branding } = useEventBranding();
const { event } = useEventData();
const radius = branding.buttons?.radius ?? 12;
const buttonStyle = branding.buttons?.style ?? 'filled';
const linkColor = branding.buttons?.linkColor ?? branding.secondaryColor;
const bodyFont = branding.typography?.body ?? branding.fontFamily ?? undefined;
const uploadsRequireApproval =
(event?.guest_upload_visibility as 'immediate' | 'review' | undefined) !== 'immediate';
const taskIdParam = searchParams.get('task');
const emotionSlug = searchParams.get('emotion') || '';
@@ -253,12 +257,19 @@ const [canUpload, setCanUpload] = useState(true);
headers: {
Accept: 'application/json',
'X-Locale': locale,
'X-Device-Id': getDeviceId(),
},
}
);
if (!res.ok) throw new Error('Tasks konnten nicht geladen werden');
const payload = (await res.json()) as unknown;
const entries = Array.isArray(payload) ? payload.filter(isTaskPayload) : [];
const entries = Array.isArray(payload)
? payload.filter(isTaskPayload)
: Array.isArray((payload as any)?.data)
? (payload as any).data.filter(isTaskPayload)
: Array.isArray((payload as any)?.tasks)
? (payload as any).tasks.filter(isTaskPayload)
: [];
const found = entries.find((entry) => entry.id === currentTaskId) ?? null;
if (!active) return;
@@ -1103,6 +1114,12 @@ const renderWithDialog = (content: ReactNode, wrapperClassName = 'space-y-6 pb-[
>
{taskFloatingCard}
{heroOverlay}
{uploadsRequireApproval ? (
<div className="mx-4 rounded-xl border border-amber-300/70 bg-amber-50/80 p-3 text-amber-900 shadow-sm backdrop-blur dark:border-amber-400/40 dark:bg-amber-500/10 dark:text-amber-50">
<p className="text-sm font-semibold">{t('upload.review.noticeTitle', 'Uploads werden geprüft')}</p>
<p className="text-xs">{t('upload.review.noticeBody', 'Dein Foto erscheint, sobald es freigegeben wurde.')}</p>
</div>
) : null}
<section
className="relative flex flex-col overflow-hidden border border-white/10 bg-black text-white shadow-2xl"
style={{ borderRadius: radius }}