import { Component, Inject } from "@angular/core"; import { AbstractControl, FormBuilder, FormControl, FormGroup, FormsModule, ReactiveFormsModule, ValidationErrors, Validators, } from "@angular/forms"; import { OrganizationUserApiService } from "@bitwarden/admin-console/common"; import { JslibModule } from "@bitwarden/angular/jslib.module"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { PlanSponsorshipType } from "@bitwarden/common/billing/enums"; import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { OrgKey } from "@bitwarden/common/types/key"; import { DialogRef, ButtonModule, DialogConfig, DIALOG_DATA, DialogModule, DialogService, FormFieldModule, ToastService, } from "@bitwarden/components"; interface RequestSponsorshipForm { sponsorshipEmail: FormControl; sponsorshipNote: FormControl; } interface AddSponsorshipDialogParams { organizationId: string; organizationKey: OrgKey; } @Component({ templateUrl: "add-sponsorship-dialog.component.html", standalone: true, imports: [ JslibModule, ButtonModule, DialogModule, FormsModule, ReactiveFormsModule, FormFieldModule, ], }) export class AddSponsorshipDialogComponent { sponsorshipForm: FormGroup; loading = false; organizationId: string; organizationKey: OrgKey; constructor( private dialogRef: DialogRef, private formBuilder: FormBuilder, private i18nService: I18nService, private organizationUserApiService: OrganizationUserApiService, private toastService: ToastService, private apiService: ApiService, private encryptService: EncryptService, @Inject(DIALOG_DATA) protected dialogParams: AddSponsorshipDialogParams, ) { this.organizationId = this.dialogParams?.organizationId; this.organizationKey = this.dialogParams.organizationKey; this.sponsorshipForm = this.formBuilder.group({ sponsorshipEmail: new FormControl("", { validators: [Validators.email, Validators.required], asyncValidators: [this.isOrganizationMember.bind(this)], updateOn: "change", }), sponsorshipNote: new FormControl("", { validators: [Validators.maxLength(1000)], }), }); } static open(dialogService: DialogService, config: DialogConfig) { return dialogService.open(AddSponsorshipDialogComponent, { ...config, data: config.data, } as unknown as DialogConfig); } protected async save() { this.sponsorshipEmailControl.markAllAsTouched(); if (this.sponsorshipForm.invalid) { return; } this.loading = true; try { const notes = this.sponsorshipForm.value.sponsorshipNote || ""; const email = this.sponsorshipForm.value.sponsorshipEmail || ""; const encryptedNotes = await this.encryptService.encryptString(notes, this.organizationKey); const isAdminInitiated = true; await this.apiService.postCreateSponsorship(this.organizationId, { sponsoredEmail: email, planSponsorshipType: PlanSponsorshipType.FamiliesForEnterprise, friendlyName: email, isAdminInitiated, notes: encryptedNotes.encryptedString, }); this.toastService.showToast({ variant: "success", title: undefined, message: this.i18nService.t("sponsorshipCreated"), }); await this.resetForm(); } catch (e: any) { this.toastService.showToast({ variant: "error", title: this.i18nService.t("errorOccurred"), message: e?.message || this.i18nService.t("unexpectedError"), }); } this.loading = false; this.dialogRef.close(); } private async resetForm() { this.sponsorshipForm.reset(); } get sponsorshipEmailControl() { return this.sponsorshipForm.controls.sponsorshipEmail; } get sponsorshipNoteControl() { return this.sponsorshipForm.controls.sponsorshipNote; } private async isOrganizationMember(control: AbstractControl): Promise { const value = control.value; const users = await this.organizationUserApiService.getAllMiniUserDetails(this.organizationId); const userExists = users.data.some( (member) => member.email.toLowerCase() === value.toLowerCase(), ); if (userExists) { return { isOrganizationMember: { message: this.i18nService.t("organizationHasMemberMessage", value), }, }; } return null; } }