- Reworked the tenant admin login page

- Updated the User model to implement Filament’s tenancy contracts
- Seeded a ready-to-use demo tenant (user, tenant, active package, purchase)
- Introduced a branded, translated 403 error page to replace the generic forbidden message for unauthorised admin hits
- Removed the public “Register” links from the marketing header
- hardened join event logic and improved error handling in the guest pwa.
This commit is contained in:
Codex Agent
2025-10-13 12:50:46 +02:00
parent 9394c3171e
commit 64a5411fb9
69 changed files with 5447 additions and 588 deletions

View File

@@ -2,6 +2,21 @@ import { authorizedFetch } from './auth/tokens';
type JsonValue = Record<string, any>;
export type EventJoinTokenLayout = {
id: string;
name: string;
description: string;
subtitle: string;
preview: {
background: string | null;
background_gradient: { angle: number; stops: string[] } | null;
accent: string | null;
text: string | null;
};
formats: string[];
download_urls: Record<string, string>;
};
export type TenantEvent = {
id: number;
name: string | Record<string, string>;
@@ -139,6 +154,8 @@ export type EventJoinToken = {
is_active: boolean;
created_at: string | null;
metadata: Record<string, unknown>;
layouts: EventJoinTokenLayout[];
layouts_url: string | null;
};
type CreatedEventResponse = { message: string; data: TenantEvent; balance: number };
type PhotoResponse = { message: string; data: TenantPhoto };
@@ -271,6 +288,30 @@ function normalizeMember(member: JsonValue): EventMember {
}
function normalizeJoinToken(raw: JsonValue): EventJoinToken {
const rawLayouts = Array.isArray(raw.layouts) ? raw.layouts : [];
const layouts: EventJoinTokenLayout[] = rawLayouts
.map((layout: any) => {
const formats = Array.isArray(layout.formats)
? layout.formats.map((format: unknown) => String(format ?? '')).filter((format: string) => format.length > 0)
: [];
return {
id: String(layout.id ?? ''),
name: String(layout.name ?? ''),
description: String(layout.description ?? ''),
subtitle: String(layout.subtitle ?? ''),
preview: {
background: layout.preview?.background ?? null,
background_gradient: layout.preview?.background_gradient ?? null,
accent: layout.preview?.accent ?? null,
text: layout.preview?.text ?? null,
},
formats,
download_urls: (layout.download_urls ?? {}) as Record<string, string>,
};
})
.filter((layout: EventJoinTokenLayout) => layout.id.length > 0);
return {
id: Number(raw.id ?? 0),
token: String(raw.token ?? ''),
@@ -283,6 +324,8 @@ function normalizeJoinToken(raw: JsonValue): EventJoinToken {
is_active: Boolean(raw.is_active),
created_at: raw.created_at ?? null,
metadata: (raw.metadata ?? {}) as Record<string, unknown>,
layouts,
layouts_url: typeof raw.layouts_url === 'string' ? raw.layouts_url : null,
};
}