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 {MenuAlignment, 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'; // import {Page} from "../../utils/entities/adminTool/page"; declare var UIkit; @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 newPageWindowOpen: boolean = false; 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 = null; public selectedMenuItem: string; public selectedMenuItemParent: string; public isChild: boolean = false; public showNormalMenu: boolean = false; public showFeaturedMenu: boolean = false; public featuredAlignment: string = MenuAlignment.CENTER.valueOf(); 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.featuredAlignment = data.featuredAlignment.valueOf(); 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 successfully deleted"); this.showLoading = false; this._clearCacheService.clearCacheInRoute("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(this.menuItemForm.getRawValue(), this.portal).subscribe( menuItem => { this.menuItemSavedSuccessfully(menuItem, true); NotificationHandler.rise('Menu item ' + menuItem.title + ' has been successfully created'); this._clearCacheService.clearCacheInRoute("Menu item saved",this.portal, "/"); }, error => this.handleError("System error creating menu item", error) ) ) } else { this.subscriptions.push( this._helpContentService.updateMenuItem(this.menuItemForm.getRawValue(), this.portal).subscribe( menuItem => { this.menuItemSavedSuccessfully(menuItem, false); NotificationHandler.rise('Menu item ' + menuItem.title + ' has been successfully updated'); this._clearCacheService.clearCacheInRoute("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.cdr.detectChanges(); this.elements.init(); } 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.clearCacheInRoute("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.clearCacheInRoute("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.clearCacheInRoute("Menu toggled",this.portal, "/"); NotificationHandler.rise("Menu has been successfully toggled to be "+(status?"visible":"hidden")+""); }, error => { this.handleError("System error toggling menu", error); }) ); } public alignMenu(alignment: string) { this.subscriptions.push( this._helpContentService.alignMenu(MenuAlignment[alignment], this.portal).subscribe(() => { this.featuredAlignment = alignment; this._clearCacheService.clearCacheInRoute("Menu aligned",this.portal, "/"); NotificationHandler.rise("Menu has been successfully "+alignment.toLowerCase()+" aligned"); }, error => { this.handleError("System error aligning menu to the "+alignment.toLowerCase(), error); }) ); } // public newPageWindow() { // this.newPageWindowOpen = !this.newPageWindowOpen; // this.pageForm = this._fb.group({ // _id: this._fb.control(null), // route: this._fb.control('/featured/', [Validators.required, StringUtils.validRoute(this.allPages, 'value'), this.validCustomRoute()]), // name: this._fb.control('', Validators.required), // isEnabled: this._fb.control(true), // portalType: this._fb.control(this.properties.adminToolsPortalType, Validators.required), // portalPid: this._fb.control(this.portal), // top: this._fb.control(true), // bottom: this._fb.control(false), // left: this._fb.control(false), // right: this._fb.control(false), // type: this._fb.control('html', Validators.required), // entities: this._fb.control(['']) // }); // } // // public validCustomRoute(): ValidatorFn { // return (control: AbstractControl): ValidationErrors | null => { // if (control.value) { // if (!control.value.startsWith("/featured")) { // return {error: 'Custom route should start with /featured'} // } // } // } // } // // public createPage() { // if(!this.pageForm.value.route.startsWith('/featured')) { // this.pageForm.value.route = '/featured/'.concat(this.pageForm.value.route); // } // // this.showLoading = true; // this.subscriptions.push( // this._helpContentService.savePage(this.pageForm.value, this.properties.adminToolsAPIURL).subscribe( // page => { // this.allPages.push({value: page.route, label: page.name}); // NotificationHandler.rise('Page ' + page.name + ' has been successfully created'); // this.newPageWindowOpen = !this.newPageWindowOpen; // this.menuItemForm.get('route').setValue(page.route); // this.menuItemForm.get('route').markAsDirty(); // this.showLoading = false; // }, // error => this.handleError('System error creating page', error) // ) // ); // } }