Add init link.
This commit is contained in:
+106
@@ -0,0 +1,106 @@
|
||||
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 { ButtonsModule } from '@progress/kendo-angular-buttons';
|
||||
import { IndicatorsModule } from '@progress/kendo-angular-indicators';
|
||||
import { MemberListItemDto, memberDisplayName } from '../../models/member.model';
|
||||
import { InvitationApiService } from '../../services/invitation-api.service';
|
||||
import { ToastService } from '../../../../core/services/toast.service';
|
||||
|
||||
type Step = 'needEmail' | 'generating' | 'ready';
|
||||
|
||||
@Component({
|
||||
selector: 'app-invitation-dialog',
|
||||
standalone: true,
|
||||
imports: [
|
||||
CommonModule, ReactiveFormsModule, DialogsModule, InputsModule,
|
||||
LabelModule, ButtonsModule, IndicatorsModule,
|
||||
],
|
||||
templateUrl: './invitation-dialog.component.html',
|
||||
})
|
||||
export class InvitationDialogComponent implements OnInit {
|
||||
@Input({ required: true }) member!: MemberListItemDto;
|
||||
@Output() cancelled = new EventEmitter<void>();
|
||||
|
||||
step: Step = 'generating';
|
||||
emailForm!: FormGroup;
|
||||
|
||||
link = '';
|
||||
expiresAt: string | null = null;
|
||||
copied = false;
|
||||
isSending = false;
|
||||
errorMessage = '';
|
||||
|
||||
get memberName(): string { return memberDisplayName(this.member); }
|
||||
|
||||
constructor(
|
||||
private fb: FormBuilder,
|
||||
private invitationApi: InvitationApiService,
|
||||
private toast: ToastService,
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.emailForm = this.fb.group({
|
||||
email: [this.member.email ?? '', [Validators.required, Validators.email]],
|
||||
});
|
||||
|
||||
// Auto-generate when the member already has an email; otherwise ask for one first.
|
||||
if (this.member.email) {
|
||||
this.generate();
|
||||
} else {
|
||||
this.step = 'needEmail';
|
||||
}
|
||||
}
|
||||
|
||||
/** Generate (or re-issue) the link. Uses the form email when the member has none on file. */
|
||||
generate(): void {
|
||||
if (this.step === 'needEmail') {
|
||||
if (this.emailForm.invalid) { this.emailForm.markAllAsTouched(); return; }
|
||||
}
|
||||
|
||||
const email = this.member.email ? undefined : this.emailForm.value.email;
|
||||
this.step = 'generating';
|
||||
this.errorMessage = '';
|
||||
|
||||
this.invitationApi.create(this.member.id, email).subscribe({
|
||||
next: (result) => {
|
||||
this.link = `${window.location.origin}/accept-invitation?token=${result.token}`;
|
||||
this.expiresAt = result.expiresAt;
|
||||
this.step = 'ready';
|
||||
},
|
||||
error: (err) => {
|
||||
this.errorMessage = err.error?.message ?? 'Failed to create the invitation link.';
|
||||
// Fall back to the email step so the admin can supply/correct an address.
|
||||
this.step = 'needEmail';
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
copyLink(): void {
|
||||
navigator.clipboard.writeText(this.link).then(() => {
|
||||
this.copied = true;
|
||||
setTimeout(() => (this.copied = false), 2000);
|
||||
});
|
||||
}
|
||||
|
||||
sendEmail(): void {
|
||||
this.isSending = true;
|
||||
this.invitationApi.sendEmail(this.member.id, this.link).subscribe({
|
||||
next: () => {
|
||||
this.toast.success(`Invitation emailed to ${this.memberName}.`);
|
||||
this.isSending = false;
|
||||
},
|
||||
error: (err) => {
|
||||
this.toast.error(err.error?.message ?? 'Failed to send the email.');
|
||||
this.isSending = false;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
onClose(): void {
|
||||
this.cancelled.emit();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user