AI Implementation feature(859): Admin Area General Settings and Categories (#21)

This commit was merged in pull request #21.
This commit is contained in:
2026-07-22 11:45:23 +00:00
parent de527ec6d6
commit c9e8dfc611
34 changed files with 7349 additions and 62 deletions
@@ -8,6 +8,61 @@ export interface AdminUser {
role: 'admin' | 'player';
}
export interface GeneralSettings {
pageTitle: string;
logo: string;
welcomeMarkdown: string;
themeKey: string;
eventStartUtc: string;
eventEndUtc: string;
defaultChallengeIp: string;
registrationsEnabled: boolean;
}
export interface ThemeView {
id: string;
key: string;
name: string;
}
export interface AdminCategory {
id: string;
name: string;
abbreviation: string;
description: string;
iconPath: string;
isSystem: boolean;
systemKey: string | null;
createdAt: string;
updatedAt: string;
}
export interface CreateCategoryBody {
name: string;
abbreviation: string;
description: string;
iconPath?: string;
}
export interface UpdateCategoryBody {
name?: string;
abbreviation?: string;
description?: string;
iconPath?: string;
}
export interface IconUploadResponse {
publicUrl: string;
width: number;
height: number;
mimeType: string;
}
export interface LogoUploadResponse {
publicUrl: string;
originalFilename: string;
}
@Injectable({ providedIn: 'root' })
export class AdminService {
private readonly http = inject(HttpClient);
@@ -17,4 +72,71 @@ export class AdminService {
this.http.get<AdminUser[]>('/api/v1/admin/users', { withCredentials: true }),
);
}
async getGeneralSettings(): Promise<GeneralSettings> {
return firstValueFrom(
this.http.get<GeneralSettings>('/api/v1/admin/general/settings', { withCredentials: true }),
);
}
async updateGeneralSettings(payload: GeneralSettings): Promise<GeneralSettings> {
return firstValueFrom(
this.http.put<GeneralSettings>('/api/v1/admin/general/settings', payload, {
withCredentials: true,
}),
);
}
async listAdminThemes(): Promise<ThemeView[]> {
return firstValueFrom(
this.http.get<ThemeView[]>('/api/v1/admin/general/themes', { withCredentials: true }),
);
}
async listCategories(): Promise<AdminCategory[]> {
return firstValueFrom(
this.http.get<AdminCategory[]>('/api/v1/admin/categories', { withCredentials: true }),
);
}
async createCategory(body: CreateCategoryBody): Promise<AdminCategory> {
return firstValueFrom(
this.http.post<AdminCategory>('/api/v1/admin/categories', body, { withCredentials: true }),
);
}
async updateCategory(id: string, body: UpdateCategoryBody): Promise<AdminCategory> {
return firstValueFrom(
this.http.put<AdminCategory>(`/api/v1/admin/categories/${encodeURIComponent(id)}`, body, {
withCredentials: true,
}),
);
}
async deleteCategory(id: string): Promise<void> {
await firstValueFrom(
this.http.delete<void>(`/api/v1/admin/categories/${encodeURIComponent(id)}`, {
withCredentials: true,
}),
);
}
async uploadCategoryIcon(categoryId: string, file: File): Promise<IconUploadResponse> {
const fd = new FormData();
fd.append('file', file);
fd.append('categoryId', categoryId);
return firstValueFrom(
this.http.post<IconUploadResponse>('/api/v1/uploads/category-icon', fd, {
withCredentials: true,
}),
);
}
async uploadLogo(file: File): Promise<LogoUploadResponse> {
const fd = new FormData();
fd.append('file', file);
return firstValueFrom(
this.http.post<LogoUploadResponse>('/api/v1/uploads/logo', fd, { withCredentials: true }),
);
}
}