openaire-library/monitor-admin/umbrella/umbrella.component.ts

383 lines
16 KiB
TypeScript

import {ChangeDetectorRef, Component, OnInit, ViewChild} from "@angular/core";
import {StakeholderBaseComponent} from "../utils/stakeholder-base.component";
import {ActivatedRoute, Router} from "@angular/router";
import {Title} from "@angular/platform-browser";
import {StakeholderService} from "../../monitor/services/stakeholder.service";
import {ManageStakeholders, Stakeholder, StakeholderType, Umbrella} from "../../monitor/entities/stakeholder";
import {Session, User} from "../../login/utils/helper.class";
import {UserManagementService} from "../../services/user-management.service";
import {FormBuilder, UntypedFormGroup, Validators} from "@angular/forms";
import {AlertModal} from "../../utils/modal/alert";
import {NotificationHandler} from "../../utils/notification-handler";
import {Option} from "../../sharedComponents/input/input.component";
import {IDeactivateComponent} from "../../utils/can-exit.guard";
import {FullScreenModalComponent} from "../../utils/modal/full-screen-modal/full-screen-modal.component";
import {map} from "rxjs/operators";
import {StakeholderCategory} from "../utils/indicator-utils";
import {HelperFunctions} from "../../utils/HelperFunctions.class";
import {properties} from "../../../../environments/environment";
import {TransitionGroupComponent} from "../../utils/transition-group/transition-group.component";
declare var UIkit;
@Component({
selector: 'umbrella',
template: `
<div page-content>
<div header class="uk-margin-medium-top">
<ul #typesGroup *ngIf="umbrella" class="uk-tab uk-margin-xsmall-top" transition-group>
<ng-container *ngFor="let type of umbrella.types; let i=index">
<li class="uk-visible-toggle uk-flex" [class.uk-active]="activeIndex === i" transition-group-item>
<a (click)="chooseType(i)">
<span class="uk-text-uppercase">{{ stakeholderUtils.entities[type] }}</span>
</a>
<div class="uk-flex uk-flex-column uk-flex-center uk-margin-small-left"
[class.uk-invisible-hover]="activeIndex !== i"
(click)="$event.stopPropagation();$event.preventDefault()">
<a class="uk-link-reset uk-flex uk-flex-middle">
<icon [flex]="true" name="more_vert"></icon>
</a>
<div #element
uk-dropdown="mode: click; pos: bottom-left; offset: 5; delay-hide: 0; container: body">
<ul class="uk-nav uk-dropdown-nav">
<li *ngIf="i > 0">
<a (click)="hide(element);moveType(i)">
<div class="uk-flex uk-flex-middle">
<icon [flex]="true" name="west" ratio="0.6"></icon>
<span class="uk-margin-small-left uk-width-expand">Move Left</span>
</div>
</a>
</li>
<li *ngIf="i < umbrella.types.length - 1">
<a (click)="hide(element);moveType(i, i + 1)">
<div class="uk-flex uk-flex-middle">
<icon [flex]="true" name="east" ratio="0.6"></icon>
<span class="uk-margin-small-left uk-width-expand">Move Right</span>
</div>
</a>
</li>
<li *ngIf="i > 0 || i < umbrella.types.length - 1" class="uk-nav-divider"></li>
<li>
<a (click)="deleteTypeOpen(i); hide(element)">
<div class="uk-flex uk-flex-middle">
<icon [flex]="true" name="delete" ratio="0.6"></icon>
<span class="uk-margin-small-left uk-width-expand">Remove</span>
</div>
</a>
</li>
</ul>
</div>
</div>
</li>
</ng-container>
<li *ngIf="isCurator && types.length > 0">
<a (click)="addTypeOpen(); $event.preventDefault()" class="uk-flex uk-flex-middle">
<icon name="add" [flex]="true"></icon>
<span class="uk-text-uppercase">Add type</span>
</a>
</li>
</ul>
</div>
<div actions class="uk-flex uk-flex-right@m uk-flex-center">
<button *ngIf="activeType" class="uk-button uk-button-primary" (click)="manageStakeholdersOpen()">
Manage {{ entities.stakeholders }}
</button>
</div>
<div inner class="uk-section">
<div *ngIf="children == null" class="message">
<h6>No types yet. Add a type to start.</h6>
</div>
<div *ngIf="children != null" uk-height-match="target: .titleContainer; row: false">
<div uk-height-match="target: .logoContainer; row: false">
<filtered-stakeholders [remove]="true" (removed)="removeStakeholder($event)"
[keyword]="keyword" [stakeholders]="children">
</filtered-stakeholders>
</div>
</div>
</div>
</div>
<modal-alert #deleteTypeModal classTitle="uk-background-primary uk-light" (alertOutput)="deleteType()"
[overflowBody]="false">
<div [class.uk-invisible]="loading" class="uk-position-relative">
<div *ngIf="loading">
<loading class="uk-position-center"></loading>
</div>
You are about to remove <span class="uk-text-bold">{{ entities[umbrella.types[index]] }}</span> from the
umbrella of {{ stakeholder.name }}.
All the profiles added to this type will be removed too.
Are you sure you want to proceed?
</div>
</modal-alert>
<modal-alert #addTypeModal classTitle="uk-background-primary uk-light" (alertOutput)="addType()"
[okDisabled]="updateFb && (updateFb.invalid || updateFb.pristine)">
<div *ngIf="loading" class="uk-position-relative uk-height-large">
<loading class="uk-position-center"></loading>
</div>
<div *ngIf="updateFb" [class.uk-hidden]="loading"
class="uk-grid uk-padding uk-padding-remove-horizontal uk-child-width-1-1" [formGroup]="updateFb"
uk-grid>
<div input [formInput]="updateFb.get('type')" class="uk-width-1-1"
placeholder="Type" [options]="types" type="select"></div>
</div>
</modal-alert>
<fs-modal #manageStakeholdersModal>
<div *ngIf="loading" class="uk-position-relative uk-height-large">
<loading class="uk-position-center"></loading>
</div>
<ng-container *ngIf="!loading && manageStakeholders">
<div class="uk-section-xsmall">
<div class="uk-flex uk-flex-center uk-flex-wrap uk-flex-middle uk-flex-right@m">
<div search-input [(value)]="keyword" [expandable]="true"
[disabled]="loading" [placeholder]="'Search ' + entities.stakeholders"
searchInputClass="outer"
class="uk-width-1-3@xl uk-width-2-5@l uk-width-1-2@m uk-width-1-1 uk-flex uk-flex-right"></div>
</div>
</div>
<div uk-height-match="target: .titleContainer; row: false">
<div uk-height-match="target: .logoContainer; row: false">
<filtered-stakeholders *ngFor="let category of categories" [add]="true"
(added)="addStakeholder($event)"
[stakeholderCategory]="category" [remove]="true"
(removed)="removeStakeholder($event)"
[keyword]="keyword" [(stakeholders)]="manageStakeholders[category.value]">
</filtered-stakeholders>
</div>
</div>
</ng-container>
</fs-modal>
`
})
export class UmbrellaComponent extends StakeholderBaseComponent implements OnInit, IDeactivateComponent {
public loading: boolean = false;
public stakeholder: Stakeholder;
public user: User;
public types: Option[] = [];
public manageStakeholders: ManageStakeholders;
public activeIndex: number = 0;
public index: number;
public updateFb: UntypedFormGroup;
public keyword: string;
@ViewChild('addTypeModal', {static: true}) addTypeModal: AlertModal;
@ViewChild('deleteTypeModal', {static: true}) deleteTypeModal: AlertModal;
@ViewChild('manageStakeholdersModal', {static: true}) manageStakeholdersModal: FullScreenModalComponent;
@ViewChild('typesGroup') typesGroup: TransitionGroupComponent;
constructor(protected _route: ActivatedRoute,
protected _router: Router,
protected _title: Title,
private fb: FormBuilder,
private userManagementService: UserManagementService,
private stakeholderService: StakeholderService,
private cdr: ChangeDetectorRef) {
super();
}
ngOnInit(): void {
this.subscriptions.push(this.userManagementService.getUserInfo().subscribe(user => {
this.user = user;
}));
this.subscriptions.push(this.stakeholderService.getStakeholderAsObservable().subscribe(stakeholder => {
if (stakeholder) {
this.stakeholder = stakeholder;
if (!this.stakeholder.umbrella) {
this.navigateToError();
} else {
this.umbrella = stakeholder.umbrella;
}
this.title = stakeholder.name + " | Manage Umbrella";
this.setMetadata();
}
}));
}
canExit(): boolean {
this.stakeholderService.setStakeholder(this.stakeholder);
return true;
}
resetUpdateForm(action: "ADD" | "REMOVE" | "UPDATE" = "ADD", type: StakeholderType = null, child: string = null): void {
this.updateFb = this.fb.group({
type: this.fb.control(type, Validators.required),
action: this.fb.control(action, Validators.required),
});
if (child) {
this.updateFb.addControl("child", this.fb.control(child, Validators.required));
}
}
resetUpdateFormForReorder(index: number, newIndex: number = index - 1) {
let types = HelperFunctions.copy(this.umbrella.types);
HelperFunctions.swap(types, index, newIndex);
this.updateFb = this.fb.group({
types: this.fb.control(types, Validators.required),
action: this.fb.control("UPDATE", Validators.required)
});
}
addTypeOpen(): void {
this.resetUpdateForm();
this.addTypeModal.cancelButtonText = 'Cancel';
this.addTypeModal.okButtonLeft = false;
this.addTypeModal.alertMessage = false;
this.addTypeModal.alertTitle = 'Add a type';
this.addTypeModal.stayOpen = true;
this.addTypeModal.open();
}
deleteTypeOpen(index: number): void {
this.index = index;
this.resetUpdateForm("REMOVE", this.umbrella.types[this.index]);
this.deleteTypeModal.cancelButtonText = 'No';
this.deleteTypeModal.okButtonText = 'Yes';
this.deleteTypeModal.alertTitle = 'Remove ' + this.umbrella.types[this.index];
this.deleteTypeModal.stayOpen = true;
this.deleteTypeModal.open();
}
addType() {
this.loading = true;
this.updateUmbrella((umbrella: Umbrella) => {
this.addTypeModal.cancel();
this.umbrella = umbrella;
}, () => {
this.addTypeModal.cancel();
});
}
deleteType() {
this.loading = true;
this.updateUmbrella((umbrella: Umbrella) => {
this.deleteTypeModal.cancel();
this.umbrella = umbrella;
}, () => {
this.deleteTypeModal.cancel();
});
}
addStakeholder(id: string) {
this.resetUpdateForm('ADD', this.activeType, id);
this.updateUmbrella((umbrella: Umbrella) => {
this.umbrella = umbrella;
});
}
removeStakeholder(id: string) {
this.resetUpdateForm('REMOVE', this.activeType, id);
this.updateUmbrella((umbrella: Umbrella) => {
this.umbrella = umbrella;
});
}
public moveType(index: number, newIndex: number = index - 1): void {
this.resetUpdateFormForReorder(index, newIndex);
this.typesGroup.init();
this.updateUmbrella( () => {
HelperFunctions.swap(this.umbrella.types, index, newIndex);
});
}
public manageStakeholdersOpen() {
this.manageStakeholdersModal.title = 'Manage ' + this.entities.stakeholders;
this.manageStakeholdersModal.okButtonText = "Done";
this.manageStakeholdersModal.okButton = true;
this.setManageStakeholders();
this.manageStakeholdersModal.open();
}
setManageStakeholders() {
this.loading = true;
this.subscriptions.push(this.stakeholderService.getMyStakeholders(this.properties.monitorServiceAPIURL, this.activeType).pipe(map(manageStakeholders => {
delete manageStakeholders.templates;
delete manageStakeholders.umbrella;
return manageStakeholders;
})).subscribe(manageStakeholders => {
this.filterManagedStakeholders(manageStakeholders);
this.manageStakeholders.standalone.sort(this.sort);
this.manageStakeholders.dependent.sort(this.sort);
this.loading = false;
}));
}
filterManagedStakeholders(manageStakeholders: ManageStakeholders) {
manageStakeholders.standalone.forEach(stakeholder => {
stakeholder['added'] = this.children.findIndex(child => child._id === stakeholder._id) !== -1;
});
manageStakeholders.dependent.forEach(stakeholder => {
stakeholder['added'] = this.children.findIndex(child => child._id === stakeholder._id) !== -1;
});
this.manageStakeholders = manageStakeholders;
}
sort(a: any, b: any): number {
if (a['added'] && !b['added']) {
return -1;
} else if (!a['added'] && b['added']) {
return 1;
} else {
return 0
}
}
updateUmbrella(successFn: Function = null, errorFn: Function = null): void {
this.subscriptions.push(this.stakeholderService.updateUmbrella(this.properties.monitorServiceAPIURL, this.stakeholder._id, this.updateFb.getRawValue())
.subscribe(umbrella => {
this.loading = false;
if(!this.activeType) {
this.activeIndex = 0;
}
if(successFn) {
successFn(umbrella);
}
if(this.manageStakeholders) {
this.filterManagedStakeholders(this.manageStakeholders);
}
this.cdr.detectChanges();
}, error => {
this.loading = false;
if(errorFn) {
errorFn();
}
NotificationHandler.rise(error.error.message, 'danger');
}));
}
hide(element: any) {
UIkit.dropdown(element).hide();
}
chooseType(index: number) {
this.activeIndex = index;
}
get umbrella() {
return this.stakeholder.umbrella;
}
get activeType(): StakeholderType {
return this.umbrella.types[this.activeIndex];
}
set umbrella(umbrella) {
this.stakeholder.umbrella = HelperFunctions.copy(umbrella);
this.types = this.stakeholderUtils.types.filter(type => !umbrella.types.includes(type.value));
}
get isCurator(): boolean {
return Session.isPortalAdministrator(this.user) || Session.isCurator(this.stakeholder.type, this.user);
}
get children(): Stakeholder[] {
if (this.activeType) {
return this.umbrella.children[this.activeType].map(stakeholder => {
stakeholder['added'] = true;
return stakeholder;
});
}
return null;
}
get categories(): StakeholderCategory[] {
return this.stakeholderUtils.stakeholderCategories.filter(category => category.value === 'standalone' || category.value === 'dependent');
}
}