diff --git a/src/app/portal/components/tab-button/tab-button.component.html b/src/app/portal/components/tab-button/tab-button.component.html index 831bed992..1d78eaf28 100644 --- a/src/app/portal/components/tab-button/tab-button.component.html +++ b/src/app/portal/components/tab-button/tab-button.component.html @@ -1,13 +1,30 @@ - + + -
- +
+ -
{{ label }}
-
+
{{ label }}
+
- -
-
+ +
+
+
+ + + + + +
+ + +
{{ label }}
+
+ + +
+
+
+
- diff --git a/src/app/portal/components/tab-button/tab-button.component.scss b/src/app/portal/components/tab-button/tab-button.component.scss index 55035af55..a46fa0bba 100644 --- a/src/app/portal/components/tab-button/tab-button.component.scss +++ b/src/app/portal/components/tab-button/tab-button.component.scss @@ -48,6 +48,11 @@ border: 2px solid #4546B9; } +.link-button__disabled { + color: #B0B0B0; + cursor: not-allowed; +} + /*.animated-number { font-variant-numeric: tabular-nums; }*/ diff --git a/src/app/portal/components/tab-button/tab-button.component.ts b/src/app/portal/components/tab-button/tab-button.component.ts index 37e1be95a..2868b5bce 100644 --- a/src/app/portal/components/tab-button/tab-button.component.ts +++ b/src/app/portal/components/tab-button/tab-button.component.ts @@ -24,8 +24,12 @@ import { RouterLinkWithHref } from '@angular/router'; export class TabButtonComponent { @Input() label: string; @Input() count: number; - @Input() route: string; + + @Input() routerLink: string; + @Input() queryParams: any; + @Input() active = false; + @Input() disabled = false; countOps = { duration: 0.5, diff --git a/src/app/portal/components/tab-navigation/tab-navigation.component.html b/src/app/portal/components/tab-navigation/tab-navigation.component.html index 8da54e99b..f9eb37a8e 100644 --- a/src/app/portal/components/tab-navigation/tab-navigation.component.html +++ b/src/app/portal/components/tab-navigation/tab-navigation.component.html @@ -1,11 +1,35 @@ diff --git a/src/app/portal/components/tab-navigation/tab-navigation.component.ts b/src/app/portal/components/tab-navigation/tab-navigation.component.ts index 133202f53..4fccda671 100644 --- a/src/app/portal/components/tab-navigation/tab-navigation.component.ts +++ b/src/app/portal/components/tab-navigation/tab-navigation.component.ts @@ -7,10 +7,10 @@ import { HttpClient } from '@angular/common/http'; import { AppConfigService } from '@shared/services/app-config-service.service'; import { BreakpointObserver } from '@angular/cdk/layout'; import { SearchService } from '@portal/services/search.service'; -import { ActivatedRoute } from '@angular/router'; +import { ActivatedRoute, Router, UrlSegment } from '@angular/router'; type IndexCounts = { [index: string]: number }; -type ButtonData = { label: string, icon: string, route: string, count: number, active: boolean }; +type ButtonData = { label: string, icon: string, route: string, count: number, active: boolean, disabled?: boolean}; @Component({ selector: 'app-tab-navigation', @@ -24,13 +24,15 @@ export class TabNavigationComponent { breakpointObserver = inject(BreakpointObserver); appConfigService = inject(AppConfigService); + route = inject(ActivatedRoute); + router = inject(Router); + url = this.appConfigService.apiUrl + "publication,person,funding,dataset,funding-call,infrastructure,organization/_search?request_cache=true"; showAll$ = new BehaviorSubject(false); // Legacy compatibility searchService = inject(SearchService); - route = inject(ActivatedRoute); fullCounts$: Observable = this.http.post(this.url, payloadWithoutKeywords()).pipe( map((response: any) => response.aggregations), @@ -41,6 +43,11 @@ export class TabNavigationComponent { input$ = this.route.params.pipe(map(params => params["input"])) tab$ = this.route.params.pipe(map(params => params["tab"])) + // Just the "size" (of the page) of the query parameters is needed + queryParams$ = this.route.queryParams.pipe( + map(queryParams => ({ size: queryParams.size })) + ); + partialCounts$ = this.input$.pipe( switchMap(input => this.http.post(this.url, payloadWithKeywords(input)).pipe( map((response: any) => response.aggregations), @@ -58,12 +65,18 @@ export class TabNavigationComponent { defaultOrderButtons$: Observable = combineLatest([this.counts$, this.tab$]).pipe( map(([counts, tab]) => [ { label: $localize`:@@navigation.publications:Julkaisut`, icon: `faFileLines`, route: "/results/publications", count: counts.publications, active: tab === `publications` }, + { label: $localize`:@@navigation.funding-calls:Rahoitushaut`, icon: 'faBullhorn', route: "/results/funding-calls", count: counts.fundingCalls, active: tab === 'funding-calls' }, + + // label: $localize`:@@navigation.fundings:Hankkeet`, + { label: "Myönnetty rahoitus", icon: 'faBriefcase', route: "/results/fundings", count: counts.fundings, active: tab === 'fundings' }, + // "Myönnetty rahoitus", + { label: $localize`:@@navigation.persons:Tutkijat`, icon: 'faUsers', route: "/results/persons", count: counts.persons, active: tab === 'persons' }, - { label: $localize`:@@navigation.fundings:Hankkeet`, icon: 'faBriefcase', route: "/results/fundings", count: counts.fundings, active: tab === 'fundings' }, { label: $localize`:@@navigation.datasets:Aineistot`, icon: 'faFileAlt', route: "/results/datasets", count: counts.datasets, active: tab === 'datasets' }, - { label: $localize`:@@navigation.funding-calls:Rahoitushaut`, icon: 'faBullhorn', route: "/results/funding-calls", count: counts.fundingCalls, active: tab === 'funding-calls' }, { label: $localize`:@@navigation.infrastructures:Infrastruktuurit`, icon: 'faUniversity', route: "/results/infrastructures", count: counts.infrastructures, active: tab === 'infrastructures' }, { label: $localize`:@@navigation.organizations:Organisaatiot`, icon: 'faCalculator', route: "/results/organizations", count: counts.organizations, active: tab === 'organizations' }, + + { label: "Hankkeet (tulossa)", icon: `faFileLines`, route: "/results/publications", count: -1, active: false, disabled: true }, ]) ); @@ -89,10 +102,26 @@ export class TabNavigationComponent { }) ); - end$ = combineLatest([this.showAll$, this.responsiveSize$, this.defaultOrderButtons$]).pipe( + sliceEnd$ = combineLatest([this.showAll$, this.responsiveSize$, this.defaultOrderButtons$]).pipe( map<[boolean, number, ButtonData[]], number>(([showAll, end, buttons]) => showAll ? buttons.length : end) ); + slicedButtons$: Observable = combineLatest([this.responsiveOrder$, this.sliceEnd$]).pipe( + map(([buttons, end]) => buttons.slice(0, end)) + ); + + activeButton$: Observable = combineLatest([this.defaultOrderButtons$]).pipe( + map(([buttons]) => buttons.find(button => button.active)) + ); + + isActiveVisible$ = combineLatest([this.activeButton$, this.slicedButtons$]).pipe( + // See inclusion based on the label field + map(([active, buttons]) => buttons.map(b => b.label).includes(active.label)) + + // Compare button against buttons + // map(([active, buttons]) => buttons.includes(active)) + ); + isDesktop$ = this.breakpointObserver.observe(['(min-width: 1200px)']).pipe( map(result => result.matches) ); @@ -104,6 +133,28 @@ export class TabNavigationComponent { trackByLabel(index: number, button: ButtonData) { return button.label; } + + changeLastPartOfUrl(newLastSegment: string) { + // Extract the current URL segments. + this.route.url.subscribe((segments: UrlSegment[]) => { + const pathSegments = segments.map(s => s.path); + + if (pathSegments.length > 0) { + // Modify the last part of the path. + pathSegments[pathSegments.length - 1] = newLastSegment; + } + + // Retain the existing query parameters. + const queryParams = this.route.snapshot.queryParams; + + // Navigate to the new URL. + this.router.navigate([pathSegments.join('/')], { queryParams: queryParams }).then(success => { + if (!success) { + console.error('Navigation failed!'); + } + }); + }); + } } function payloadWithoutKeywords() { diff --git a/src/app/portal/models/person/person-activities-awards.model.ts b/src/app/portal/models/person/person-activities-awards.model.ts index 264dde4c7..739ea0fad 100644 --- a/src/app/portal/models/person/person-activities-awards.model.ts +++ b/src/app/portal/models/person/person-activities-awards.model.ts @@ -1,57 +1,56 @@ -// This file is part of the research.fi API service -// -// Copyright 2019 Ministry of Education and Culture, Finland -// -// :author: CSC - IT Center for Science Ltd., Espoo Finland servicedesk@csc.fi -// :license: MIT - -import { Adapter } from '../adapter.model'; -import { Injectable } from '@angular/core'; -import { ModelUtilsService } from '@shared/services/model-util.service'; - -export class PersonActivitiesAndRewards { - constructor( - public name: string, - public role: string, - public type: string, - public description: string, - public internationalCollaboration: string, - public year: string, - public organizationName: string, - public departmentName: string, - public url: string, - ) {} -} - -@Injectable({ - providedIn: 'root', -}) -export class PersonActivitiesAndRewardsAdapter - implements Adapter -{ - constructor(private utils: ModelUtilsService) {} - - adapt(activity: any): PersonActivitiesAndRewards { - console.log('activity', activity); - const getYearRange = () => { - return [activity.startDate.year, activity.endDate.year] - .filter((item) => item > 0) - .join(' - '); - }; - - const translateBoolean = (value: boolean) => - value ? $localize`:@@yes:Kyllä` : $localize`:@@no:Ei`; - - return new PersonActivitiesAndRewards( - this.utils.checkTranslation('name', activity), - this.utils.checkTranslation('roleName', activity), - this.utils.checkTranslation('activityTypeName', activity), - this.utils.checkTranslation('description', activity), - translateBoolean(activity.internationalCollaboration), - getYearRange(), - this.utils.checkTranslation('organizationName', activity), - this.utils.checkTranslation('departmentName', activity), - activity.url - ); - } -} +// This file is part of the research.fi API service +// +// Copyright 2019 Ministry of Education and Culture, Finland +// +// :author: CSC - IT Center for Science Ltd., Espoo Finland servicedesk@csc.fi +// :license: MIT + +import { Adapter } from '../adapter.model'; +import { Injectable } from '@angular/core'; +import { ModelUtilsService } from '@shared/services/model-util.service'; + +export class PersonActivitiesAndRewards { + constructor( + public name: string, + public role: string, + public type: string, + public description: string, + public internationalCollaboration: string, + public year: string, + public organizationName: string, + public departmentName: string, + public url: string, + ) {} +} + +@Injectable({ + providedIn: 'root', +}) +export class PersonActivitiesAndRewardsAdapter + implements Adapter +{ + constructor(private utils: ModelUtilsService) {} + + adapt(activity: any): PersonActivitiesAndRewards { + const getYearRange = () => { + return [activity.startDate.year, activity.endDate.year] + .filter((item) => item > 0) + .join(' - '); + }; + + const translateBoolean = (value: boolean) => + value ? $localize`:@@yes:Kyllä` : $localize`:@@no:Ei`; + + return new PersonActivitiesAndRewards( + this.utils.checkTranslation('name', activity), + this.utils.checkTranslation('roleName', activity), + this.utils.checkTranslation('activityTypeName', activity), + this.utils.checkTranslation('description', activity), + translateBoolean(activity.internationalCollaboration), + getYearRange(), + this.utils.checkTranslation('organizationName', activity), + this.utils.checkTranslation('departmentName', activity), + activity.url + ); + } +} diff --git a/src/app/portal/models/person/person.model.ts b/src/app/portal/models/person/person.model.ts index 627337b61..aa7dc3d4a 100644 --- a/src/app/portal/models/person/person.model.ts +++ b/src/app/portal/models/person/person.model.ts @@ -1,170 +1,176 @@ -// This file is part of the research.fi API service -// -// Copyright 2019 Ministry of Education and Culture, Finland -// -// :author: CSC - IT Center for Science Ltd., Espoo Finland servicedesk@csc.fi -// :license: MIT - -import { Injectable, Inject, LOCALE_ID } from '@angular/core'; -import { Adapter } from '../adapter.model'; -import { ModelUtilsService } from '@shared/services/model-util.service'; -import { - PersonActivitiesAndRewards, - PersonActivitiesAndRewardsAdapter, -} from './person-activities-awards.model'; -import { - PersonAffiliations, - PersonAffiliationAdapter, -} from './person-affiliation.model'; -import { PersonContact, PersonContactAdapter } from './person-contact.model'; -import { PersonDataset, PersonDatasetAdapter } from './person-dataset.model'; -import { PersonFunding, PersonFundingAdapter } from './person-funding.model'; -import { - PersonPublication, - PersonPublicationAdapter, -} from './person-publication.model'; -import sanitizeHtml from 'sanitize-html'; - -type Education = { degree: string; organization: string }; - -export class Person { - constructor( - public id: string, - public orcid: string, - public name: string, - public contact: PersonContact, - public affiliations: PersonAffiliations, - public educations: Education[], - public publications: PersonPublication[], - public datasets: PersonDataset[], - public fundings: PersonFunding[], - public activityAndAwards: PersonActivitiesAndRewards[], - public description: string, - public fieldsOfScience: string, - public keywords: string, - public collaboration: string[], - public uniqueDataSources: any, - public orcidLink?: string - ) {} -} - -@Injectable({ - providedIn: 'root', -}) -export class PersonAdapter implements Adapter { - constructor( - private utils: ModelUtilsService, - private affiliationAdapter: PersonAffiliationAdapter, - private contactAdapter: PersonContactAdapter, - private publicationAdapter: PersonPublicationAdapter, - private datasetAdapter: PersonDatasetAdapter, - private fundingAdapter: PersonFundingAdapter, - private activitiesAndRewardsAdapter: PersonActivitiesAndRewardsAdapter, - @Inject(LOCALE_ID) protected localeId: string - ) {} - adapt(data: any): Person { - const capitalizeFirstLetter = (str: string) => - str[0].toUpperCase() + str.slice(1); - - const names = data.personal.names[0]; - - // Capitalize first letter of each name - const fullName = `${capitalizeFirstLetter( - names.lastName - )}, ${names.firstNames - .split(' ') - .map((name) => capitalizeFirstLetter(name)).join(' ')}`; - - const contact = this.contactAdapter.adapt(data.personal); - - const affiliations = this.affiliationAdapter.adapt( - data.activity.affiliations - ); - - let collaboration: string[] = []; - - if (data?.cooperation) { - data.cooperation.forEach(item => { - collaboration.push(this.utils.checkTranslation( - 'name', - item - )); - }) - } - - const educations = data.activity.educations.map((item) => ({ - organization: item.degreeGrantingInstitutionName, - degree: this.utils.checkTranslation('name', item), - sources: this.utils.mapSources(item.dataSources), - dateRange: this.utils.getDateRange(item.startDate, item.endDate), - })); - - const publications = data.activity.publications.map((publication) => - this.publicationAdapter.adapt(publication) - ); - - // Sort datasets by year - let datasetsSorted = data.activity.researchDatasets.sort((a, b) => { - return b.datasetCreated - a.datasetCreated; - }); - const datasets = datasetsSorted.map((dataset) => - this.datasetAdapter.adapt(dataset) - ); - - // Sort funding decisions by year - let fundingsSorted = data.activity.fundingDecisions.sort((a, b) => { - const endYearDiff = b.fundingEndYear - a.fundingEndYear; - const startYearDiff = b.fundingStartYear - a.fundingStartYear; - if (endYearDiff !== 0) { - return endYearDiff; - } else - return startYearDiff; - }); - - let fundings = fundingsSorted.map((funding) => { - return this.fundingAdapter.adapt(funding); - } - ); - - const activityAndAwards = data.activity.activitiesAndRewards.map( - (activity) => this.activitiesAndRewardsAdapter.adapt(activity) - ); - - // Some descriptions might hold HTML tags. These should be stripped - const description = this.utils.checkTranslation( - 'researchDescription', - data.personal.researcherDescriptions[0] - ); - - const fieldsOfScience = 'Placeholder'; - - const keywords = data.personal.keywords - .map((keyword) => keyword.value) - .join(', '); - - const uniqueDataSources = data.uniqueDataSources - ?.map((item) => this.utils.checkTranslation('name', item.organization)) - .join(', '); - - return new Person( - data.id, - data.id, // ORCID indicator for dev puposes - fullName, - contact, - affiliations, - educations, - publications, - datasets, - fundings, - activityAndAwards, - sanitizeHtml(description, { - allowedTags: [], - allowedAttributes: {}, - }), - fieldsOfScience, - keywords, - collaboration, - uniqueDataSources - ); - } -} +// This file is part of the research.fi API service +// +// Copyright 2019 Ministry of Education and Culture, Finland +// +// :author: CSC - IT Center for Science Ltd., Espoo Finland servicedesk@csc.fi +// :license: MIT + +import { Injectable, Inject, LOCALE_ID } from '@angular/core'; +import { Adapter } from '../adapter.model'; +import { ModelUtilsService } from '@shared/services/model-util.service'; +import { + PersonActivitiesAndRewards, + PersonActivitiesAndRewardsAdapter, +} from './person-activities-awards.model'; +import { + PersonAffiliations, + PersonAffiliationAdapter, +} from './person-affiliation.model'; +import { PersonContact, PersonContactAdapter } from './person-contact.model'; +import { PersonDataset, PersonDatasetAdapter } from './person-dataset.model'; +import { PersonFunding, PersonFundingAdapter } from './person-funding.model'; +import { + PersonPublication, + PersonPublicationAdapter, +} from './person-publication.model'; +import sanitizeHtml from 'sanitize-html'; + +type Education = { degree: string; organization: string }; + +export class Person { + constructor( + public id: string, + public orcid: string, + public name: string, + public contact: PersonContact, + public affiliations: PersonAffiliations, + public educations: Education[], + public publications: PersonPublication[], + public datasets: PersonDataset[], + public fundings: PersonFunding[], + public activityAndAwards: PersonActivitiesAndRewards[], + public description: string, + public fieldsOfScience: string, + public keywords: string, + public collaboration: string[], + public uniqueDataSources: any, + public orcidLink?: string + ) {} +} + +@Injectable({ + providedIn: 'root', +}) +export class PersonAdapter implements Adapter { + constructor( + private utils: ModelUtilsService, + private affiliationAdapter: PersonAffiliationAdapter, + private contactAdapter: PersonContactAdapter, + private publicationAdapter: PersonPublicationAdapter, + private datasetAdapter: PersonDatasetAdapter, + private fundingAdapter: PersonFundingAdapter, + private activitiesAndRewardsAdapter: PersonActivitiesAndRewardsAdapter, + @Inject(LOCALE_ID) protected localeId: string + ) {} + adapt(data: any): Person { + const capitalizeFirstLetter = (str: string) => { + // Check if the string is null, undefined, or empty + if (!str || str.length === 0) { + return ''; + } + + return str[0].toUpperCase() + str.slice(1); + }; + + const names = data.personal.names[0]; + + // Capitalize first letter of each name + const fullName = `${capitalizeFirstLetter( + names.lastName + )}, ${names.firstNames + .split(' ') + .map((name) => capitalizeFirstLetter(name)).join(' ')}`; + + const contact = this.contactAdapter.adapt(data.personal); + + const affiliations = this.affiliationAdapter.adapt( + data.activity.affiliations + ); + + let collaboration: string[] = []; + + if (data?.cooperation) { + data.cooperation.forEach(item => { + collaboration.push(this.utils.checkTranslation( + 'name', + item + )); + }) + } + + const educations = data.activity.educations.map((item) => ({ + organization: item.degreeGrantingInstitutionName, + degree: this.utils.checkTranslation('name', item), + sources: this.utils.mapSources(item.dataSources), + dateRange: this.utils.getDateRange(item.startDate, item.endDate), + })); + + const publications = data.activity.publications.map((publication) => + this.publicationAdapter.adapt(publication) + ); + + // Sort datasets by year + let datasetsSorted = data.activity.researchDatasets.sort((a, b) => { + return b.datasetCreated - a.datasetCreated; + }); + const datasets = datasetsSorted.map((dataset) => + this.datasetAdapter.adapt(dataset) + ); + + // Sort funding decisions by year + let fundingsSorted = data.activity.fundingDecisions.sort((a, b) => { + const endYearDiff = b.fundingEndYear - a.fundingEndYear; + const startYearDiff = b.fundingStartYear - a.fundingStartYear; + if (endYearDiff !== 0) { + return endYearDiff; + } else + return startYearDiff; + }); + + let fundings = fundingsSorted.map((funding) => { + return this.fundingAdapter.adapt(funding); + } + ); + + const activityAndAwards = data.activity.activitiesAndRewards.map( + (activity) => this.activitiesAndRewardsAdapter.adapt(activity) + ); + + // Some descriptions might hold HTML tags. These should be stripped + const description = this.utils.checkTranslation( + 'researchDescription', + data.personal.researcherDescriptions[0] + ); + + const fieldsOfScience = 'Placeholder'; + + const keywords = data.personal.keywords + .map((keyword) => keyword.value) + .join(', '); + + const uniqueDataSources = data.uniqueDataSources + ?.map((item) => this.utils.checkTranslation('name', item.organization)) + .join(', '); + + return new Person( + data.id, + data.id, // ORCID indicator for dev puposes + fullName, + contact, + affiliations, + educations, + publications, + datasets, + fundings, + activityAndAwards, + sanitizeHtml(description, { + allowedTags: [], + allowedAttributes: {}, + }), + fieldsOfScience, + keywords, + collaboration, + uniqueDataSources + ); + } +} diff --git a/src/app/portal/models/search.model.ts b/src/app/portal/models/search.model.ts index 9c6254e74..b41031ebb 100644 --- a/src/app/portal/models/search.model.ts +++ b/src/app/portal/models/search.model.ts @@ -1,105 +1,105 @@ -// # This file is part of the research.fi API service -// # -// # Copyright 2019 Ministry of Education and Culture, Finland -// # -// # :author: CSC - IT Center for Science Ltd., Espoo Finland servicedesk@csc.fi -// # :license: MIT - -import { - Publication, - PublicationAdapter, -} from './publication/publication.model'; -import { Injectable } from '@angular/core'; -import { Adapter } from './adapter.model'; -import { PersonAdapter, Person } from './person/person.model'; -import { FundingAdapter, Funding } from './funding/funding.model'; -import { DatasetAdapter, Dataset } from './dataset/dataset.model'; -import { OrganizationAdapter, Organization } from './organization.model'; -import { - InfrastructureAdapter, - Infrastructure, -} from './infrastructure/infrastructure.model'; -import { FundingCall, FundingCallAdapter } from './funding-call.model'; - -export class Search { - constructor( - public total: number, - public publications: Publication[], - public persons: Person[], - public fundings: Funding[], - public datasets: Dataset[], - public infrastructures: Infrastructure[], - public organizations: Organization[], - public fundingCalls: FundingCall[] - ) {} -} - -@Injectable({ - providedIn: 'root', -}) -export class SearchAdapter implements Adapter { - constructor( - private publicationAdapter: PublicationAdapter, - private personAdapter: PersonAdapter, - private fundingAdapter: FundingAdapter, - private datasetAdapter: DatasetAdapter, - private organizationAdapter: OrganizationAdapter, - private infrastructureAdapter: InfrastructureAdapter, - private fundingCallAdapter: FundingCallAdapter - ) {} - adapt(item: any, tab?: string): Search { - const publications: Publication[] = []; - const persons: Person[] = []; - const fundings: Funding[] = []; - const datasets: Dataset[] = []; - const infrastructures: Infrastructure[] = []; - const organizations: Organization[] = []; - const fundingCalls: FundingCall[] = []; - - // Enables error handling when mapping data - const adaptResults = (tab, adapter) => { - item.hits.hits.forEach((e) => { - try { - tab.push(adapter.adapt(e._source)); - } catch (error) { - console.error(error); - } - }); - }; - - switch (tab) { - case 'publications': - adaptResults(publications, this.publicationAdapter); - break; - case 'persons': - adaptResults(persons, this.personAdapter); - break; - case 'fundings': - adaptResults(fundings, this.fundingAdapter); - break; - case 'datasets': - adaptResults(datasets, this.datasetAdapter); - break; - case 'infrastructures': - adaptResults(infrastructures, this.infrastructureAdapter); - break; - case 'organizations': - adaptResults(organizations, this.organizationAdapter); - break; - case 'funding-calls': - adaptResults(fundingCalls, this.fundingCallAdapter); - break; - } - - return new Search( - item.hits.total.value, - publications, - persons, - fundings, - datasets, - infrastructures, - organizations, - fundingCalls - ); - } -} +// # This file is part of the research.fi API service +// # +// # Copyright 2019 Ministry of Education and Culture, Finland +// # +// # :author: CSC - IT Center for Science Ltd., Espoo Finland servicedesk@csc.fi +// # :license: MIT + +import { + Publication, + PublicationAdapter, +} from './publication/publication.model'; +import { Injectable } from '@angular/core'; +import { Adapter } from './adapter.model'; +import { PersonAdapter, Person } from './person/person.model'; +import { FundingAdapter, Funding } from './funding/funding.model'; +import { DatasetAdapter, Dataset } from './dataset/dataset.model'; +import { OrganizationAdapter, Organization } from './organization.model'; +import { + InfrastructureAdapter, + Infrastructure, +} from './infrastructure/infrastructure.model'; +import { FundingCall, FundingCallAdapter } from './funding-call.model'; + +export class Search { + constructor( + public total: number, + public publications: Publication[], + public persons: Person[], + public fundings: Funding[], + public datasets: Dataset[], + public infrastructures: Infrastructure[], + public organizations: Organization[], + public fundingCalls: FundingCall[] + ) {} +} + +@Injectable({ + providedIn: 'root', +}) +export class SearchAdapter implements Adapter { + constructor( + private publicationAdapter: PublicationAdapter, + private personAdapter: PersonAdapter, + private fundingAdapter: FundingAdapter, + private datasetAdapter: DatasetAdapter, + private organizationAdapter: OrganizationAdapter, + private infrastructureAdapter: InfrastructureAdapter, + private fundingCallAdapter: FundingCallAdapter + ) {} + adapt(item: any, tab?: string): Search { + const publications: Publication[] = []; + const persons: Person[] = []; + const fundings: Funding[] = []; + const datasets: Dataset[] = []; + const infrastructures: Infrastructure[] = []; + const organizations: Organization[] = []; + const fundingCalls: FundingCall[] = []; + + // Enables error handling when mapping data + const adaptResults = (tab, adapter) => { + item.hits.hits.forEach((e) => { + try { + tab.push(adapter.adapt(e._source)); + } catch (error) { + console.error(error, e); + } + }); + }; + + switch (tab) { + case 'publications': + adaptResults(publications, this.publicationAdapter); + break; + case 'persons': + adaptResults(persons, this.personAdapter); + break; + case 'fundings': + adaptResults(fundings, this.fundingAdapter); + break; + case 'datasets': + adaptResults(datasets, this.datasetAdapter); + break; + case 'infrastructures': + adaptResults(infrastructures, this.infrastructureAdapter); + break; + case 'organizations': + adaptResults(organizations, this.organizationAdapter); + break; + case 'funding-calls': + adaptResults(fundingCalls, this.fundingCallAdapter); + break; + } + + return new Search( + item.hits.total.value, + publications, + persons, + fundings, + datasets, + infrastructures, + organizations, + fundingCalls + ); + } +}