import {ChangeDetectorRef, Directive, HostListener, OnInit, ViewRef} from "@angular/core"; import {IndicatorStakeholderBaseComponent} from "../monitor-admin/utils/stakeholder-base.component"; import {DomSanitizer} from "@angular/platform-browser"; import { Category, Indicator, IndicatorPath, IndicatorSize, Overlay, Section, Stakeholder, SubCategory, Topic, Visibility } from "./entities/stakeholder"; import {LayoutService} from "../dashboard/sharedComponents/sidebar/layout.service"; import {ClickEvent} from "../utils/click/click-outside-or-esc.directive"; import {Session, User} from "../login/utils/helper.class"; import {Filter, Value} from "../searchPages/searchUtils/searchHelperClasses.class"; import {RangeFilter} from "../utils/rangeFilter/rangeFilterHelperClasses.class"; import {RangeFilterComponent} from "../utils/rangeFilter/rangeFilter.component"; import {Dates, StringUtils} from "../utils/string-utils.class"; import {Params} from "@angular/router"; import {StatisticsService} from "../monitor-admin/utils/services/statistics.service"; import {SearchResearchResultsService} from "../services/searchResearchResults.service"; import {CustomFilterService} from "../shared/customFilter.service"; @Directive() export abstract class MonitorIndicatorStakeholderBaseComponent extends IndicatorStakeholderBaseComponent implements OnInit { /** Status */ public loading: boolean = true; public isMobile: boolean = false; public isFullscreen: boolean = false; /** Variables */ public user: User; public requireLogin: boolean = true; public view: Visibility; public stakeholder: Stakeholder; public activeTopic: Topic = null; public activeCategory: Category = null; public activeSubCategory: SubCategory = null; public filters: Filter[] = []; public queryParams: any = {}; public periodFilter: RangeFilter = { title: "Time range", filterId: "year", originalFilterIdFrom: null, originalFilterIdTo: null, selectedFromValue: null, selectedToValue: null, selectedFromAndToValues: "" }; rangeFilter: RangeFilterComponent; minYear = Dates.currentYear - 20; maxYear = Dates.currentYear; public numberResults: Map = new Map(); public clipboard; /** Services */ protected sanitizer: DomSanitizer; protected cdr: ChangeDetectorRef; protected layoutService: LayoutService; protected statisticsService: StatisticsService; protected searchResearchResultsService: SearchResearchResultsService; protected customFilterService: CustomFilterService; @HostListener('fullscreenchange', ['$event']) @HostListener('webkitfullscreenchange', ['$event']) @HostListener('mozfullscreenchange', ['$event']) @HostListener('MSFullscreenChange', ['$event']) screenChange() { this.isFullscreen = !this.isFullscreen; } ngOnInit() { this.layoutService.isMobile.subscribe(isMobile => { this.isMobile = isMobile; this.cdr.detectChanges(); }); this.createClipboard(); } protected setView(params: Params) { this.setSelectedFilters(); this.loading = false; if (params['topic']) { this.activeTopic = this.stakeholder.topics.find(topic => topic.alias === decodeURIComponent(params['topic']) && this.hasPermission(topic.visibility)); if (this.activeTopic) { if (params['category']) { this.activeCategory = this.activeTopic.categories.find(category => (category.alias === params['category']) && this.hasPermission(category.visibility)); if (!this.activeCategory) { this.navigateToError(); return; } } else { this.activeCategory = this.activeTopic.categories.find(category => this.hasPermission(category.visibility)); if (this.activeCategory) { this.activeSubCategory = this.activeCategory.subCategories.find(subCategory => this.hasPermission(subCategory.visibility)); if (this.activeSubCategory) { this.setIndicators(); } } return; } if (this.activeCategory) { if (params['subCategory']) { this.activeSubCategory = this.activeCategory.subCategories.find(subCategory => (subCategory.alias === params['subCategory'] && this.hasPermission(subCategory.visibility))); if (!this.activeSubCategory) { this.navigateToError(); return; } } else { this.activeSubCategory = this.activeCategory.subCategories.find(subCategory => this.hasPermission(subCategory.visibility)); } if (this.activeSubCategory) { this.setIndicators(); } else { this.navigateToError(); } return; } else { this.activeSubCategory = null; } } else { this.navigateToError(); return; } } else { this.activeTopic = this.stakeholder.topics.find(topic => this.hasPermission(topic.visibility)); if (this.activeTopic) { this.activeCategory = this.activeTopic.categories.find(category => this.hasPermission(category.visibility)); if (this.activeCategory) { this.activeSubCategory = this.activeCategory.subCategories.find(subCategory => this.hasPermission(subCategory.visibility)); if (this.activeSubCategory) { this.setIndicators(); } } } } } protected handleQueryParams(queryParams, params) { this.queryParams = Object.assign({}, queryParams); this.initializeFilters(); this.setView(params); if(this.requireLogin && !this.user && (this.filters.filter(filter => this.queryParams[filter.filterId]).length > 0 || this.queryParams['year'])) { if(queryParams['view']) { this._router.navigate([], {queryParams: {view: queryParams['view']}}); } else { this._router.navigate([], {queryParams: {}}); } } this.view = queryParams['view']; } protected initializeFilters() { this.periodFilter.selectedFromValue = (this.queryParams['year'] && this.queryParams['year'].indexOf("range") == 0) ? this.queryParams['year'].split("range")[1].split(":")[0] : ""; this.periodFilter.selectedToValue = (this.queryParams['year'] && this.queryParams['year'].indexOf("range") == 0) ? this.queryParams['year'].split("range")[1].split(":")[1] : ""; this.validateYearRange(false); for (let filter of this.filters) { if (this.queryParams[filter.filterId]) { for (let value of filter.values) { if (value.id == StringUtils.URIDecode(StringUtils.unquote(this.queryParams[filter.filterId]))) { value.selected = true; filter.countSelectedValues = 1; break; } } } else { this.clearFilter(filter); } } } protected validateYearRange(navigateTo: boolean = false) { let validYears = true; if (this.periodFilter.selectedToValue && (this.periodFilter.selectedToValue.length == 0 || !Dates.isValidYear(this.periodFilter.selectedToValue, this.minYear, this.maxYear))) { this.periodFilter.selectedToValue = this.maxYear + ""; validYears = false; } if (this.periodFilter.selectedFromValue && (this.periodFilter.selectedFromValue.length == 0 || !Dates.isValidYear(this.periodFilter.selectedFromValue, this.minYear, this.maxYear))) { this.periodFilter.selectedFromValue = this.minYear + ""; validYears = false; } if (this.periodFilter.selectedFromValue && this.periodFilter.selectedFromValue.length && this.periodFilter.selectedToValue && this.periodFilter.selectedToValue.length > 0 && parseInt(this.periodFilter.selectedFromValue, 10) > parseInt(this.periodFilter.selectedToValue, 10)) { this.periodFilter.selectedFromValue = this.periodFilter.selectedToValue; validYears = false; } if (!validYears || navigateTo) { if (this.periodFilter.selectedFromValue || this.periodFilter.selectedToValue) { this.queryParams["year"] = 'range' + (this.periodFilter.selectedFromValue ? this.periodFilter.selectedFromValue : '') + ":" + (this.periodFilter.selectedToValue ? this.periodFilter.selectedToValue : ""); } else { delete this.queryParams["year"]; } this._router.navigate([], {queryParams: this.queryParams}); this.setIndicators(); } } protected getFullUrl(indicatorPath: IndicatorPath) { let fosValues = this.getSelectedFilterValues("fos"); return this.indicatorUtils.getFullUrlWithFilters(this.stakeholder, indicatorPath,null, this.periodFilter.selectedFromValue, this.periodFilter.selectedToValue, false, fosValues?fosValues.lvl1:[],fosValues?fosValues.lvl2:[], this.getSelectedFilterValues("publiclyfunded")); } protected setIndicators() { this.activeSubCategory.numbers = this.activeSubCategory.numbers.filter(section => section.indicators.length > 0); this.activeSubCategory.charts = this.activeSubCategory.charts.filter(section => section.indicators.length > 0); this.periodFilter.selectedFromAndToValues = (this.periodFilter.selectedFromValue || this.periodFilter.selectedToValue ? ((this.periodFilter.selectedFromValue && !this.periodFilter.selectedToValue ? "From " : "") + (!this.periodFilter.selectedFromValue && this.periodFilter.selectedToValue ? "Until " : "") + (this.periodFilter.selectedFromValue ? this.periodFilter.selectedFromValue : "") + (this.periodFilter.selectedFromValue && this.periodFilter.selectedToValue ? " - " : "") + (this.periodFilter.selectedToValue ? this.periodFilter.selectedToValue : "")) : ""); //clear numbers when filters change this.numberResults.clear(); let urls: Map = new Map(); this.activeSubCategory.numbers.forEach((section, i) => { section.indicators.forEach((number, j) => { if (this.hasPermission(number.visibility)) { number.indicatorPaths.forEach((indicatorPath, k) => { let url = this.getFullUrl(indicatorPath); const pair = JSON.stringify([indicatorPath.source, url]); const indexes = urls.get(pair) ? urls.get(pair) : []; indexes.push([i, j, k]); urls.set(pair, indexes); }) } }); }); urls.forEach((indexes, pair) => { pair = JSON.parse(pair); let activeSubcategory = this.activeSubCategory._id; this.subscriptions.push(this.statisticsService.getNumbers(this.indicatorUtils.getSourceType(pair[0]), pair[1]).subscribe(response => { if(activeSubcategory === this.activeSubCategory._id) { indexes.forEach(([i, j, k]) => { if( this.activeSubCategory?.numbers[i]?.indicators[j]) { let result = JSON.parse(JSON.stringify(response)); this.activeSubCategory.numbers[i].indicators[j].indicatorPaths[k].jsonPath.forEach(jsonPath => { if (result) { result = result[jsonPath]; } }); if (typeof result === 'string' || typeof result === 'number') { result = Number(result); if (result === Number.NaN) { result = 0; } } else { result = 0; } this.numberResults.set(i + '-' + j + '-' + k, result); } }); } })); }); this.activeSubCategory.charts.forEach((section, i) => { section.indicators.forEach((indicator, j) => { indicator.indicatorPaths.forEach((indicatorPath, k) => { indicator.indicatorPaths[k].safeResourceUrl = this.getUrlByStakeHolder(indicator.indicatorPaths[k]); }); }); }); if (this.cdr && !(this.cdr as ViewRef).destroyed) { this.cdr.detectChanges(); } } public getUrlByStakeHolder(indicatorPath: IndicatorPath) { return this.sanitizer.bypassSecurityTrustResourceUrl( this.indicatorUtils.getChartUrl(indicatorPath.source, this.getFullUrl(indicatorPath))); } public getActiveIndicatorPath(indicator: Indicator) { if(indicator.activePath) { return indicator.indicatorPaths[indicator.activePath]; } else { return indicator.indicatorPaths[0]; } } public filter() { this.validateYearRange(true); } public filterChanged($event, navigate: boolean = true) { let selected = []; for (let value of $event.value.values) { if (value.selected) { selected.push( StringUtils.quote(StringUtils.URIEncode(value.id))); } } if (selected.length > 0) { this.queryParams[$event.value.filterId] = selected.join(","); } else { delete this.queryParams[$event.value.filterId]; } if (navigate) { this._router.navigate([], {queryParams: this.queryParams}); this.setIndicators(); } } public countSelectedFilters(): number { let count = 0; if (this.periodFilter.selectedFromAndToValues.length > 0) { count += 1; } for (let filter of this.filters) { count += filter.countSelectedValues; } return count; } public clearAll() { for (let filter of this.filters) { this.clearFilter(filter); } this.periodFilter.selectedFromValue = ""; this.periodFilter.selectedToValue = ""; this.validateYearRange(true) } public clearFilter(filter: Filter) { filter.countSelectedValues = 0; filter.radioValue = ""; for (let value of filter.values) { if (value.selected) { value.selected = false; } } if (this.queryParams[filter.filterId]) { delete this.queryParams[filter.filterId]; } } clearPeriodFilter() { if (this.periodFilter.selectedFromValue || this.periodFilter.selectedToValue) { this.periodFilter.selectedFromValue = ""; this.periodFilter.selectedToValue = ""; if(this.rangeFilter) { this.rangeFilter.clearFilter(); } this.filter(); } } clearFilterValue(filter: Filter, value: Value) { value.selected = false; filter.radioValue = ''; filter.countSelectedValues = filter.countSelectedValues - 1; this.filterChanged({ value:filter }); } public hasPermission(visibility: Visibility): boolean { if(visibility === 'PUBLIC') { return true; } else if(visibility === 'RESTRICTED') { return (!this.view || this.view === 'RESTRICTED') && this.isMember(this.stakeholder); } else { return !this.view && this.isManager(this.stakeholder); } } public isMember(stakeholder: Stakeholder) { return this.user && (Session.isPortalAdministrator(this.user) || Session.isCurator(stakeholder.type, this.user) || Session.isManager(stakeholder.type, stakeholder.alias, this.user) || Session.isMember(stakeholder.type, stakeholder.alias, this.user)); } public isManager(stakeholder: Stakeholder) { return this.user && (Session.isPortalAdministrator(this.user) || Session.isCurator(stakeholder.type, this.user) || Session.isManager(stakeholder.type, stakeholder.alias, this.user)); } public countSubCategoriesToShow(category: Category): number { return category.subCategories.filter(subCategory => this.hasPermission(subCategory.visibility)).length; } public countSectionsWithIndicatorsToShow(sections: Section[]):number { return sections.map(section => this.countIndicatorsToShow(section.indicators)).reduce((sum, current) => sum + current, 0); } public countIndicatorsToShow(indicators: Indicator[]): number { return indicators.filter(indicator => this.hasPermission(indicator.visibility)).length; } public getNumberClassBySize(size: IndicatorSize) { if (size === 'small') { return 'uk-width-medium@m uk-width-1-1'; } else if (size === 'medium') { return 'uk-width-1-4@l uk-width-1-2@m uk-width-1-1'; } else { return 'uk-width-1-2@l uk-width-1-1@m uk-width-1-1'; } } public getChartClassBySize(size: IndicatorSize): string { if (size === 'small') { return 'uk-width-1-3@xl uk-width-1-2@m uk-width-1-1'; } else if (size === 'medium') { return 'uk-width-1-2@l uk-width-1-1'; } else { return 'uk-width-1-1'; } } public printReport() { window.print(); } changeOverlay(event, indicator: Indicator, overlay: Overlay) { event.stopPropagation(); indicator.overlay = overlay; } closeOverlay(event: ClickEvent, indicator: Indicator) { if(event.clicked && indicator.overlay) { indicator.overlay = false; } } private createClipboard() { if (typeof window !== 'undefined') { delete this.clipboard; let Clipboard; Clipboard = require('clipboard'); this.clipboard = new Clipboard('.clipboard_btn'); } } //Refine Type Filters setSelectedFilters(){ for (var i = 0; i < this.filters.length; i++) { var filter: Filter = this.filters[i]; filter.countSelectedValues = 0; let parameterNames = Object.keys(this.queryParams); if (parameterNames.indexOf(filter.filterId) != -1) { let values = (decodeURIComponent(this.queryParams[filter.filterId])).split(/,(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/, -1); for (let filterValue of filter.values) { if (values.indexOf(StringUtils.quote(filterValue.id)) > -1) { filterValue.selected = true; filter.countSelectedValues++; } else { filterValue.selected = false; } } } else { for (let filterValue of filter.values) { filterValue.selected = false; } } } } getSelectedFilterValues(filterId){ let values = null; for (let filter of this.filters) { if(filterId == filter.filterId && filter.countSelectedValues > 0) { values =filterId == "fos"?{lvl1:[],lvl2:[]}:[]; for (let filterValue of filter.values) { if (filterValue.selected) { if(filterId == "fos"){ let code = filterValue.id.split(" ")[0]; if(code.length == 2){ values.lvl1.push(filterValue.id) }else{ values.lvl2.push(filterValue.id) } }else if(filterId == "publiclyfunded"){ // console.log("publiclyFunded", filterValue) return filterValue.id; }else{ values.push(filterValue.id); } } } } } return values; } }