425 lines
15 KiB
TypeScript
425 lines
15 KiB
TypeScript
import {ChangeDetectorRef, Component, OnInit, ViewChild} from '@angular/core';
|
|
import {ActivatedRoute} from '@angular/router';
|
|
import {HelpContentService} from '../../services/help-content.service';
|
|
import {FormBuilder, FormGroup, Validators} from '@angular/forms';
|
|
import {Portal} from '../../utils/entities/adminTool/portal';
|
|
import {EnvProperties} from '../../utils/properties/env-properties';
|
|
import {Session} from '../../login/utils/helper.class';
|
|
import {UserManagementService} from '../../services/user-management.service';
|
|
import {Subscriber, Subscription} from "rxjs";
|
|
import {properties} from "../../../../environments/environment";
|
|
import {StringUtils} from "../../utils/string-utils.class";
|
|
import {Title} from "@angular/platform-browser";
|
|
import {AlertModal} from '../../utils/modal/alert';
|
|
import {MenuItemExtended} from '../../sharedComponents/menu';
|
|
import {SearchInputComponent} from '../../sharedComponents/search-input/search-input.component';
|
|
import {Option} from '../../sharedComponents/input/input.component';
|
|
import {CommunityInfo} from '../../connect/community/communityInfo';
|
|
import {Stakeholder} from '../../monitor/entities/stakeholder';
|
|
import {StakeholderService} from '../../monitor/services/stakeholder.service';
|
|
import {CommunityService} from '../../connect/community/community.service';
|
|
import {ClearCacheService} from '../../services/clear-cache.service';
|
|
import {TransitionGroupComponent} from '../../utils/transition-group/transition-group.component';
|
|
import {HelperFunctions} from '../../utils/HelperFunctions.class';
|
|
import {NotificationHandler} from '../../utils/notification-handler';
|
|
|
|
@Component({
|
|
selector: 'menuSelector',
|
|
templateUrl: './menu.component.html',
|
|
styleUrls: ['./menu.component.less']
|
|
})
|
|
export class MenuComponent implements OnInit {
|
|
|
|
@ViewChild('searchInputComponent') searchInputComponent: SearchInputComponent;
|
|
@ViewChild('editModal') editModal: AlertModal;
|
|
@ViewChild('deleteModal') deleteModal: AlertModal;
|
|
@ViewChild("elements") elements: TransitionGroupComponent;
|
|
@ViewChild("subElements") subElements: TransitionGroupComponent;
|
|
|
|
private index: number;
|
|
|
|
public menuItemForm: FormGroup;
|
|
public pageForm: FormGroup;
|
|
public menuTypes = [
|
|
{label: 'Normal Menu', value: 'normalMenu'},
|
|
{label: 'Custom Menu', value: 'customMenu'}
|
|
];
|
|
public selectedMenuType = this.menuTypes[0].value;
|
|
public normalMenuItems: MenuItemExtended[] = [];
|
|
public featuredMenuItems: MenuItemExtended[] = [];
|
|
public allPages = [];
|
|
public parentOptions: Option[] = [];
|
|
public pageStatus: Map<string,boolean> = null;
|
|
|
|
public selectedMenuItem: string;
|
|
public selectedMenuItemParent: string;
|
|
public isChild: boolean = false;
|
|
|
|
public showNormalMenu: boolean = false;
|
|
public showFeaturedMenu: boolean = false;
|
|
|
|
public communities: Portal[] = [];
|
|
public portal: string;
|
|
public name: string;
|
|
public entity: CommunityInfo | Stakeholder;
|
|
public showLogo: boolean = true;
|
|
public type: any;
|
|
|
|
public showLoading = true;
|
|
public isPortalAdministrator = null;
|
|
public filterForm: FormGroup;
|
|
public typeOptions: Option[] = [
|
|
{label: 'Internal page', value: 'internal'},
|
|
{label: 'External URL', value: 'external'},
|
|
]
|
|
public rootOnlyTypeOptions: Option[] = [
|
|
{label: 'No Action', value: 'noAction'}
|
|
]
|
|
|
|
public properties: EnvProperties = properties;
|
|
private subscriptions: any[] = [];
|
|
private typeSub: Subscription = null;
|
|
|
|
constructor(private route: ActivatedRoute,
|
|
private title: Title,
|
|
private _helpContentService: HelpContentService,
|
|
private userManagementService: UserManagementService, private _fb: FormBuilder,
|
|
private stakeholderService: StakeholderService,
|
|
private communityService: CommunityService,
|
|
private _clearCacheService: ClearCacheService,
|
|
private cdr: ChangeDetectorRef) {
|
|
}
|
|
|
|
ngOnInit() {
|
|
this.userManagementService.getUserInfo().subscribe(user => {
|
|
this.portal = (this.route.snapshot.data.portal) ? this.route.snapshot.data.portal : this.route.snapshot.params[this.route.snapshot.data.param];
|
|
this.getMenuItems();
|
|
if (this.route.snapshot.data.portal) {
|
|
this.name = StringUtils.capitalize(this.portal);
|
|
this.title.setTitle(StringUtils.capitalize(this.portal) + ' | Menu');
|
|
} else if (this.route.snapshot.params[this.route.snapshot.data.param]) {
|
|
this.type = this.route.snapshot.data.param;
|
|
if(this.route.snapshot.data.param === 'stakeholder') {
|
|
this.subscriptions.push(this.stakeholderService.getStakeholderAsObservable().subscribe(stakeholder => {
|
|
if(stakeholder) {
|
|
this.name = stakeholder.name;
|
|
this.entity = stakeholder;
|
|
this.title.setTitle(this.name + ' | Menu');
|
|
}
|
|
}));
|
|
} else {
|
|
this.subscriptions.push(this.communityService.getCommunityAsObservable().subscribe(community => {
|
|
if(community) {
|
|
this.showLogo = false;
|
|
this.name = community.shortTitle;
|
|
this.entity = community;
|
|
this.title.setTitle(this.name + ' | Menu');
|
|
}
|
|
}));
|
|
}
|
|
} else {
|
|
this.title.setTitle('Administrator Dashboard | Menu');
|
|
}
|
|
this.isPortalAdministrator = Session.isPortalAdministrator(user);
|
|
this.selectedMenuType = this.isPortalAdministrator ? this.menuTypes[0].value : this.menuTypes[1].value;
|
|
});
|
|
}
|
|
|
|
ngOnDestroy(): void {
|
|
this.subscriptions.forEach(value => {
|
|
if (value instanceof Subscriber) {
|
|
value.unsubscribe();
|
|
} else if (value instanceof Function) {
|
|
value();
|
|
}
|
|
});
|
|
this.destroyTypeSubscription();
|
|
}
|
|
|
|
destroyTypeSubscription() {
|
|
if(this.typeSub instanceof Subscriber) {
|
|
this.typeSub.unsubscribe();
|
|
}
|
|
}
|
|
|
|
getMenuItems() {
|
|
this.subscriptions.push(
|
|
this._helpContentService.getMenuItems(this.portal).subscribe(
|
|
data => {
|
|
this.featuredMenuItems = data.featuredMenuItems;
|
|
this.normalMenuItems = data.menuItems;
|
|
this.showFeaturedMenu = data.isFeaturedMenuEnabled;
|
|
this.showNormalMenu = data.isMenuEnabled;
|
|
this.getPages();
|
|
this.getParentOptions();
|
|
this.showLoading = false;
|
|
},
|
|
error => this.handleError("Server error fetching menu items", error)
|
|
)
|
|
);
|
|
}
|
|
|
|
getTypeOptions(isFeatured: boolean = false, parentItem) {
|
|
if(this.isChild || parentItem != '') {
|
|
return this.typeOptions;
|
|
} else {
|
|
if(isFeatured || !this.isPortalAdministrator) {
|
|
return this.typeOptions;
|
|
} else {
|
|
return this.typeOptions.concat(this.rootOnlyTypeOptions);
|
|
}
|
|
}
|
|
}
|
|
|
|
getPages() {
|
|
this.subscriptions.push(
|
|
this._helpContentService.getCommunityPagesByType(this.portal, '', this.properties.adminToolsAPIURL).subscribe(
|
|
data => {
|
|
let pages = data;
|
|
this.pageStatus = new Map();
|
|
for(let i = 0; i < pages.length; i++) {
|
|
if(pages[i] && pages[i].name && pages[i].route) {
|
|
this.allPages.push({value: pages[i].route, label: pages[i].name + (pages[i].isEnabled ? '' : ' [disabled]'), isEnabled: pages[i].isEnabled});
|
|
this.pageStatus.set(pages[i].route, pages[i].isEnabled);
|
|
}
|
|
}
|
|
},
|
|
error => this.handleError("Server error fetching pages", error)
|
|
)
|
|
);
|
|
}
|
|
|
|
getParentOptions() {
|
|
this.parentOptions = this.normalMenuItems.map(item => ({label: item.title, value: item._id}));
|
|
this.parentOptions.unshift({label: 'No parent', value: ''});
|
|
}
|
|
|
|
addValidatorForUrlOrRoute() {
|
|
this.destroyTypeSubscription();
|
|
this.typeSub = this.menuItemForm.get('type').valueChanges.subscribe(value => {
|
|
setTimeout(() => {
|
|
this.menuItemForm.controls['route'].clearValidators();
|
|
this.menuItemForm.controls['url'].clearValidators();
|
|
if(value === "internal") {
|
|
this.menuItemForm.controls['route'].setValidators([Validators.required]);
|
|
} else if(value === "external") {
|
|
this.menuItemForm.controls['url'].setValidators([Validators.required, StringUtils.urlValidator()]);
|
|
}
|
|
this.menuItemForm.controls['route'].updateValueAndValidity();
|
|
this.menuItemForm.controls['url'].updateValueAndValidity();
|
|
}, 0);
|
|
});
|
|
}
|
|
|
|
public newMenuItem() {
|
|
this.menuItemForm = this._fb.group({
|
|
_id: this._fb.control(""),
|
|
title: this._fb.control("",Validators.required),
|
|
type: this._fb.control("",Validators.required),
|
|
route: this._fb.control(""),
|
|
url: this._fb.control(""),
|
|
isEnabled: this._fb.control(""),
|
|
isFeatured: this._fb.control(this.selectedMenuType == 'customMenu'),
|
|
parentItemId: this._fb.control("")
|
|
});
|
|
this.addValidatorForUrlOrRoute();
|
|
this.menuItemsModalOpen('Add Menu Item', 'Create');
|
|
}
|
|
|
|
public editMenuItem(index: number, menuItem: MenuItemExtended, isChild: boolean = false) {
|
|
this.menuItemForm = this._fb.group({
|
|
_id: this._fb.control(menuItem['_id']),
|
|
title: this._fb.control(menuItem.title,Validators.required),
|
|
type: this._fb.control(menuItem['type'],Validators.required),
|
|
route: this._fb.control(menuItem.route, (menuItem['type'] == "internal") ? [Validators.required] : []),
|
|
url: this._fb.control(menuItem.url, (menuItem['type'] == "external") ? [Validators.required, StringUtils.urlValidator()] : []),
|
|
isFeatured: this._fb.control(menuItem.isFeatured),
|
|
parentItemId: this._fb.control(menuItem.parentItemId)
|
|
});
|
|
this.isChild = isChild;
|
|
this.index = index;
|
|
this.addValidatorForUrlOrRoute();
|
|
this.menuItemsModalOpen('Edit Menu Item', 'Save Changes');
|
|
}
|
|
|
|
public confirmDeleteMenuItem(id: string, isChild: boolean = false, parentId: string) {
|
|
this.selectedMenuItemParent = parentId;
|
|
this.selectedMenuItem = id;
|
|
this.isChild = isChild;
|
|
this.confirmModalOpen();
|
|
}
|
|
|
|
private confirmModalOpen() {
|
|
this.deleteModal.alertTitle = 'Delete Confirmation';
|
|
this.deleteModal.message = 'Are you sure you want to delete this menu item?';
|
|
this.deleteModal.okButtonText = 'Yes';
|
|
this.deleteModal.open();
|
|
}
|
|
|
|
public confirmedDeleteMenuItem(data: any) {
|
|
this.showLoading = true;
|
|
this.subscriptions.push(
|
|
this._helpContentService.deleteMenuItem(this.selectedMenuItem, this.portal).subscribe(
|
|
_ => {
|
|
this.deleteMenuItemFromArray(this.selectedMenuItem, this.isChild);
|
|
NotificationHandler.rise("Menu item have been <b>successfully deleted</b>");
|
|
this.showLoading = false;
|
|
this._clearCacheService.clearCache("Menu item deleted");
|
|
this._clearCacheService.purgeBrowserCache("Menu item deleted", this.portal);
|
|
},
|
|
error => this.handleError("Server error deleting menu item", error)
|
|
)
|
|
)
|
|
}
|
|
|
|
private deleteMenuItemFromArray(id: string, isChild: boolean = false) {
|
|
if(isChild) {
|
|
let i = this.normalMenuItems.findIndex(_ => _._id == this.selectedMenuItemParent);
|
|
let j = this.normalMenuItems[i].items.findIndex(_ => _._id == id);
|
|
this.normalMenuItems[i].items.splice(j, 1);
|
|
} else {
|
|
if(this.selectedMenuType == 'customMenu') {
|
|
let i = this.featuredMenuItems.findIndex(_ => _._id == id);
|
|
this.featuredMenuItems.splice(i, 1);
|
|
} else {
|
|
let i = this.normalMenuItems.findIndex(_ => _._id == id);
|
|
this.normalMenuItems.splice(i, 1);
|
|
this.getParentOptions();
|
|
}
|
|
}
|
|
}
|
|
|
|
private menuItemsModalOpen(title: string, yesBtn: string) {
|
|
this.editModal.okButtonLeft = false;
|
|
this.editModal.alertTitle = title;
|
|
this.editModal.okButtonText = yesBtn;
|
|
this.editModal.open();
|
|
}
|
|
|
|
public menuItemSaveConfirmed(data: any) {
|
|
this.destroyTypeSubscription();
|
|
this.showLoading = true;
|
|
this.menuItemForm.value.target = this.menuItemForm.value['type'] == "internal" ? "_self" : "_blank";
|
|
if(!this.menuItemForm.value._id) {
|
|
this.subscriptions.push(
|
|
this._helpContentService.saveMenuItem(<MenuItemExtended>this.menuItemForm.getRawValue(), this.portal).subscribe(
|
|
menuItem => {
|
|
this.menuItemSavedSuccessfully(menuItem, true);
|
|
NotificationHandler.rise('Menu item <b>' + menuItem.title + '</b> has been <b>successfully created</b>');
|
|
this._clearCacheService.clearCache("Menu item saved");
|
|
this._clearCacheService.purgeBrowserCache("Menu item saved", this.portal);
|
|
},
|
|
error => this.handleError("System error creating menu item", error)
|
|
)
|
|
)
|
|
} else {
|
|
this.subscriptions.push(
|
|
this._helpContentService.updateMenuItem(<MenuItemExtended>this.menuItemForm.getRawValue(), this.portal).subscribe(
|
|
menuItem => {
|
|
this.menuItemSavedSuccessfully(menuItem, false);
|
|
NotificationHandler.rise('Menu item <b>' + menuItem.title + '</b> has been <b>successfully updated</b>');
|
|
this._clearCacheService.clearCache("Menu item updated");
|
|
this._clearCacheService.purgeBrowserCache("Menu item updated", this.portal);
|
|
},
|
|
error => this.handleError("System error updating menu item", error)
|
|
)
|
|
)
|
|
}
|
|
}
|
|
|
|
public menuItemSavedSuccessfully(menuItem: MenuItemExtended, isNew: boolean) {
|
|
if(isNew) {
|
|
if(menuItem.parentItemId) {
|
|
let i = this.normalMenuItems.findIndex(_ => _._id == menuItem.parentItemId);
|
|
this.normalMenuItems[i].items.push(menuItem);
|
|
} else {
|
|
if(menuItem.isFeatured) {
|
|
this.featuredMenuItems.push(menuItem);
|
|
} else {
|
|
this.normalMenuItems.push(menuItem);
|
|
this.getParentOptions();
|
|
}
|
|
}
|
|
} else {
|
|
if(menuItem.parentItemId) {
|
|
} else {
|
|
if(menuItem.isFeatured) {
|
|
this.featuredMenuItems[this.index] = menuItem;
|
|
} else {
|
|
this.normalMenuItems[this.index] = menuItem;
|
|
this.getParentOptions();
|
|
}
|
|
}
|
|
}
|
|
this.showLoading = false;
|
|
}
|
|
|
|
handleError(message: string, error) {
|
|
NotificationHandler.rise(message, 'danger');
|
|
console.log('Server responded: ' + error);
|
|
this.showLoading = false;
|
|
}
|
|
|
|
public toggleMenuItem(menuItem) {
|
|
menuItem.isOpen = !menuItem.isOpen;
|
|
}
|
|
|
|
public valueChange() {
|
|
this.elements.disable();
|
|
this.cdr.detectChanges();
|
|
this.elements.init();
|
|
this.elements.enable();
|
|
}
|
|
|
|
public get displayMenuItems() {
|
|
return this.selectedMenuType == 'customMenu' ? this.featuredMenuItems : this.normalMenuItems;
|
|
}
|
|
|
|
public moveElement(index: number, newIndex: number, children: MenuItemExtended[] = []) {
|
|
this.elements.init();
|
|
if(children && children.length) {
|
|
this.subElements.init();
|
|
}
|
|
if(this.selectedMenuType == 'customMenu') {
|
|
let temp = HelperFunctions.copy(this.featuredMenuItems);
|
|
HelperFunctions.swap(temp, index, newIndex);
|
|
this._helpContentService.reorderMenuItems(temp, this.portal).subscribe(() => {
|
|
HelperFunctions.swap(this.featuredMenuItems, index, newIndex);
|
|
this._clearCacheService.clearCache("Menu items reordered");
|
|
this._clearCacheService.purgeBrowserCache("Menu items reordered", this.portal);
|
|
}, error => {
|
|
this.handleError("System error reordering menu items", error);
|
|
});
|
|
} else {
|
|
let temp = HelperFunctions.copy(this.normalMenuItems);
|
|
if(children && children.length) {
|
|
temp = HelperFunctions.copy(children);
|
|
}
|
|
HelperFunctions.swap(temp, index, newIndex);
|
|
this._helpContentService.reorderMenuItems(temp, this.portal).subscribe(() => {
|
|
HelperFunctions.swap(children && children.length ? children : this.normalMenuItems, index, newIndex);
|
|
this._clearCacheService.clearCache("Menu items reordered");
|
|
this._clearCacheService.purgeBrowserCache("Menu items reordered", this.portal);
|
|
}, error => {
|
|
this.handleError("System error reordering menu items", error);
|
|
});
|
|
}
|
|
}
|
|
|
|
public toggleMenu(status: boolean, isFeatured: boolean) {
|
|
this.subscriptions.push(
|
|
this._helpContentService.toggleMenu(status, isFeatured, this.portal).subscribe(() => {
|
|
if(isFeatured) {
|
|
this.showFeaturedMenu = status;
|
|
} else {
|
|
this.showNormalMenu = status;
|
|
}
|
|
this._clearCacheService.clearCache("Menu toggled");
|
|
this._clearCacheService.purgeBrowserCache("Menu toggled", this.portal);
|
|
}, error => {
|
|
this.handleError("System error toggling menu", error);
|
|
})
|
|
);
|
|
}
|
|
}
|