feat(giving): giving categories management page
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 <noreply@anthropic.com>
This commit is contained in:
+58
@@ -0,0 +1,58 @@
|
|||||||
|
<div class="page">
|
||||||
|
<header class="page-header">
|
||||||
|
<h2>Giving Types / 奉獻類型</h2>
|
||||||
|
<div class="header-actions">
|
||||||
|
<label class="inactive-toggle">
|
||||||
|
<input type="checkbox" [(ngModel)]="includeInactive" (change)="load()" /> Show inactive
|
||||||
|
</label>
|
||||||
|
<button kendoButton themeColor="primary" (click)="openAdd()">+ Add</button>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<kendo-grid [data]="data" [loading]="isLoading">
|
||||||
|
<kendo-grid-column field="sortOrder" title="#" [width]="60"></kendo-grid-column>
|
||||||
|
<kendo-grid-column field="name_en" title="Name (EN)"></kendo-grid-column>
|
||||||
|
<kendo-grid-column field="name_zh" title="名稱 (中)"></kendo-grid-column>
|
||||||
|
<kendo-grid-column field="isActive" title="Active" [width]="90">
|
||||||
|
<ng-template kendoGridCellTemplate let-c>{{ c.isActive ? 'Yes' : 'No' }}</ng-template>
|
||||||
|
</kendo-grid-column>
|
||||||
|
<kendo-grid-column title="Actions" [width]="160">
|
||||||
|
<ng-template kendoGridCellTemplate let-c>
|
||||||
|
<button kendoButton fillMode="flat" (click)="openEdit(c)">Edit</button>
|
||||||
|
<button kendoButton fillMode="flat" *ngIf="c.isActive" (click)="deactivate(c)">Deactivate</button>
|
||||||
|
</ng-template>
|
||||||
|
</kendo-grid-column>
|
||||||
|
</kendo-grid>
|
||||||
|
|
||||||
|
<kendo-dialog *ngIf="showDialog" [title]="editing ? 'Edit Giving Type' : 'Add Giving Type'" (close)="showDialog=false" [width]="480">
|
||||||
|
<div class="form-grid">
|
||||||
|
<label>
|
||||||
|
Name (EN) *
|
||||||
|
<kendo-textbox [(ngModel)]="form.name_en"></kendo-textbox>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
名稱 (中)
|
||||||
|
<kendo-textbox [(ngModel)]="form.name_zh"></kendo-textbox>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
Description (EN)
|
||||||
|
<kendo-textbox [(ngModel)]="form.description_en"></kendo-textbox>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
說明 (中)
|
||||||
|
<kendo-textbox [(ngModel)]="form.description_zh"></kendo-textbox>
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
Sort order
|
||||||
|
<kendo-numerictextbox [(ngModel)]="form.sortOrder" [format]="'n0'" [decimals]="0" [min]="0"></kendo-numerictextbox>
|
||||||
|
</label>
|
||||||
|
<label *ngIf="editing">
|
||||||
|
<input type="checkbox" [(ngModel)]="form.isActive" /> Active
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<kendo-dialog-actions>
|
||||||
|
<button kendoButton (click)="showDialog=false">Cancel</button>
|
||||||
|
<button kendoButton themeColor="primary" [disabled]="!form.name_en" (click)="save()">Save</button>
|
||||||
|
</kendo-dialog-actions>
|
||||||
|
</kendo-dialog>
|
||||||
|
</div>
|
||||||
+31
@@ -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;
|
||||||
|
}
|
||||||
+74
@@ -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 };
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user