feat: add guest notification insights

This commit is contained in:
Codex Agent
2025-11-12 19:31:13 +01:00
parent 642541c8fb
commit 2c412e3764
7 changed files with 440 additions and 7 deletions

View File

@@ -509,8 +509,30 @@ export type EventToolkit = {
};
items: EventQrInvite[];
};
notifications?: {
summary: {
total: number;
last_sent_at: string | null;
by_type: Record<string, number>;
broadcasts: {
total: number;
last_title: string | null;
last_sent_at: string | null;
};
};
recent: EventToolkitNotification[];
};
alerts: string[];
};
export type EventToolkitNotification = {
id: number;
title: string;
type: string;
status: string;
audience_scope: string;
created_at: string | null;
};
type CreatedEventResponse = { message: string; data: JsonValue; balance: number };
type PhotoResponse = { message: string; data: TenantPhoto };
@@ -1238,6 +1260,7 @@ export async function getEventToolkit(slug: string): Promise<EventToolkit> {
const tasks = json.tasks ?? {};
const photos = json.photos ?? {};
const invites = json.invites ?? {};
const notifications = normalizeToolkitNotifications(json.notifications ?? null);
const pendingPhotosRaw = Array.isArray((photos as Record<string, JsonValue>).pending)
? (photos as Record<string, JsonValue>).pending
@@ -1284,12 +1307,63 @@ export async function getEventToolkit(slug: string): Promise<EventToolkit> {
? ((invites as JsonValue).items as JsonValue[]).map((item) => normalizeQrInvite(item))
: [],
},
notifications,
alerts: Array.isArray(json.alerts) ? (json.alerts as string[]) : [],
};
return toolkit;
}
function normalizeToolkitNotifications(payload: JsonValue | null | undefined): EventToolkit['notifications'] | undefined {
if (!payload || typeof payload !== 'object') {
return undefined;
}
const record = payload as Record<string, JsonValue>;
const summaryRaw = record.summary ?? {};
const broadcastsRaw = summaryRaw?.broadcasts ?? {};
return {
summary: {
total: Number(summaryRaw?.total ?? 0),
last_sent_at: typeof summaryRaw?.last_sent_at === 'string' ? summaryRaw.last_sent_at : null,
by_type: (summaryRaw?.by_type ?? {}) as Record<string, number>,
broadcasts: {
total: Number(broadcastsRaw?.total ?? 0),
last_title: typeof broadcastsRaw?.last_title === 'string' ? broadcastsRaw.last_title : null,
last_sent_at: typeof broadcastsRaw?.last_sent_at === 'string' ? broadcastsRaw.last_sent_at : null,
},
},
recent: Array.isArray(record.recent)
? (record.recent as JsonValue[]).map((row) => normalizeToolkitNotification(row))
: [],
};
}
function normalizeToolkitNotification(row: JsonValue): EventToolkitNotification {
if (!row || typeof row !== 'object') {
return {
id: 0,
title: '',
type: 'broadcast',
status: 'active',
audience_scope: 'all',
created_at: null,
};
}
const record = row as Record<string, JsonValue>;
return {
id: Number(record.id ?? 0),
title: typeof record.title === 'string' ? record.title : '',
type: typeof record.type === 'string' ? record.type : 'broadcast',
status: typeof record.status === 'string' ? record.status : 'active',
audience_scope: typeof record.audience_scope === 'string' ? record.audience_scope : 'all',
created_at: typeof record.created_at === 'string' ? record.created_at : null,
};
}
export async function listGuestNotifications(slug: string): Promise<GuestNotificationSummary[]> {
const response = await authorizedFetch(guestNotificationsEndpoint(slug));
const data = await jsonOrThrow<{ data?: JsonValue[] }>(response, 'Failed to load guest notifications');