From 7260e5c115c165ce6bd5d3ba32b561fccf0148d9 Mon Sep 17 00:00:00 2001 From: Chris Chen Date: Thu, 28 May 2026 17:04:55 -0700 Subject: [PATCH] feat(giving): giving categories management page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add GivingCategoriesPageComponent — standalone Angular 18 component with Kendo Grid (list/deactivate) and Kendo Dialog (add/edit form) for managing giving types. Co-Authored-By: Claude Sonnet 4.6 --- .../giving-categories-page.component.html | 58 +++++++++++++++ .../giving-categories-page.component.scss | 31 ++++++++ .../giving-categories-page.component.ts | 74 +++++++++++++++++++ 3 files changed, 163 insertions(+) create mode 100644 APP/src/app/features/giving/pages/giving-categories-page/giving-categories-page.component.html create mode 100644 APP/src/app/features/giving/pages/giving-categories-page/giving-categories-page.component.scss create mode 100644 APP/src/app/features/giving/pages/giving-categories-page/giving-categories-page.component.ts diff --git a/APP/src/app/features/giving/pages/giving-categories-page/giving-categories-page.component.html b/APP/src/app/features/giving/pages/giving-categories-page/giving-categories-page.component.html new file mode 100644 index 0000000..79bdd68 --- /dev/null +++ b/APP/src/app/features/giving/pages/giving-categories-page/giving-categories-page.component.html @@ -0,0 +1,58 @@ +
+ + + + + + + + {{ c.isActive ? 'Yes' : 'No' }} + + + + + + + + + + +
+ + + + + + +
+ + + + +
+
diff --git a/APP/src/app/features/giving/pages/giving-categories-page/giving-categories-page.component.scss b/APP/src/app/features/giving/pages/giving-categories-page/giving-categories-page.component.scss new file mode 100644 index 0000000..e249197 --- /dev/null +++ b/APP/src/app/features/giving/pages/giving-categories-page/giving-categories-page.component.scss @@ -0,0 +1,31 @@ +.page-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 1rem; +} + +.header-actions { + display: flex; + align-items: center; + gap: 1rem; +} + +.inactive-toggle { + display: flex; + align-items: center; + gap: 0.25rem; + cursor: pointer; +} + +.form-grid { + display: flex; + flex-direction: column; + gap: 0.75rem; +} + +.form-grid label { + display: flex; + flex-direction: column; + gap: 0.25rem; +} diff --git a/APP/src/app/features/giving/pages/giving-categories-page/giving-categories-page.component.ts b/APP/src/app/features/giving/pages/giving-categories-page/giving-categories-page.component.ts new file mode 100644 index 0000000..3d61cf5 --- /dev/null +++ b/APP/src/app/features/giving/pages/giving-categories-page/giving-categories-page.component.ts @@ -0,0 +1,74 @@ +import { Component, OnInit } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { FormsModule } from '@angular/forms'; +import { GridModule } from '@progress/kendo-angular-grid'; +import { InputsModule } from '@progress/kendo-angular-inputs'; +import { ButtonsModule } from '@progress/kendo-angular-buttons'; +import { DialogsModule } from '@progress/kendo-angular-dialog'; +import { GivingCategoryApiService } from '../../services/giving-category-api.service'; +import { + GivingCategoryDto, CreateGivingCategoryRequest, UpdateGivingCategoryRequest, +} from '../../models/giving.model'; + +@Component({ + selector: 'app-giving-categories-page', + standalone: true, + imports: [CommonModule, FormsModule, GridModule, InputsModule, ButtonsModule, DialogsModule], + templateUrl: './giving-categories-page.component.html', + styleUrls: ['./giving-categories-page.component.scss'], +}) +export class GivingCategoriesPageComponent implements OnInit { + data: GivingCategoryDto[] = []; + isLoading = false; + includeInactive = false; + + showDialog = false; + editing: GivingCategoryDto | null = null; + form: UpdateGivingCategoryRequest = this.blankForm(); + + constructor(private api: GivingCategoryApiService) {} + + ngOnInit(): void { this.load(); } + + load(): void { + this.isLoading = true; + this.api.getAll(this.includeInactive).subscribe({ + next: rows => { this.data = rows; this.isLoading = false; }, + error: () => { this.isLoading = false; }, + }); + } + + openAdd(): void { this.editing = null; this.form = this.blankForm(); this.showDialog = true; } + + openEdit(c: GivingCategoryDto): void { + this.editing = c; + this.form = { + name_en: c.name_en, name_zh: c.name_zh, + description_en: c.description_en, description_zh: c.description_zh, + isActive: c.isActive, sortOrder: c.sortOrder, + }; + this.showDialog = true; + } + + save(): void { + if (this.editing) { + this.api.update(this.editing.id, this.form).subscribe(() => { this.showDialog = false; this.load(); }); + } else { + const create: CreateGivingCategoryRequest = { + name_en: this.form.name_en, name_zh: this.form.name_zh, + description_en: this.form.description_en, description_zh: this.form.description_zh, + sortOrder: this.form.sortOrder, + }; + this.api.create(create).subscribe(() => { this.showDialog = false; this.load(); }); + } + } + + deactivate(c: GivingCategoryDto): void { + if (!confirm(`Deactivate "${c.name_en}"?`)) return; + this.api.deactivate(c.id).subscribe(() => this.load()); + } + + private blankForm(): UpdateGivingCategoryRequest { + return { name_en: '', name_zh: null, description_en: null, description_zh: null, isActive: true, sortOrder: 0 }; + } +}