From 0face4b57f291ea0168fe0d8fe32b51ebb1850d8 Mon Sep 17 00:00:00 2001 From: "k.triantafyllou" Date: Mon, 26 Jun 2023 15:09:37 +0300 Subject: [PATCH] Fix an undefined error in searchInput of Input component. Add multi emails in invitation of manager and members and optimize subscriber invite. --- .../role-users/role-users.component.html | 11 +- .../users/role-users/role-users.component.ts | 110 +++++++++++++----- sharedComponents/input/input.component.ts | 8 +- .../subscriber-invite.component.ts | 13 ++- 4 files changed, 104 insertions(+), 38 deletions(-) diff --git a/dashboard/users/role-users/role-users.component.html b/dashboard/users/role-users/role-users.component.html index cdf80b45..6fb1d94f 100644 --- a/dashboard/users/role-users/role-users.component.html +++ b/dashboard/users/role-users/role-users.component.html @@ -95,13 +95,16 @@ + [okDisabled]="!valid">
-
-
+
+
+
Separate emails with commas
+
diff --git a/dashboard/users/role-users/role-users.component.ts b/dashboard/users/role-users/role-users.component.ts index 9adb749d..665a8303 100644 --- a/dashboard/users/role-users/role-users.component.ts +++ b/dashboard/users/role-users/role-users.component.ts @@ -1,5 +1,21 @@ -import {Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges, ViewChild} from '@angular/core'; -import {UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, Validators} from '@angular/forms'; +import { + ChangeDetectorRef, + Component, + Input, + OnChanges, + OnDestroy, + OnInit, + SimpleChanges, + ViewChild +} from '@angular/core'; +import { + UntypedFormArray, + UntypedFormBuilder, + UntypedFormControl, + UntypedFormGroup, + ValidatorFn, + Validators +} from '@angular/forms'; import {AlertModal} from "../../../utils/modal/alert"; import {UserRegistryService} from "../../../services/user-registry.service"; import {EnvProperties} from "../../../utils/properties/env-properties"; @@ -9,9 +25,22 @@ import {UserManagementService} from "../../../services/user-management.service"; import {Router} from "@angular/router"; import {StringUtils} from "../../../utils/string-utils.class"; import {NotificationService} from "../../../notifications/notification.service"; -import {Subscription} from "rxjs"; +import {forkJoin, of, Subscription} from "rxjs"; import {NotificationHandler} from "../../../utils/notification-handler"; import {ClearCacheService} from "../../../services/clear-cache.service"; +import {catchError, map, tap} from "rxjs/operators"; +import notification = CKEDITOR.plugins.notification; +import {InputComponent} from "../../../sharedComponents/input/input.component"; + +class InvitationResponse { + email: string; + invitation: any; + + constructor(email, invitation) { + this.email = email; + this.invitation = invitation; + } +} @Component({ selector: 'role-users', @@ -49,7 +78,8 @@ export class RoleUsersComponent implements OnInit, OnDestroy, OnChanges { public loadActive: boolean = true; public loadPending: boolean = true; public selectedUser: string = null; - public invited: UntypedFormControl; + public emailsForm: UntypedFormArray; + public validators: ValidatorFn[] = [Validators.email]; public properties: EnvProperties = properties; public exists: boolean = true; public roleFb: UntypedFormGroup; @@ -60,6 +90,7 @@ export class RoleUsersComponent implements OnInit, OnDestroy, OnChanges { /** Search */ filterForm: UntypedFormGroup; @ViewChild('inviteModal') inviteModal: AlertModal; + @ViewChild('emailInput') emailInput: InputComponent; @ViewChild('deleteModal') deleteModal: AlertModal; @ViewChild('deletePendingModal') deletePendingModal: AlertModal; @ViewChild('createRoleModal') createRoleModal: AlertModal; @@ -69,6 +100,7 @@ export class RoleUsersComponent implements OnInit, OnDestroy, OnChanges { private clearCacheService: ClearCacheService, private notificationService: NotificationService, private router: Router, + private cdr: ChangeDetectorRef, private fb: UntypedFormBuilder) { } @@ -172,7 +204,8 @@ export class RoleUsersComponent implements OnInit, OnDestroy, OnChanges { this.inviteModal.alertTitle = 'Invite ' + this.role; this.inviteModal.okButtonLeft = false; this.inviteModal.okButtonText = 'Send'; - this.invited = this.fb.control('', [Validators.required, Validators.email]); + this.emailsForm = this.fb.array([], Validators.required); + this.cdr.detectChanges(); this.inviteModal.open(); } @@ -224,33 +257,56 @@ export class RoleUsersComponent implements OnInit, OnDestroy, OnChanges { this.loadPending = false; })); } - + + get valid() { + return this.emailsForm && this.emailsForm.valid || (this.emailInput && this.emailInput.searchControl.getRawValue() && this.emailInput.searchControl.valid); + } + invite() { + if(this.emailInput.searchControl.getRawValue() && this.emailInput.searchControl.valid) { + this.emailInput.add(null,true); + } this.showCurrent = false; this.loadPending = true; - this.selectedUser = this.invited.value; - let details = { - link: this.link, - email: this.emailComposer(this.name, this.invited.value, this.role) - } - this.subs.push(this.userRegistryService.invite(this.type, this.id, details, this.role).subscribe(invitation => { - if (!this.pending.includes(this.invited.value)) { - this.pending.push(this.invited.value); + let current = null; + let invitations = (>this.emailsForm.value).map(email => { + current = email; + return this.userRegistryService.invite(this.type, this.id, { + link: this.link, + email: this.emailComposer(this.name, email, this.role) + }, this.role).pipe(map(invitation => new InvitationResponse(email, invitation), catchError(error => { + return of(new InvitationResponse(current, null)); + }))); + }); + this.subs.push(forkJoin(invitations).subscribe(responses => { + let notifications = responses.map(response => { + if(response.invitation) { + NotificationHandler.rise(StringUtils.capitalize(this.role) + ' invitation to ' + response.email + ' has been sent'); + if (!this.pending.includes(response.email)) { + this.pending.push(response.email); + } + if(this.notificationFn) { + return this.notificationService.sendNotification(this.notificationFn(this.name, response.email, this.role, response.invitation)).pipe(map(notification => { + return notification; + }), tap(() => { + NotificationHandler.rise('A notification has been sent successfully to ' + response.email); + }), catchError( error => { + NotificationHandler.rise('An error has occurred while sending a notification to ' + response.email + '. Please try again later', 'danger'); + return of(null); + })); + } else { + return of(null); + } + } else { + NotificationHandler.rise('An error has occurred while sending the invitation mail to ' + response.email + '.Please try again later', 'danger'); + return of(null); + } + }); + this.subs.push(forkJoin(notifications).subscribe(() => { this.pendingPage = Math.ceil(this.pending.length / this.pageSize); this.filterPendingBySearch(this.filterForm.value.pending); - } - if (this.notificationFn) { - this.subs.push(this.notificationService.sendNotification(this.notificationFn(this.name, this.invited.value, this.role, invitation)).subscribe(notification => { - NotificationHandler.rise('A notification has been sent successfully'); - }, error => { - NotificationHandler.rise('An error has occurred. Please try again later', 'danger'); - })); - } - NotificationHandler.rise(StringUtils.capitalize(this.role) + ' invitation to ' + this.selectedUser + ' has been sent'); - this.loadPending = false; - }, error => { - NotificationHandler.rise('An error has occurred. Please try again later', 'danger'); - this.loadPending = false; + this.loadPending = false; + })) })); } diff --git a/sharedComponents/input/input.component.ts b/sharedComponents/input/input.component.ts index 98f4b9c4..7b889d2f 100644 --- a/sharedComponents/input/input.component.ts +++ b/sharedComponents/input/input.component.ts @@ -405,7 +405,7 @@ export class InputComponent implements OnInit, OnDestroy, AfterViewInit, OnChang } click(event: ClickEvent) { - this.focus(!event.clicked, event); + this.focus(!event.clicked); } ngOnInit() { @@ -532,8 +532,10 @@ export class InputComponent implements OnInit, OnDestroy, AfterViewInit, OnChang if (this.focused) { this.open(true); setTimeout(() => { - this.searchInput.nativeElement.focus(); - this.searchInput.nativeElement.value = value; + if(this.searchInput) { + this.searchInput.nativeElement.focus(); + this.searchInput.nativeElement.value = value; + } }, 0); } })); diff --git a/sharedComponents/subscriber-invite/subscriber-invite.component.ts b/sharedComponents/subscriber-invite/subscriber-invite.component.ts index 515fc97b..863ac1e3 100644 --- a/sharedComponents/subscriber-invite/subscriber-invite.component.ts +++ b/sharedComponents/subscriber-invite/subscriber-invite.component.ts @@ -1,4 +1,4 @@ -import {Component, Input, OnDestroy, OnInit} from "@angular/core"; +import {Component, Input, OnDestroy, OnInit, ViewChild} from "@angular/core"; import {AbstractControl, FormBuilder, FormGroup, ValidationErrors, ValidatorFn, Validators} from "@angular/forms"; import {Subscriber} from "rxjs"; import {StringUtils} from "../../utils/string-utils.class"; @@ -11,13 +11,14 @@ import {EmailService} from "../../utils/email/email.service"; import {properties} from "../../../../environments/environment"; import {CommunityInfo} from "../../connect/community/communityInfo"; import {NotificationHandler} from "../../utils/notification-handler"; +import {InputComponent} from "../input/input.component"; @Component({ selector: 'subscriber-invite', template: `
-
Separate emails with commas
@@ -61,7 +62,8 @@ export class SubscriberInviteComponent implements OnInit, OnDestroy { public validators: ValidatorFn[] = [Validators.email]; public loading: boolean = true; private subscriptions: any[] = []; - + @ViewChild('emailInput') emailInput: InputComponent; + constructor(private fb: FormBuilder, private emailService: EmailService, private communityService: CommunityService) { @@ -105,6 +107,9 @@ export class SubscriberInviteComponent implements OnInit, OnDestroy { } invite() { + if(this.emailInput.searchControl.getRawValue() && this.emailInput.searchControl.valid) { + this.emailInput.add(null,true); + } this.loading = true; this.body.paragraphs = this.inviteForm.getRawValue().message; this.email.body = Composer.formatEmailBodyForInvitation(this.body); @@ -129,6 +134,6 @@ export class SubscriberInviteComponent implements OnInit, OnDestroy { } get valid() { - return !this.loading && this.inviteForm && this.inviteForm.valid; + return !this.loading && this.inviteForm && this.inviteForm.valid || (this.emailInput && this.emailInput.searchControl.getRawValue() && this.emailInput.searchControl.valid); } }