diff --git a/APP/src/app/features/members/components/create-user-dialog/create-user-dialog.component.html b/APP/src/app/features/members/components/create-user-dialog/create-user-dialog.component.html new file mode 100644 index 0000000..5d502c1 --- /dev/null +++ b/APP/src/app/features/members/components/create-user-dialog/create-user-dialog.component.html @@ -0,0 +1,67 @@ + + + + +

Creating account for {{ memberName }}

+ +
+ + + + + Email is required. + Invalid email address. + + + + + + + + + + + + + + +

{{ errorMessage }}

+ +
+ + + + + +
+ + + +
+

Account created!

+

Share this temporary password with {{ memberName }}.

+ +
+ {{ tempPassword }} + +
+ +

+ Warning: This password will not be shown again. +

+
+ + + + +
+ +
diff --git a/APP/src/app/features/members/components/create-user-dialog/create-user-dialog.component.ts b/APP/src/app/features/members/components/create-user-dialog/create-user-dialog.component.ts new file mode 100644 index 0000000..6013fc1 --- /dev/null +++ b/APP/src/app/features/members/components/create-user-dialog/create-user-dialog.component.ts @@ -0,0 +1,92 @@ +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 { ButtonsModule } from '@progress/kendo-angular-buttons'; +import { IndicatorsModule } from '@progress/kendo-angular-indicators'; +import { MemberListItemDto, memberDisplayName } from '../../models/member.model'; +import { CreateUserRequest, CreateUserResult, ALL_ROLES } from '../../../users/models/user.model'; +import { UserApiService } from '../../../users/services/user-api.service'; + +@Component({ + selector: 'app-create-user-dialog', + standalone: true, + imports: [ + CommonModule, ReactiveFormsModule, DialogsModule, InputsModule, + LabelModule, DropDownsModule, ButtonsModule, IndicatorsModule + ], + templateUrl: './create-user-dialog.component.html', +}) +export class CreateUserDialogComponent implements OnInit { + @Input({ required: true }) member!: MemberListItemDto; + @Output() created = new EventEmitter(); + @Output() cancelled = new EventEmitter(); + + form!: FormGroup; + step: 'form' | 'success' = 'form'; + tempPassword = ''; + copied = false; + isLoading = false; + errorMessage = ''; + + readonly roleOptions: string[] = [...ALL_ROLES]; + readonly langOptions = [ + { text: 'English', value: 'en' }, + { text: '中文', value: 'zh-TW' }, + ]; + + get memberName(): string { return memberDisplayName(this.member); } + + constructor(private fb: FormBuilder, private userApi: UserApiService) {} + + ngOnInit(): void { + this.form = this.fb.group({ + email: [this.member.email ?? '', [Validators.required, Validators.email]], + roles: [['member'], Validators.required], + languagePreference: ['en'], + }); + } + + onSubmit(): void { + if (this.form.invalid) { this.form.markAllAsTouched(); return; } + this.isLoading = true; + this.errorMessage = ''; + + const request: CreateUserRequest = { + memberId: this.member.id, + email: this.form.value.email, + roles: this.form.value.roles, + languagePreference: this.form.value.languagePreference, + }; + + this.userApi.createUser(request).subscribe({ + next: (result: CreateUserResult) => { + this.tempPassword = result.tempPassword; + this.step = 'success'; + this.isLoading = false; + }, + error: (err: any) => { + this.errorMessage = err.error?.message ?? 'Failed to create account.'; + this.isLoading = false; + }, + }); + } + + copyPassword(): void { + navigator.clipboard.writeText(this.tempPassword).then(() => { + this.copied = true; + setTimeout(() => (this.copied = false), 2000); + }); + } + + onDone(): void { + this.created.emit(); + } + + onCancel(): void { + this.cancelled.emit(); + } +}