feat: add MemberFormDialogComponent (3-tab form)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+155
@@ -0,0 +1,155 @@
|
|||||||
|
<kendo-dialog [title]="title" (close)="onCancel()" [minWidth]="600" [width]="750">
|
||||||
|
<form [formGroup]="form" (ngSubmit)="onSubmit()">
|
||||||
|
<kendo-tabstrip>
|
||||||
|
|
||||||
|
<!-- TAB 1: Basic Info -->
|
||||||
|
<kendo-tabstrip-tab title="Basic Info" [selected]="true">
|
||||||
|
<ng-template kendoTabContent>
|
||||||
|
<div class="k-form k-form-horizontal k-mt-4">
|
||||||
|
|
||||||
|
<kendo-formfield>
|
||||||
|
<kendo-label text="Legal First Name *"></kendo-label>
|
||||||
|
<kendo-textbox formControlName="firstName_en"></kendo-textbox>
|
||||||
|
</kendo-formfield>
|
||||||
|
|
||||||
|
<kendo-formfield>
|
||||||
|
<kendo-label text="Last Name *"></kendo-label>
|
||||||
|
<kendo-textbox formControlName="lastName_en"></kendo-textbox>
|
||||||
|
</kendo-formfield>
|
||||||
|
|
||||||
|
<kendo-formfield>
|
||||||
|
<kendo-label text="Nick Name (Common Name)"></kendo-label>
|
||||||
|
<kendo-textbox formControlName="nickName" placeholder="e.g. Chris"></kendo-textbox>
|
||||||
|
</kendo-formfield>
|
||||||
|
|
||||||
|
<kendo-formfield>
|
||||||
|
<kendo-label text="Chinese First Name"></kendo-label>
|
||||||
|
<kendo-textbox formControlName="firstName_zh"></kendo-textbox>
|
||||||
|
</kendo-formfield>
|
||||||
|
|
||||||
|
<kendo-formfield>
|
||||||
|
<kendo-label text="Chinese Last Name"></kendo-label>
|
||||||
|
<kendo-textbox formControlName="lastName_zh"></kendo-textbox>
|
||||||
|
</kendo-formfield>
|
||||||
|
|
||||||
|
<kendo-formfield>
|
||||||
|
<kendo-label text="Gender"></kendo-label>
|
||||||
|
<kendo-dropdownlist
|
||||||
|
formControlName="gender"
|
||||||
|
[data]="genderOptions"
|
||||||
|
textField="text" valueField="value"
|
||||||
|
[defaultItem]="{ text: '-- Select --', value: null }">
|
||||||
|
</kendo-dropdownlist>
|
||||||
|
</kendo-formfield>
|
||||||
|
|
||||||
|
<kendo-formfield>
|
||||||
|
<kendo-label text="Date of Birth"></kendo-label>
|
||||||
|
<kendo-datepicker formControlName="dateOfBirth"></kendo-datepicker>
|
||||||
|
</kendo-formfield>
|
||||||
|
|
||||||
|
<kendo-formfield>
|
||||||
|
<kendo-label text="Status *"></kendo-label>
|
||||||
|
<kendo-dropdownlist formControlName="status" [data]="statusOptions">
|
||||||
|
</kendo-dropdownlist>
|
||||||
|
</kendo-formfield>
|
||||||
|
|
||||||
|
<kendo-formfield>
|
||||||
|
<kendo-label text="Language"></kendo-label>
|
||||||
|
<kendo-dropdownlist
|
||||||
|
formControlName="languagePreference"
|
||||||
|
[data]="langOptions" textField="text" valueField="value">
|
||||||
|
</kendo-dropdownlist>
|
||||||
|
</kendo-formfield>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
</kendo-tabstrip-tab>
|
||||||
|
|
||||||
|
<!-- TAB 2: Contact -->
|
||||||
|
<kendo-tabstrip-tab title="Contact">
|
||||||
|
<ng-template kendoTabContent>
|
||||||
|
<div class="k-form k-form-horizontal k-mt-4">
|
||||||
|
|
||||||
|
<kendo-formfield>
|
||||||
|
<kendo-label text="Email"></kendo-label>
|
||||||
|
<kendo-textbox formControlName="email" type="email"></kendo-textbox>
|
||||||
|
</kendo-formfield>
|
||||||
|
|
||||||
|
<kendo-formfield>
|
||||||
|
<kendo-label text="Cell Phone"></kendo-label>
|
||||||
|
<kendo-textbox formControlName="phoneCell"></kendo-textbox>
|
||||||
|
</kendo-formfield>
|
||||||
|
|
||||||
|
<kendo-formfield>
|
||||||
|
<kendo-label text="Home Phone"></kendo-label>
|
||||||
|
<kendo-textbox formControlName="phoneHome"></kendo-textbox>
|
||||||
|
</kendo-formfield>
|
||||||
|
|
||||||
|
<kendo-formfield>
|
||||||
|
<kendo-label text="Address"></kendo-label>
|
||||||
|
<kendo-textbox formControlName="address"></kendo-textbox>
|
||||||
|
</kendo-formfield>
|
||||||
|
|
||||||
|
<kendo-formfield>
|
||||||
|
<kendo-label text="City"></kendo-label>
|
||||||
|
<kendo-textbox formControlName="city"></kendo-textbox>
|
||||||
|
</kendo-formfield>
|
||||||
|
|
||||||
|
<kendo-formfield>
|
||||||
|
<kendo-label text="State"></kendo-label>
|
||||||
|
<kendo-textbox formControlName="state"></kendo-textbox>
|
||||||
|
</kendo-formfield>
|
||||||
|
|
||||||
|
<kendo-formfield>
|
||||||
|
<kendo-label text="Zip Code"></kendo-label>
|
||||||
|
<kendo-textbox formControlName="zipCode"></kendo-textbox>
|
||||||
|
</kendo-formfield>
|
||||||
|
|
||||||
|
<kendo-formfield>
|
||||||
|
<kendo-label text="Country"></kendo-label>
|
||||||
|
<kendo-textbox formControlName="country"></kendo-textbox>
|
||||||
|
</kendo-formfield>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
</kendo-tabstrip-tab>
|
||||||
|
|
||||||
|
<!-- TAB 3: Church Info -->
|
||||||
|
<kendo-tabstrip-tab title="Church Info">
|
||||||
|
<ng-template kendoTabContent>
|
||||||
|
<div class="k-form k-form-horizontal k-mt-4">
|
||||||
|
|
||||||
|
<kendo-formfield>
|
||||||
|
<kendo-label text="Join Date"></kendo-label>
|
||||||
|
<kendo-datepicker formControlName="joinDate"></kendo-datepicker>
|
||||||
|
</kendo-formfield>
|
||||||
|
|
||||||
|
<kendo-formfield>
|
||||||
|
<kendo-label text="Baptism Date"></kendo-label>
|
||||||
|
<kendo-datepicker formControlName="baptismDate"></kendo-datepicker>
|
||||||
|
</kendo-formfield>
|
||||||
|
|
||||||
|
<kendo-formfield>
|
||||||
|
<kendo-label text="Baptism Church"></kendo-label>
|
||||||
|
<kendo-textbox formControlName="baptismChurch"></kendo-textbox>
|
||||||
|
</kendo-formfield>
|
||||||
|
|
||||||
|
<kendo-formfield>
|
||||||
|
<kendo-label text="Notes"></kendo-label>
|
||||||
|
<kendo-textarea formControlName="notes" [rows]="4"></kendo-textarea>
|
||||||
|
</kendo-formfield>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
</kendo-tabstrip-tab>
|
||||||
|
|
||||||
|
</kendo-tabstrip>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<kendo-dialog-actions>
|
||||||
|
<button kendoButton (click)="onCancel()">Cancel</button>
|
||||||
|
<button kendoButton themeColor="primary" (click)="onSubmit()" [disabled]="form.invalid">
|
||||||
|
{{ isEditMode ? 'Save Changes' : 'Add Member' }}
|
||||||
|
</button>
|
||||||
|
</kendo-dialog-actions>
|
||||||
|
</kendo-dialog>
|
||||||
+85
@@ -0,0 +1,85 @@
|
|||||||
|
import { Component, Input, Output, EventEmitter, OnInit } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { FormBuilder, FormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
|
||||||
|
import { DialogsModule } from '@progress/kendo-angular-dialog';
|
||||||
|
import { InputsModule } from '@progress/kendo-angular-inputs';
|
||||||
|
import { LabelModule } from '@progress/kendo-angular-label';
|
||||||
|
import { DropDownsModule } from '@progress/kendo-angular-dropdowns';
|
||||||
|
import { DateInputsModule } from '@progress/kendo-angular-dateinputs';
|
||||||
|
import { LayoutModule } from '@progress/kendo-angular-layout';
|
||||||
|
import { ButtonsModule } from '@progress/kendo-angular-buttons';
|
||||||
|
import { MemberDto, CreateMemberRequest } from '../../models/member.model';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-member-form-dialog',
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
CommonModule, ReactiveFormsModule, DialogsModule, InputsModule,
|
||||||
|
LabelModule, DropDownsModule, DateInputsModule, LayoutModule, ButtonsModule
|
||||||
|
],
|
||||||
|
templateUrl: './member-form-dialog.component.html',
|
||||||
|
})
|
||||||
|
export class MemberFormDialogComponent implements OnInit {
|
||||||
|
@Input() member: MemberDto | null = null; // null = create mode
|
||||||
|
@Output() saved = new EventEmitter<CreateMemberRequest>();
|
||||||
|
@Output() cancelled = new EventEmitter<void>();
|
||||||
|
|
||||||
|
form!: FormGroup;
|
||||||
|
isEditMode = false;
|
||||||
|
|
||||||
|
readonly statusOptions = ['Member', 'Visitor', 'Inactive', 'Former'];
|
||||||
|
readonly genderOptions = [
|
||||||
|
{ text: 'Male', value: 'M' },
|
||||||
|
{ text: 'Female', value: 'F' },
|
||||||
|
{ text: 'Other', value: 'Other' },
|
||||||
|
];
|
||||||
|
readonly langOptions = [
|
||||||
|
{ text: 'English', value: 'en' },
|
||||||
|
{ text: '中文', value: 'zh-TW' },
|
||||||
|
];
|
||||||
|
|
||||||
|
constructor(private fb: FormBuilder) {}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.isEditMode = this.member !== null;
|
||||||
|
this.form = this.fb.group({
|
||||||
|
// Basic Info
|
||||||
|
firstName_en: [this.member?.firstName_en ?? '', [Validators.required, Validators.maxLength(100)]],
|
||||||
|
lastName_en: [this.member?.lastName_en ?? '', [Validators.required, Validators.maxLength(100)]],
|
||||||
|
nickName: [this.member?.nickName ?? null, Validators.maxLength(100)],
|
||||||
|
firstName_zh: [this.member?.firstName_zh ?? null, Validators.maxLength(100)],
|
||||||
|
lastName_zh: [this.member?.lastName_zh ?? null, Validators.maxLength(100)],
|
||||||
|
gender: [this.member?.gender ?? null],
|
||||||
|
dateOfBirth: [this.member?.dateOfBirth ?? null],
|
||||||
|
status: [this.member?.status ?? 'Member', Validators.required],
|
||||||
|
languagePreference: [this.member?.languagePreference ?? 'en', Validators.required],
|
||||||
|
// Contact
|
||||||
|
email: [this.member?.email ?? null, [Validators.email, Validators.maxLength(200)]],
|
||||||
|
phoneCell:[this.member?.phoneCell ?? null, Validators.maxLength(30)],
|
||||||
|
phoneHome:[this.member?.phoneHome ?? null, Validators.maxLength(30)],
|
||||||
|
address: [this.member?.address ?? null, Validators.maxLength(500)],
|
||||||
|
city: [this.member?.city ?? null, Validators.maxLength(100)],
|
||||||
|
state: [this.member?.state ?? null, Validators.maxLength(50)],
|
||||||
|
zipCode: [this.member?.zipCode ?? null, Validators.maxLength(20)],
|
||||||
|
country: [this.member?.country ?? 'USA', Validators.maxLength(100)],
|
||||||
|
// Church Info
|
||||||
|
joinDate: [this.member?.joinDate ?? null],
|
||||||
|
baptismDate: [this.member?.baptismDate ?? null],
|
||||||
|
baptismChurch:[this.member?.baptismChurch ?? null, Validators.maxLength(200)],
|
||||||
|
notes: [this.member?.notes ?? null],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get title(): string {
|
||||||
|
return this.isEditMode ? 'Edit Member' : 'Add Member';
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmit(): void {
|
||||||
|
if (this.form.invalid) { this.form.markAllAsTouched(); return; }
|
||||||
|
this.saved.emit(this.form.value as CreateMemberRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
onCancel(): void {
|
||||||
|
this.cancelled.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user