der tenant admin hat eine neue, mobil unterstützende UI, login redirect funktioniert, typescript fehler wurden bereinigt. Neue Blog Posts von ChatGPT eingebaut, übersetzt von Gemini 2.5
This commit is contained in:
@@ -3,7 +3,7 @@ import { ApiError, emitApiErrorEvent } from './lib/apiError';
|
||||
import type { EventLimitSummary } from './lib/limitWarnings';
|
||||
import i18n from './i18n';
|
||||
|
||||
type JsonValue = Record<string, unknown>;
|
||||
type JsonValue = Record<string, any>;
|
||||
|
||||
export type TenantAccountProfile = {
|
||||
id: number;
|
||||
@@ -98,6 +98,7 @@ export type TenantPhoto = {
|
||||
likes_count: number;
|
||||
uploaded_at: string;
|
||||
uploader_name: string | null;
|
||||
caption?: string | null;
|
||||
};
|
||||
|
||||
export type EventStats = {
|
||||
@@ -107,6 +108,10 @@ export type EventStats = {
|
||||
recent_uploads: number;
|
||||
status: string;
|
||||
is_active: boolean;
|
||||
uploads_total?: number;
|
||||
uploads_24h?: number;
|
||||
likes_total?: number;
|
||||
pending_photos?: number;
|
||||
};
|
||||
|
||||
export type PaginationMeta = {
|
||||
@@ -156,7 +161,9 @@ export async function trackOnboarding(step: string, meta?: Record<string, unknow
|
||||
body: JSON.stringify({ step, meta }),
|
||||
});
|
||||
} catch (error) {
|
||||
emitApiErrorEvent(new ApiError('onboarding.track_failed', i18n.t('common.errors.generic', 'Etwas ist schiefgelaufen.'), error));
|
||||
const message = i18n.t('common.errors.generic', 'Etwas ist schiefgelaufen.');
|
||||
emitApiErrorEvent({ message, code: 'onboarding.track_failed' });
|
||||
console.error('[Onboarding] Failed to track tenant onboarding step', error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,7 +172,9 @@ export async function fetchOnboardingStatus(): Promise<TenantOnboardingStatus |
|
||||
const response = await authorizedFetch('/api/v1/tenant/onboarding');
|
||||
return (await response.json()) as TenantOnboardingStatus;
|
||||
} catch (error) {
|
||||
emitApiErrorEvent(new ApiError('onboarding.fetch_failed', i18n.t('common.errors.generic', 'Etwas ist schiefgelaufen.'), error));
|
||||
const message = i18n.t('common.errors.generic', 'Etwas ist schiefgelaufen.');
|
||||
emitApiErrorEvent({ message, code: 'onboarding.fetch_failed' });
|
||||
console.error('[Onboarding] Failed to fetch tenant onboarding status', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -232,6 +241,7 @@ export type TenantTask = {
|
||||
difficulty: 'easy' | 'medium' | 'hard' | null;
|
||||
due_date: string | null;
|
||||
is_completed: boolean;
|
||||
tenant_id: number | null;
|
||||
collection_id: number | null;
|
||||
source_task_id: number | null;
|
||||
source_collection_id: number | null;
|
||||
@@ -401,14 +411,17 @@ async function jsonOrThrow<T>(response: Response, message: string, options: Json
|
||||
const body = await safeJson(response);
|
||||
const status = response.status;
|
||||
const errorPayload = body && typeof body === 'object' ? (body as Record<string, unknown>).error : null;
|
||||
const errorMessage = (errorPayload && typeof errorPayload === 'object' && 'message' in errorPayload && typeof errorPayload.message === 'string')
|
||||
? errorPayload.message
|
||||
const errorRecord = errorPayload && typeof errorPayload === 'object'
|
||||
? (errorPayload as Record<string, unknown>)
|
||||
: null;
|
||||
const errorMessage = errorRecord && typeof errorRecord.message === 'string'
|
||||
? errorRecord.message
|
||||
: message;
|
||||
const errorCode = errorPayload && typeof errorPayload === 'object' && typeof errorPayload.code === 'string'
|
||||
? errorPayload.code
|
||||
const errorCode = errorRecord && typeof errorRecord.code === 'string'
|
||||
? errorRecord.code
|
||||
: undefined;
|
||||
let errorMeta = errorPayload && typeof errorPayload === 'object' && typeof errorPayload.meta === 'object'
|
||||
? errorPayload.meta as Record<string, unknown>
|
||||
let errorMeta = errorRecord && typeof errorRecord.meta === 'object'
|
||||
? (errorRecord.meta ?? null) as Record<string, unknown>
|
||||
: undefined;
|
||||
|
||||
if (!errorMeta && body && typeof body === 'object' && 'errors' in body && typeof body.errors === 'object') {
|
||||
@@ -587,6 +600,7 @@ function normalizePhoto(photo: TenantPhoto): TenantPhoto {
|
||||
likes_count: Number(photo.likes_count ?? 0),
|
||||
uploaded_at: photo.uploaded_at,
|
||||
uploader_name: photo.uploader_name ?? null,
|
||||
caption: photo.caption ?? null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -654,7 +668,6 @@ function normalizeTask(task: JsonValue): TenantTask {
|
||||
|
||||
return {
|
||||
id: Number(task.id ?? 0),
|
||||
tenant_id: task.tenant_id ?? null,
|
||||
slug: String(task.slug ?? `task-${task.id ?? ''}`),
|
||||
title: pickTranslatedText(titleTranslations, 'Ohne Titel'),
|
||||
title_translations: titleTranslations,
|
||||
@@ -668,6 +681,7 @@ function normalizeTask(task: JsonValue): TenantTask {
|
||||
difficulty: (task.difficulty ?? null) as TenantTask['difficulty'],
|
||||
due_date: task.due_date ?? null,
|
||||
is_completed: Boolean(task.is_completed ?? false),
|
||||
tenant_id: task.tenant_id ?? null,
|
||||
collection_id: task.collection_id ?? null,
|
||||
source_task_id: task.source_task_id ?? null,
|
||||
source_collection_id: task.source_collection_id ?? null,
|
||||
@@ -680,7 +694,11 @@ function normalizeTask(task: JsonValue): TenantTask {
|
||||
|
||||
function normalizeTaskCollection(raw: JsonValue): TenantTaskCollection {
|
||||
const nameTranslations = normalizeTranslationMap(raw.name_translations ?? raw.name ?? {});
|
||||
const descriptionTranslations = normalizeTranslationMap(raw.description_translations ?? raw.description ?? {}, true);
|
||||
const descriptionTranslations = normalizeTranslationMap(
|
||||
raw.description_translations ?? raw.description ?? {},
|
||||
undefined,
|
||||
true
|
||||
);
|
||||
|
||||
const eventTypeRaw = raw.event_type ?? raw.eventType ?? null;
|
||||
let eventType: TenantTaskCollection['event_type'] = null;
|
||||
@@ -715,7 +733,11 @@ function normalizeTaskCollection(raw: JsonValue): TenantTaskCollection {
|
||||
|
||||
function normalizeEmotion(raw: JsonValue): TenantEmotion {
|
||||
const nameTranslations = normalizeTranslationMap(raw.name_translations ?? raw.name ?? {});
|
||||
const descriptionTranslations = normalizeTranslationMap(raw.description_translations ?? raw.description ?? {}, true);
|
||||
const descriptionTranslations = normalizeTranslationMap(
|
||||
raw.description_translations ?? raw.description ?? {},
|
||||
undefined,
|
||||
true
|
||||
);
|
||||
|
||||
const eventTypes = Array.isArray(raw.event_types ?? raw.eventTypes)
|
||||
? (raw.event_types ?? raw.eventTypes)
|
||||
@@ -906,6 +928,10 @@ export async function getEventStats(slug: string): Promise<EventStats> {
|
||||
recent_uploads: Number(data.recent_uploads ?? 0),
|
||||
status: data.status ?? 'draft',
|
||||
is_active: Boolean(data.is_active),
|
||||
uploads_total: Number((data as JsonValue).uploads_total ?? data.total ?? 0),
|
||||
uploads_24h: Number((data as JsonValue).uploads_24h ?? data.recent_uploads ?? 0),
|
||||
likes_total: Number((data as JsonValue).likes_total ?? data.likes ?? 0),
|
||||
pending_photos: Number((data as JsonValue).pending_photos ?? 0),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1006,8 +1032,8 @@ export async function getEventToolkit(slug: string): Promise<EventToolkit> {
|
||||
: [],
|
||||
},
|
||||
photos: {
|
||||
pending: pendingPhotosRaw.map((photo) => normalizePhoto(photo as TenantPhoto)),
|
||||
recent: recentPhotosRaw.map((photo) => normalizePhoto(photo as TenantPhoto)),
|
||||
pending: pendingPhotosRaw.map((photo: JsonValue) => normalizePhoto(photo as TenantPhoto)),
|
||||
recent: recentPhotosRaw.map((photo: JsonValue) => normalizePhoto(photo as TenantPhoto)),
|
||||
},
|
||||
invites: {
|
||||
summary: {
|
||||
|
||||
Reference in New Issue
Block a user