import { Component, OnDestroy, OnInit } from '@angular/core'; import { Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { AdminUsersService } from '@core/services/admin-users.service'; import { SpinnerService } from '@core/services/spinner.service'; import { FooterState } from '@core/states/footer.state'; import { APIAdminClient } from '@core/typings/api/admin-client.typing'; import { AdaptedAdminUser, AdminFromSearch, AdminUserPermissions } from '@core/typings/user.typing'; import { AdminClientService } from '@features/platform-admin/clients/admin-client.service'; import { ArrayHelpersService, AutoTableRepository, AutoTableRepositoryFactory, SelectOption, TypeaheadSelectOption, TypeSafeFormBuilder, TypeSafeFormGroup, ValueComparisonService } from '@yourcause/common'; import { I18nService } from '@yourcause/common/i18n'; import { NotifierService } from '@yourcause/common/notifier'; import { Subscription } from 'rxjs'; interface InternalAdminGroup { clientZones: number[]; roles: number[]; allClients: boolean; selectedAdminEmail: string; } @Component({ selector: 'gc-internal-admins-create-edit', templateUrl: './internal-admins-create-edit.component.html', styleUrls: ['./internal-admins-create-edit.component.scss'] }) export class InternalAdminsCreateEditComponent implements OnInit, OnDestroy { userId = this.activatedRoute.snapshot.params.userId; newUser = !this.userId; userDetail: AdaptedAdminUser; formGroup: TypeSafeFormGroup; ready = false; loading = false; title = ''; selectedAdmin: AdminFromSearch; adminAlreadyExists = false; selectedClientZones: number[] = []; clientsMap = this.adminClientService.clientsMap; clientAccessRepository: AutoTableRepository; sub = new Subscription(); roleOptions: SelectOption[] = this.adminUsersService.roles.map(role => { return { value: role.id, display: role.name }; }); // set this to only clients they are able to access. clientOptions: TypeaheadSelectOption[] = this.adminClientService.clients.map((client) => ({ label: client.name, value: client.clientId })); constructor ( private adminClientService: AdminClientService, private activatedRoute: ActivatedRoute, private autoTableFactory: AutoTableRepositoryFactory, private footerState: FooterState, private router: Router, private i18n: I18nService, private notifierService: NotifierService, private valueComparisonService: ValueComparisonService, private arrayHelper: ArrayHelpersService, private spinner: SpinnerService, private adminUsersService: AdminUsersService, private formBuilder: TypeSafeFormBuilder ) { this.footerState .set('footerState', this.footerState.FOOTER_STATES.ACTION) .set('footerAction', async () => { this.footerState.set('footerActionDisabled', true); await this.saveAdmin(); this.footerState.set('footerActionDisabled', false); }); this.footerState.set('footerActionLabel', i18n.translate('common:btnSave')); this.footerState.set('footerSecondaryLabel', i18n.translate('common:btnCancel')); this.footerState.set('footerSecondaryAction', () => this.navigateBack()); } get clients (): APIAdminClient.Client[] { return this.adminClientService && this.adminClientService.clients ? this.adminClientService.clients : []; } get canAccessAllClientZones () { if (this.formGroup && this.formGroup.value.roles) { const roles = this.formGroup.value.roles; const foundRoles = this.adminUsersService.roles.filter(role => roles.includes(role.id)); const allPermissions = foundRoles.reduce((acc, role) => { return [ ...acc, ...role.permissions ]; }, []); if (allPermissions.includes(AdminUserPermissions.CanAccessAllClientZones)) { return true; } else { return false; } } return false; } async ngOnInit () { this.spinner.startSpinner(); if (!this.newUser) { this.userDetail = await this.adminUsersService.getAdminDetail(this.userId); this.selectedAdmin = { firstName: this.userDetail.firstName, lastName: this.userDetail.lastName, email: this.userDetail.email, location: '' }; } this.setupForm(); if (this.newUser) { this.title = this.i18n.translate( 'ADMIN:hdrAddInternalAdmin', {}, 'Add Internal Admin' ); } else { this.title = this.i18n.translate( 'ADMIN:hdrEditInternalAdmin', {}, 'Edit Internal Admin' ); } this.checkValidity(); this.ready = true; this.spinner.stopSpinner(); } setupForm () { let rows: number[] = []; if (!this.newUser && this.userDetail) { rows = this.sortClientZones(this.userDetail.clientZoneIds); } this.formGroup = this.formBuilder.group({ clientZones: [ rows ], roles: [ this.userDetail ? this.userDetail.roleIds : [], Validators.required ], allClients: false, selectedAdminEmail: this.userDetail?.email || '' }); this.sub.add(this.formGroup.valueChanges.subscribe(() => { this.checkValidity(); })); this.clientAccessRepository = this.autoTableFactory.create({ key: 'CLIENT_ACCESS', columns: [], notifier: this.notifierService, rowsPerPage: 8, valueComparisonService: this.valueComparisonService, rows }); this.sub.add(this.clientAccessRepository.loading.subscribe((val) => { this.loading = val; })); this.setSelectedClientZones(); } setSelectedClientZones () { this.selectedClientZones = this.formGroup.value.clientZones || []; if (this.clientAccessRepository) { this.clientAccessRepository.rows = this.sortClientZones(this.selectedClientZones); this.clientAccessRepository.reset(); } } showClientAccessList () { return this.clientAccessRepository?.currentSet?.length && !this.formGroup.value.allClients && !this.canAccessAllClientZones; } sortClientZones (zones: number[]) { const foundClients = this.arrayHelper.sort( zones.filter((id) => { return this.clientsMap[id]; }).map((id) => { return { id, name: this.clientsMap[id].name }; }), 'name'); return foundClients.map((client) => { return client.id; }); } revokeClient (clientId: number) { const index = this.formGroup.value.clientZones.findIndex((id: number) => { return id === clientId; }); if (index > -1) { const newClientZones = [ ...this.formGroup.value.clientZones.slice(0, index), ...this.formGroup.value.clientZones.slice(index + 1) ]; this.formGroup.get('clientZones').setValue(newClientZones); } } async saveAdmin () { this.spinner.startSpinner(); let deps = null; const canManageAll = this.canAccessAllClientZones; let clientZoneIds = this.formGroup.value.clientZones; if (canManageAll) { clientZoneIds = []; } else if (this.formGroup.value.allClients) { clientZoneIds = this.adminClientService.clients.map(client => client.clientId); } const formValue = this.formGroup.value; const roleIds = formValue.roles; if (this.newUser) { deps = { firstName: this.selectedAdmin.firstName, lastName: this.selectedAdmin.lastName, email: this.selectedAdmin.email, roleIds, clientZoneIds }; } else { deps = { userId: this.userId, roleIds, clientZoneIds }; } await this.adminUsersService.saveAdminUser(deps, this.newUser); this.spinner.stopSpinner(); this.router.navigate( [`../../admins`], { relativeTo: this.activatedRoute } ); } checkValidity () { let valid = this.formGroup.valid; if (this.newUser) { valid = valid && !!this.selectedAdmin && !this.adminAlreadyExists; } this.footerState.set('footerActionDisabled', !valid); } onAdminSelect (admin: AdminFromSearch) { this.selectedAdmin = admin; const found = this.adminUsersService.admins.find((user) => { return (user.email || '').toLowerCase() === (admin?.email || '').toLowerCase(); }); this.adminAlreadyExists = !!found; this.checkValidity(); } onClearSelectedAdmin () { this.selectedAdmin = null; this.checkValidity(); } private navigateBack () { this.router.navigate( [`../../admins`], { relativeTo: this.activatedRoute } ); } ngOnDestroy () { this.sub.unsubscribe(); this.footerState.clearAll(); } }