import {Component, ElementRef, OnInit, ViewChild} from '@angular/core'; import {UntypedFormArray, UntypedFormBuilder, UntypedFormControl} from '@angular/forms'; import {ActivatedRoute} from '@angular/router'; import {CommunityService} from '../../../openaireLibrary/connect/community/community.service'; import {SubjectsService} from '../subjects.service'; import {EnvProperties} from '../../../openaireLibrary/utils/properties/env-properties'; import {Title} from '@angular/platform-browser'; import {properties} from '../../../../environments/environment'; import {AlertModal} from '../../../openaireLibrary/utils/modal/alert'; import {SearchInputComponent} from '../../../openaireLibrary/sharedComponents/search-input/search-input.component'; import {forkJoin, Subscription} from 'rxjs'; import {CommunityInfo} from '../../../openaireLibrary/connect/community/communityInfo'; import { FullScreenModalComponent } from 'src/app/openaireLibrary/utils/modal/full-screen-modal/full-screen-modal.component'; import {HelperFunctions} from 'src/app/openaireLibrary/utils/HelperFunctions.class'; import {NotificationHandler} from "../../../openaireLibrary/utils/notification-handler"; import {ClearCacheService} from "../../../openaireLibrary/services/clear-cache.service"; import {SdgSelectionComponent} from '../../../openaireLibrary/sdg/sdg-selection/sdg-selection.component'; import {FosSelectionComponent} from '../../../openaireLibrary/fos/fos-selection/fos-selection.component'; import {InputComponent} from "../../../openaireLibrary/sharedComponents/input/input.component"; declare var UIkit: any; @Component({ selector: 'subjects-edit-form', templateUrl: './subjects-edit-form.component.html', }) export class SubjectsEditFormComponent implements OnInit { properties: EnvProperties = properties; communityId: string = null; community: CommunityInfo = null; loading = true; params: any; private subscriptions: any[] = []; filterForm: UntypedFormControl; subjectsForm = new UntypedFormArray([]); hasChanges: boolean = false; originalAllSubjects = []; originalSubjects = []; originalSdg = []; originalFos = []; displayedAllSubjects = []; displayedSubjects = []; displayedSdg = []; displayedFos = []; groupedAllSubjects = []; groupedSubjects = []; groupedSdg = []; groupedFos = []; subjectsColumns = []; subjectsLimit: number = 6; maxCharacters: number = 25; activeTab: 'all' | 'freeText' | 'sdg' | 'fos' = 'all'; indexAll: number = 0; indexSubjects: number = 0; indexSdg: number = 0; indexFos: number = 0; @ViewChild('addSubjectsInput') addSubjectsInput: InputComponent; @ViewChild('editModal') editModal: AlertModal; @ViewChild('deleteModal') deleteModal: AlertModal; @ViewChild('fsModal', {static: true}) fullscreen: FullScreenModalComponent; @ViewChild('modalTabs') modalTabs: ElementRef; @ViewChild('sdgSelection') sdgSelection: SdgSelectionComponent; @ViewChild('fosSelection') fosSelection: FosSelectionComponent; onEnter: () => void = () => { this.addSubjectsIntoList(); } constructor(private route: ActivatedRoute, public _fb: UntypedFormBuilder, private title: Title, private _communityService: CommunityService, private _subjectsService: SubjectsService, private _clearCacheService: ClearCacheService) { } ngOnInit() { this.filterForm = this._fb.control(''); this.subscriptions.push(this.filterForm.valueChanges.subscribe(value => { this.displayedAllSubjects = this.originalAllSubjects.filter(subject => { return !value || subject.toLowerCase().indexOf(value.toLowerCase()) != -1 }); this.displayedSubjects = this.originalSubjects.filter(subject => { return !value || subject.toLowerCase().indexOf(value.toLowerCase()) != -1 }); this.displayedSdg = this.originalSdg.filter(subject => { return !value || subject.toLowerCase().indexOf(value.toLowerCase()) != -1 }); this.displayedFos = this.originalFos.filter(subject => { return !value || subject.toLowerCase().indexOf(value.toLowerCase()) != -1 }); if (this.activeTab === 'all') { this.groupSubjects(this.displayedAllSubjects, 'all'); } else if (this.activeTab === 'freeText') { this.groupSubjects(this.displayedSubjects, 'freeText'); } else if (this.activeTab === 'sdg') { this.groupSubjects(this.displayedSdg, 'sdg'); } else if (this.activeTab === 'fos') { this.groupSubjects(this.displayedFos, 'fos'); } })); this.subscriptions.push(this.route.params.subscribe( params => { this.communityId = params['community']; this.title.setTitle(this.communityId.toUpperCase() + ' | Subjects'); this.loading = true; this.subscriptions.push(this._communityService.getCommunityAsObservable().subscribe( community => { this.community = community; this.params = { community: encodeURIComponent( '"' + community.queryId + '"') }; this.community.subjects.sort((n1, n2) => { if (n1.toLowerCase() > n2.toLowerCase()) { return 1; } if (n1.toLowerCase() < n2.toLowerCase()) { return -1; } return 0; }); this.displayedSubjects = HelperFunctions.copy(this.community.subjects); this.displayedSdg = this.community.sdg; this.displayedFos = this.community.fos; this.displayedAllSubjects = [...this.displayedSubjects, ...this.displayedSdg, ...this.displayedFos]; this.groupSubjects(this.displayedAllSubjects, 'all'); this.originalAllSubjects = HelperFunctions.copy(this.displayedAllSubjects); this.originalSubjects = HelperFunctions.copy(this.displayedSubjects); this.originalSdg = HelperFunctions.copy(this.displayedSdg); this.originalFos = HelperFunctions.copy(this.displayedFos); this.loading = false; }, error => this.handleUpdateError('System error retrieving community profile', error) )); })); } ngOnDestroy() { this.subscriptions.forEach(subscription => { if (subscription instanceof Subscription) { subscription.unsubscribe(); } }); } public groupSubjects(subjects: string[], type: string) { if (subjects.length === 0) { return []; } subjects.sort((a, b) => a.localeCompare(b)); if (type === 'all') { this.indexAll = 0; this.activeTab = 'all'; this.groupedAllSubjects = Object.values( subjects.reduce((acc, subject) => { let firstLetter = subject[0].toLocaleUpperCase(); if (!acc[firstLetter]) { acc[firstLetter] = {group: firstLetter, data: [subject]}; } else { acc[firstLetter].data.push(subject); } return acc; }, {}) ) if (subjects.length > 1) { this.groupedAllSubjects.unshift({group: 'All', data: subjects}); } } if (type === 'freeText') { this.indexSubjects = 0; this.activeTab = 'freeText'; this.groupedSubjects = Object.values( subjects.reduce((acc, subject) => { let firstLetter = subject[0].toLocaleUpperCase(); if (!acc[firstLetter]) { acc[firstLetter] = {group: firstLetter, data: [subject]}; } else { acc[firstLetter].data.push(subject); } return acc; }, {}) ) if (subjects.length > 1) { this.groupedSubjects.unshift({group: 'All', data: subjects}); } } if (type === 'sdg') { this.indexSdg = 0; this.activeTab = 'sdg'; this.groupedSdg = Object.values( subjects.reduce((acc, subject) => { let firstLetter = subject[0].toLocaleUpperCase(); if (!acc[firstLetter]) { acc[firstLetter] = {group: firstLetter, data: [subject]}; } else { acc[firstLetter].data.push(subject); } return acc; }, {}) ) if (subjects.length > 1) { this.groupedSdg.unshift({group: 'All', data: subjects}); } } if (type === 'fos') { this.indexFos = 0; this.activeTab = 'fos'; this.groupedFos = Object.values( subjects.reduce((acc, subject) => { let key = subject.substring(0, 2).toLocaleUpperCase(); if (!acc[key]) { acc[key] = {group: key, data: [subject]}; } else { acc[key].data.push(subject); } return acc; }, {}) ) if (subjects.length > 1) { this.groupedFos.unshift({group: 'All', data: subjects}); } } } public changeDisplayedSubjects(i, group) { this.subjectsColumns = []; if (this.activeTab === 'all') { this.indexAll = i; } else if (this.activeTab === 'freeText') { this.indexSubjects = i; } else if (this.activeTab === 'sdg') { this.indexSdg = i; } else if (this.activeTab === 'fos') { this.indexFos = i; } if (group.data.length > this.subjectsLimit && group.group != 'All') { this.divideSubjects(group); } } public divideSubjects(group) { let columns = []; for (let i = 0; i < (group.data.length / this.subjectsLimit); i++) { columns.push(group.data.slice(i * this.subjectsLimit, ((i + 1) * this.subjectsLimit))); } this.subjectsColumns = columns; } public getSubjectsExistOnlyInFirst(firstArray: string[], secondArray: string[]): string[] { const difference = []; for (let i = 0; i < firstArray.length; i++) { if (secondArray.indexOf(firstArray[i]) === -1) { difference.push(firstArray[i]); } } return difference; } public editAllSubjects() { UIkit.tab(this.modalTabs.nativeElement).show(0); this.displayedSubjects = HelperFunctions.copy(this.community.subjects); this.sdgSelection.reset(); this.sdgSelection.sdgs.markAsPristine(); this.fosSelection.reset(); this.fosSelection.fosOptions.markAsPristine(); this.fullscreen.title = "Add/Edit Subjects"; this.fullscreen.okButtonText = "Save"; this.fullscreen.back = true; this.fullscreen.okButton = true; this.fullscreen.open(); } public addSubjectsIntoList() { if (this.addSubjectsInput.searchControl.getRawValue()) { this.addSubjectsInput.add(null, true); } this.subjectsForm.getRawValue().forEach(element => { this.displayedSubjects.unshift(element); }); this.subjectsForm.clear(); this.hasChanges = true; } public removeSubjectFromList(i) { this.displayedSubjects.splice(i, 1); this.hasChanges = true; } public saveAllSubjects() { let selectedSdg = this.sdgSelection.getSelectedSubjects().map(a => a.id); let selectedFos = this.fosSelection.getSelectedSubjects().map(a => a.id); let requests = [ ...this.saveSubjects(this.community.subjects, this.displayedSubjects, 'subjects'), ...this.saveSubjects(this.community.sdg, selectedSdg, 'sdg'), ...this.saveSubjects(this.community.fos, selectedFos, 'fos') ]; this.subscriptions.push(forkJoin(requests).subscribe(res => { this.afterUpdateActions(res, "updated"); })); } public saveSubjects(subjects, displayedSubjects, type: string) { if (this.communityId != null && this.communityId !== '') { this.loading = true; const subjectsToDeleteAr = this.getSubjectsExistOnlyInFirst(subjects, displayedSubjects); const subjectsToAddAr = this.getSubjectsExistOnlyInFirst(displayedSubjects, subjects); const subjectsToDelete = this.getNonEmptyItems(subjectsToDeleteAr); const subjectsToAdd = this.getNonEmptyItems(subjectsToAddAr); let requests = []; if (subjectsToDelete.length > 0) { requests.push(this._subjectsService.removeSubjects( this.properties.communityAPI + this.communityId + '/' + type, subjectsToDelete)) } if (subjectsToAdd.length > 0) { requests.push(this._subjectsService.addSubjects( this.properties.communityAPI + this.communityId + '/' + type, subjectsToAdd)) } return requests; } } handleUpdateError(message: string, error = null) { if (error) { console.error(error) } NotificationHandler.rise(message, 'danger'); this.loading = false; } afterUpdateActions(response, message: string) { response.forEach(res => { if (res.subjects) { this.community.subjects = res.subjects; } else if (res.sdg) { this.community.sdg = res.sdg; } else if (res.fos) { this.community.fos = res.fos; } }); this._communityService.updateSubjects(this.community.subjects, this.community.fos, this.community.sdg); this._clearCacheService.purgeBrowserCache("Subjects " + message, this.communityId); NotificationHandler.rise('Subjects successfully ' + message + '!') this.loading = false; } private getNonEmptyItems(data: string[]): string[] { const length = data.length; const arrayNonEmpty = new Array(); let j = 0; for (let i = 0; i < length; i++) { if (this.isEmpty(data[i])) { } else if (this.isNonEmpty(data[i])) { arrayNonEmpty[j] = data[i]; j++; } } return arrayNonEmpty; } private isEmpty(data: string): boolean { if (data !== undefined && !data.replace(/\s/g, '').length) { return true; } else { return false; } } private isNonEmpty(data: string): boolean { if (data !== undefined && data != null) { return true; } else { return false; } } }