feat: Admin Area General Settings and Categories 1.16

This commit is contained in:
OpenVelo Agent
2026-07-22 19:19:44 +00:00
parent 73cfbb9af0
commit c02d3934d4
7 changed files with 163 additions and 109 deletions
@@ -53,6 +53,8 @@ export type ModalMode = 'create' | 'edit';
[open]="modalMode() !== null"
[mode]="modalMode() === 'edit' ? 'edit' : 'create'"
[category]="editing()"
[errorMessage]="formError()"
[saving]="saving()"
(cancel)="closeModal()"
(submit)="onFormSubmit($event)"
/>
@@ -79,6 +81,8 @@ export class AdminCategoriesComponent implements OnInit {
readonly editing = signal<AdminCategory | null>(null);
readonly deleting = signal<AdminCategory | null>(null);
readonly deleteError = signal<string | null>(null);
readonly formError = signal<string | null>(null);
readonly saving = signal(false);
async ngOnInit(): Promise<void> {
await this.load();
@@ -102,6 +106,7 @@ export class AdminCategoriesComponent implements OnInit {
this.editing.set(null);
this.deleting.set(null);
this.deleteError.set(null);
this.formError.set(null);
this.deleteOpen.set(false);
this.modalMode.set('create');
}
@@ -110,6 +115,8 @@ export class AdminCategoriesComponent implements OnInit {
this.deleting.set(null);
this.deleteOpen.set(false);
this.editing.set(c);
this.deleteError.set(null);
this.formError.set(null);
this.modalMode.set('edit');
}
@@ -127,9 +134,13 @@ export class AdminCategoriesComponent implements OnInit {
this.editing.set(null);
this.deleting.set(null);
this.deleteError.set(null);
this.formError.set(null);
this.saving.set(false);
}
async onFormSubmit(payload: CategoryFormSubmit): Promise<void> {
this.saving.set(true);
this.formError.set(null);
try {
if (payload.mode === 'create') {
const created = await this.admin.createCategory({
@@ -151,6 +162,7 @@ export class AdminCategoriesComponent implements OnInit {
}
await this.admin.updateCategory(id, {
name: payload.name,
abbreviation: payload.abbreviation,
description: payload.description,
iconPath,
});
@@ -158,7 +170,9 @@ export class AdminCategoriesComponent implements OnInit {
this.closeModal();
await this.load();
} catch (e: any) {
this.deleteError.set(e?.error?.message ?? e?.message ?? 'Failed');
this.formError.set(e?.error?.message ?? e?.message ?? 'Failed');
} finally {
this.saving.set(false);
}
}
@@ -92,9 +92,13 @@ export function syncCategoryForm(
}
</div>
@if (errorMessage()) {
<p class="error" data-testid="cf-error" style="color: var(--color-danger, #f00); margin-top: 8px;">{{ errorMessage() }}</p>
}
<div class="actions">
<button type="button" (click)="onCancel()" data-testid="cf-cancel">Cancel</button>
<button type="button" [disabled]="form.invalid || submitting()" (click)="onOk()" data-testid="cf-ok">OK</button>
<button type="button" [disabled]="form.invalid || submitting() || saving()" (click)="onOk()" data-testid="cf-ok">OK</button>
</div>
</form>
</div>
@@ -112,6 +116,8 @@ export class CategoryFormModalComponent {
readonly cancel = output<void>();
readonly submit = output<CategoryFormSubmit>();
readonly errorMessage = input<string | null>(null);
readonly saving = input(false);
readonly iconPreview = signal<string | null>(null);
readonly iconFile = signal<File | null>(null);