Update guest v2 home and tasks experience

This commit is contained in:
Codex Agent
2026-02-03 18:59:30 +01:00
parent a820ef2e8b
commit 7f1e6c06fb
31 changed files with 753 additions and 259 deletions

View File

@@ -14,6 +14,7 @@ export const DEFAULT_EVENT_BRANDING: EventBranding = {
backgroundColor: '#FFF6F2',
fontFamily: 'Montserrat, Inter, "Helvetica Neue", system-ui, -apple-system, BlinkMacSystemFont, sans-serif',
logoUrl: null,
welcomeMessage: null,
palette: {
primary: '#E94B5A',
secondary: '#F7C7CF',
@@ -111,6 +112,7 @@ function resolveBranding(input?: EventBranding | null): EventBranding {
},
mode: input.mode ?? 'auto',
useDefaultBranding: input.useDefaultBranding ?? undefined,
welcomeMessage: input.welcomeMessage ?? null,
};
}

View File

@@ -103,6 +103,8 @@ export const demoFixtures: DemoFixtures = {
stats: {
onlineGuests: 42,
tasksSolved: 187,
guestCount: 128,
likesCount: 980,
latestPhotoAt: now(),
},
eventPackage: {

View File

@@ -295,6 +295,10 @@ export const messages: Record<LocaleCode, NestedMessages> = {
},
},
homeV2: {
welcome: {
label: 'Willkommen',
message: 'Willkommen, {name}!',
},
rings: {
newUploads: 'Neue Uploads',
topMoments: 'Top-Momente',
@@ -314,6 +318,8 @@ export const messages: Record<LocaleCode, NestedMessages> = {
},
stats: {
uploadsQueued: 'Uploads in Warteschlange',
guestCount: 'Gäste',
likesCount: 'Likes',
},
galleryPreview: {
title: 'Galerie-Vorschau',
@@ -1202,6 +1208,10 @@ export const messages: Record<LocaleCode, NestedMessages> = {
},
},
homeV2: {
welcome: {
label: 'Welcome',
message: 'Welcome, {name}!',
},
rings: {
newUploads: 'New uploads',
topMoments: 'Top moments',
@@ -1221,6 +1231,8 @@ export const messages: Record<LocaleCode, NestedMessages> = {
},
stats: {
uploadsQueued: 'Uploads queued',
guestCount: 'Guests',
likesCount: 'Likes',
},
galleryPreview: {
title: 'Gallery preview',

View File

@@ -39,6 +39,9 @@ vi.mock('../../context/EventStatsContext', () => ({
useEventStats: () => ({
latestPhotoAt: null,
onlineGuests: 2,
tasksSolved: 0,
guestCount: 2,
likesCount: 0,
}),
}));

View File

@@ -35,6 +35,9 @@ vi.mock('../../context/EventStatsContext', () => ({
useEventStats: () => ({
latestPhotoAt: null,
onlineGuests: 0,
tasksSolved: 0,
guestCount: 0,
likesCount: 0,
}),
}));

View File

@@ -35,6 +35,9 @@ vi.mock('../../context/EventStatsContext', () => ({
useEventStats: () => ({
latestPhotoAt: null,
onlineGuests: 2,
tasksSolved: 0,
guestCount: 2,
likesCount: 0,
}),
}));

View File

@@ -3,17 +3,27 @@ import { useEffect, useRef, useState } from 'react';
export type EventStats = {
onlineGuests: number;
tasksSolved: number;
guestCount: number;
likesCount: number;
latestPhotoAt: string | null;
};
type StatsResponse = {
online_guests?: number;
tasks_solved?: number;
guest_count?: number;
likes_count?: number;
latest_photo_at?: string;
};
export function usePollStats(eventKey: string | null | undefined) {
const [data, setData] = useState<EventStats>({ onlineGuests: 0, tasksSolved: 0, latestPhotoAt: null });
const [data, setData] = useState<EventStats>({
onlineGuests: 0,
tasksSolved: 0,
guestCount: 0,
likesCount: 0,
latestPhotoAt: null,
});
const [loading, setLoading] = useState(true);
const timer = useRef<number | null>(null);
const [visible, setVisible] = useState(
@@ -30,7 +40,13 @@ export function usePollStats(eventKey: string | null | undefined) {
if (res.status === 304) return;
if (!res.ok) {
if (res.status === 404) {
setData({ onlineGuests: 0, tasksSolved: 0, latestPhotoAt: null });
setData({
onlineGuests: 0,
tasksSolved: 0,
guestCount: 0,
likesCount: 0,
latestPhotoAt: null,
});
}
return;
}
@@ -38,6 +54,8 @@ export function usePollStats(eventKey: string | null | undefined) {
setData({
onlineGuests: json.online_guests ?? 0,
tasksSolved: json.tasks_solved ?? 0,
guestCount: json.guest_count ?? 0,
likesCount: json.likes_count ?? 0,
latestPhotoAt: json.latest_photo_at ?? null,
});
} finally {

View File

@@ -227,6 +227,7 @@ function mapEventBranding(raw?: EventBrandingPayload | null): EventBranding | nu
const buttonPrimary = buttons.primary ?? raw.button_primary_color ?? primary ?? '';
const buttonSecondary = buttons.secondary ?? raw.button_secondary_color ?? secondary ?? '';
const linkColor = buttons.link_color ?? raw.link_color ?? secondary ?? '';
const welcomeMessage = raw.welcome_message ?? null;
return {
primaryColor: primary ?? '',
@@ -260,6 +261,7 @@ function mapEventBranding(raw?: EventBrandingPayload | null): EventBranding | nu
},
mode: (raw.mode as 'light' | 'dark' | 'auto' | undefined) ?? 'auto',
useDefaultBranding: raw.use_default_branding ?? undefined,
welcomeMessage,
};
}

View File

@@ -11,6 +11,7 @@ export interface EventBrandingPayload {
heading_font?: string | null;
body_font?: string | null;
font_size?: 's' | 'm' | 'l' | null;
welcome_message?: string | null;
icon?: string | null;
logo_mode?: 'emoticon' | 'upload' | null;
logo_value?: string | null;
@@ -123,6 +124,8 @@ export interface EventPackage {
export interface EventStats {
onlineGuests: number;
tasksSolved: number;
guestCount: number;
likesCount: number;
latestPhotoAt: string | null;
}
@@ -339,6 +342,8 @@ export async function fetchStats(eventKey: string): Promise<EventStats> {
return {
onlineGuests: json.online_guests ?? json.onlineGuests ?? 0,
tasksSolved: json.tasks_solved ?? json.tasksSolved ?? 0,
guestCount: json.guest_count ?? json.guestCount ?? 0,
likesCount: json.likes_count ?? json.likesCount ?? 0,
latestPhotoAt: json.latest_photo_at ?? json.latestPhotoAt ?? null,
};
}

View File

@@ -5,6 +5,7 @@ export interface EventBranding {
backgroundColor: string;
fontFamily: string | null;
logoUrl: string | null;
welcomeMessage?: string | null;
// Extended branding shape
useDefaultBranding?: boolean;