create new component for handling SDG suggestions

This commit is contained in:
Alex Martzios 2023-02-17 19:08:44 +02:00
parent 4858e9f22d
commit 75ad00db3f
11 changed files with 188 additions and 40 deletions

View File

@ -16,8 +16,6 @@ import {FosComponent} from "./fos.component";
import {SdgComponent} from "./sdg.component"; import {SdgComponent} from "./sdg.component";
import {IconsModule} from "../../utils/icons/icons.module"; import {IconsModule} from "../../utils/icons/icons.module";
import {AlertModalModule} from "../../utils/modal/alertModal.module"; import {AlertModalModule} from "../../utils/modal/alertModal.module";
import {SdgSelectionComponent} from '../../sdg/sdg-selection/sdg-selection.component';
import {FosSelectionComponent} from '../../fos/fos-selection/fos-selection.component';
import { SearchInputModule } from '../../sharedComponents/search-input/search-input.module'; import { SearchInputModule } from '../../sharedComponents/search-input/search-input.module';
@ -29,16 +27,14 @@ import { SearchInputModule } from '../../sharedComponents/search-input/search-in
declarations: [ declarations: [
ShowIdentifiersComponent,ShowSubjectsComponent, ShowIdentifiersComponent,ShowSubjectsComponent,
FundedByComponent,AvailableOnComponent,TabTableComponent, FundedByComponent,AvailableOnComponent,TabTableComponent,
RelatedToComponent, FosComponent, SdgComponent, RelatedToComponent, FosComponent, SdgComponent
SdgSelectionComponent, FosSelectionComponent
], ],
providers:[ providers:[
], ],
exports: [ exports: [
ShowIdentifiersComponent, ShowSubjectsComponent, ShowIdentifiersComponent, ShowSubjectsComponent,
FundedByComponent,AvailableOnComponent, TabTableComponent, ShowPublisherComponent, FundedByComponent,AvailableOnComponent, TabTableComponent, ShowPublisherComponent,
RelatedToComponent, FosComponent, SdgComponent, RelatedToComponent, FosComponent, SdgComponent
SdgSelectionComponent, FosSelectionComponent
] ]
}) })
export class ResultLandingUtilsModule { } export class ResultLandingUtilsModule { }

View File

@ -0,0 +1,101 @@
import {HttpClient} from "@angular/common/http";
import {Component, Input, ViewChild} from "@angular/core";
import {FormBuilder, UntypedFormGroup, Validators} from "@angular/forms";
import {SdgSelectionComponent} from "../../../sdg/sdg-selection/sdg-selection.component";
import {properties} from "../../../../../environments/environment";
import {EnvProperties} from "../../../utils/properties/env-properties";
import {EmailService} from "../../../utils/email/email.service";
import {Subscription} from "rxjs";
import {Composer} from "../../../utils/email/composer";
@Component({
selector: 'sdg-fos-suggest',
template: `
<sdg-selection #sdgSelection [class.uk-hidden]="!sdgSelectionStep1" [subjects]="subjects"></sdg-selection>
<div [class.uk-hidden]="sdgSelectionStep1">
<div class="uk-flex uk-flex-column uk-flex-middle">
<div>Thank you for your feedback.</div>
<div>Before sending us your options, would you like to leave us your e-mail to notify you about the reporting status?</div>
<div input class="uk-width-1-2 uk-margin-medium-top uk-margin-medium-bottom"
[formInput]="form.get('email')" placeholder="E-mail">
</div>
<div>
<re-captcha (resolved)="handleRecaptcha($event)" [siteKey]="properties.reCaptchaSiteKey">
</re-captcha>
</div>
</div>
</div>
`
})
export class SdgFosSuggestComponent {
@Input("subjects") subjects;
@Input() title;
public properties: EnvProperties = properties;
public sdgSelectionStep1: boolean = true;
@ViewChild("sdgSelection") sdgSelection: SdgSelectionComponent;
public form: UntypedFormGroup;
subscriptions: Subscription[] = [];
constructor(
private emailService: EmailService,
private fb: FormBuilder
) {}
ngOnInit() {
let url;
if (typeof window !== "undefined") {
url = window.location.href;
}
this.form = this.fb.group({
name: this.fb.control(this.title),
url: this.fb.control(url),
email: this.fb.control('', Validators.email),
sdgs: this.fb.array([], Validators.required),
recaptcha: this.fb.control('', Validators.required),
});
}
ngOnDestroy() {
this.subscriptions.forEach(subscription => {
if (subscription instanceof Subscription) {
subscription.unsubscribe();
}
});
}
public sdgModalOutput() {
if(this.sdgSelectionStep1) {
this.sdgSelectionStep1 = false;
} else {
console.log(this.sdgSelection.sdgs.filter(element => element.checked == true));
console.log(this.form.get('email').value);
// email functionality
this.subscriptions.push(this.emailService.contact(this.properties,
Composer.composeEmailForSdgsSuggestion(this.form.value, [this.properties.feedbackmail]), this.form.get('recaptcha').value).subscribe(sent => {
// this.error = !sent;
if (sent) {
if (this.form.get('email').value !== '') {
this.subscriptions.push(this.emailService.contact(this.properties,
Composer.composeEmailForUserAfterFeedback([this.form.get('email').value])).subscribe(sent => {
if (sent) {
//console.log('An email has been sent to user ' + this.form.get('email').value);
}
}));
}
// this.init();
// this.sent = true;
}
// this.sending = false;
}, error => {
console.log(error);
// this.error = true;
// this.sending = false;
}));
}
}
public handleRecaptcha(captchaResponse: string) {
this.form.get('recaptcha').setValue(captchaResponse);
}
}

View File

@ -0,0 +1,25 @@
import {CommonModule} from "@angular/common";
import {NgModule} from "@angular/core";
import {FormsModule} from "@angular/forms";
import {RecaptchaModule} from "ng-recaptcha";
import {SdgSelectionModule} from "src/app/openaireLibrary/sdg/sdg-selection/sdg-selection.module";
import {InputModule} from "../../../sharedComponents/input/input.module";
import {SdgFosSuggestComponent} from "./sdg-fos-suggest.component";
@NgModule({
imports: [
CommonModule, FormsModule, InputModule, SdgSelectionModule, RecaptchaModule
],
declarations: [
SdgFosSuggestComponent
],
providers: [
],
exports: [
SdgFosSuggestComponent
]
})
export class SdgFosSuggestModule {
}

View File

@ -14,13 +14,13 @@ import {StringUtils} from "../../utils/string-utils.class";
<icon class="uk-margin-small-right" name="arrow_back" flex="true" ratio="1.2"></icon> <icon class="uk-margin-small-right" name="arrow_back" flex="true" ratio="1.2"></icon>
<span uk-tooltip="Sustainable Development Goals">{{title}}</span> <span uk-tooltip="Sustainable Development Goals">{{title}}</span>
</span> </span>
<span *ngIf="!viewAll" class="uk-text-emphasis uk-text-bolder uk-text-nowrap uk-margin-small-right" uk-tooltip="Sustainable Development Goals">{{title}}</span> <span *ngIf="!viewAll" class="uk-text-emphasis uk-text-bolder uk-text-nowrap uk-margin-small-right" uk-tooltip="Sustainable Development Goals">{{title}} ({{subjects.length}})</span>
<!-- <a *ngIf="viewAll && lessBtn" (click)="viewAll = !viewAll; lessBtn=false;">View less</a> --> <!-- <a *ngIf="viewAll && lessBtn" (click)="viewAll = !viewAll; lessBtn=false;">View less</a> -->
<a *ngIf="subjects && subjects.length > threshold && !viewAll" <a *ngIf="subjects && subjects.length > threshold && !viewAll"
(click)="viewAllClick();" class="view-more-less-link uk-text-truncate"> (click)="viewAllClick();" class="view-more-less-link uk-link uk-link-text uk-text-truncate">
View all & suggest</a> View all & suggest</a>
<a *ngIf="(subjects && subjects.length <= threshold || viewAll)" class="uk-link uk-text-truncate" <a *ngIf="(subjects && subjects.length <= threshold || viewAll)" class="uk-link uk-link-text uk-text-truncate"
(click)="feedbackClick();">Feedback</a> (click)="suggestClick();">Suggest</a>
</div> </div>
<div class="uk-margin-small-bottom uk-flex"> <div class="uk-margin-small-bottom uk-flex">
<img src="assets/common-assets/common/The_Global_Goals_Icon_Color.svg" <img src="assets/common-assets/common/The_Global_Goals_Icon_Color.svg"
@ -59,7 +59,7 @@ export class SdgComponent {
@Input() subjects: string[]; @Input() subjects: string[];
@Input() viewAll: boolean = false; @Input() viewAll: boolean = false;
@Output() viewAllClicked = new EventEmitter(); @Output() viewAllClicked = new EventEmitter();
@Output() feedbackClicked = new EventEmitter(); @Output() suggestClicked = new EventEmitter();
public lessBtn: boolean = false; public lessBtn: boolean = false;
public threshold: number = 2; public threshold: number = 2;
public routerHelper: RouterHelper = new RouterHelper(); public routerHelper: RouterHelper = new RouterHelper();
@ -71,7 +71,7 @@ export class SdgComponent {
// this.viewAll = true; // this.viewAll = true;
// this.lessBtn = true; // this.lessBtn = true;
// } else { // } else {
// this.viewAll = true; this.viewAll = true;
this.viewAllClicked.emit('sdg'); this.viewAllClicked.emit('sdg');
// } // }
} }
@ -81,8 +81,8 @@ export class SdgComponent {
this.viewAllClicked.emit(""); this.viewAllClicked.emit("");
} }
public feedbackClick() { public suggestClick() {
this.feedbackClicked.emit(""); this.suggestClicked.emit('sdg');
} }
public urlEncodeAndQuote(str: string): string { public urlEncodeAndQuote(str: string): string {

View File

@ -735,7 +735,7 @@
<ng-template #right_column> <ng-template #right_column>
<!-- new metrics box --> <!-- new metrics box -->
<div *ngIf="resultLandingInfo && resultLandingInfo.measure" <div *ngIf="resultLandingInfo && resultLandingInfo.measure && !viewAll"
class="uk-margin-medium-top uk-padding uk-padding-remove-vertical"> class="uk-margin-medium-top uk-padding uk-padding-remove-vertical">
<div class="landing-metrics-card uk-card uk-card-secondary uk-text-small uk-flex uk-padding-small"> <div class="landing-metrics-card uk-card uk-card-secondary uk-text-small uk-flex uk-padding-small">
<div class="uk-width-expand uk-flex uk-flex-middle"> <div class="uk-width-expand uk-flex uk-flex-middle">
@ -791,7 +791,7 @@
</div> </div>
<div *ngIf="resultLandingInfo.sdg && resultLandingInfo.sdg.length > 0 && (!viewAll || viewAll=='sdg')"> <div *ngIf="resultLandingInfo.sdg && resultLandingInfo.sdg.length > 0 && (!viewAll || viewAll=='sdg')">
<sdg [subjects]="resultLandingInfo.sdg" (viewAllClicked)="openSelectionModal($event)" (feedbackClicked)="feedbackClicked('Sustainable Development Goals (SDGs)')"></sdg> <sdg [subjects]="resultLandingInfo.sdg" (viewAllClicked)="viewAll=$event" (suggestClicked)="suggestClicked($event)"></sdg>
</div> </div>
<div *ngIf="resultLandingInfo.fos && resultLandingInfo.fos.length > 0 && (!viewAll || viewAll=='fos')"> <div *ngIf="resultLandingInfo.fos && resultLandingInfo.fos.length > 0 && (!viewAll || viewAll=='fos')">
<fos [subjects]="resultLandingInfo.fos" (viewAllClicked)="openSelectionModal($event)" (feedbackClicked)="feedbackClicked('Fields of Science and Technology (FOS)')"></fos> <fos [subjects]="resultLandingInfo.fos" (viewAllClicked)="openSelectionModal($event)" (feedbackClicked)="feedbackClicked('Fields of Science and Technology (FOS)')"></fos>
@ -986,8 +986,8 @@
</modal-alert> </modal-alert>
<modal-alert *ngIf="resultLandingInfo && resultLandingInfo.sdg?.length > 0" <modal-alert *ngIf="resultLandingInfo && resultLandingInfo.sdg?.length > 0"
#sdgSelectionModal [large]="true"> #sdgSelectionModal [large]="true" (alertOutput)="sdgModalOutput()">
<sdg-selection [subjects]="resultLandingInfo.sdg" [properties]="properties"></sdg-selection> <sdg-fos-suggest #sdgFosSuggest [subjects]="resultLandingInfo.sdg" [title]="resultLandingInfo.title"></sdg-fos-suggest>
</modal-alert> </modal-alert>
<modal-alert *ngIf="resultLandingInfo && resultLandingInfo.fos?.length > 0" <modal-alert *ngIf="resultLandingInfo && resultLandingInfo.fos?.length > 0"

View File

@ -26,6 +26,7 @@ import {UserManagementService} from "../../services/user-management.service";
import {OpenaireEntities} from "../../utils/properties/searchFields"; import {OpenaireEntities} from "../../utils/properties/searchFields";
import {Option} from "../../sharedComponents/input/input.component"; import {Option} from "../../sharedComponents/input/input.component";
import {NumberUtils} from '../../utils/number-utils.class'; import {NumberUtils} from '../../utils/number-utils.class';
import {SdgFosSuggestComponent} from '../landing-utils/sdg-fos-suggest/sdg-fos-suggest.component';
declare var ResizeObserver; declare var ResizeObserver;
@ -144,6 +145,7 @@ export class ResultLandingComponent {
public viewAll: string = ""; public viewAll: string = "";
@ViewChild("sdgSelectionModal") sdgSelectionModal; @ViewChild("sdgSelectionModal") sdgSelectionModal;
@ViewChild("fosSelectionModal") fosSelectionModal; @ViewChild("fosSelectionModal") fosSelectionModal;
@ViewChild("sdgFosSuggest") sdgFosSuggest: SdgFosSuggestComponent;
public noCommunities: boolean = false; public noCommunities: boolean = false;
@ -911,6 +913,14 @@ export class ResultLandingComponent {
this.viewAll = ""; this.viewAll = "";
} }
public suggestClicked(value: string) {
if(value == 'sdg') {
this.openSdgSelectionModal();
} else if(value == 'fos') {
this.openFosSelectionModal();
}
}
public openDescriptionModal() { public openDescriptionModal() {
this.descriptionModal.alertFooter = false; this.descriptionModal.alertFooter = false;
this.descriptionModal.alertTitle = "Abstract"; this.descriptionModal.alertTitle = "Abstract";
@ -928,17 +938,11 @@ export class ResultLandingComponent {
return formatted.number + formatted.size; return formatted.number + formatted.size;
} }
public openSelectionModal(value: string) {
if(value == 'sdg') {
this.openSdgSelectionModal();
} else if(value == 'fos') {
this.openFosSelectionModal();
}
}
private openSdgSelectionModal() { private openSdgSelectionModal() {
this.sdgSelectionModal.cancelButton = false; this.sdgSelectionModal.cancelButton = false;
this.sdgSelectionModal.alertTitle = "Please select SDGs that are the most relevant for this publication."; this.sdgSelectionModal.alertTitle = "Please select SDGs that are the most relevant for this publication.";
this.sdgSelectionModal.okButtonText = "Send feedback";
this.sdgSelectionModal.stayOpen = true;
this.sdgSelectionModal.open(); this.sdgSelectionModal.open();
} }
@ -947,4 +951,8 @@ export class ResultLandingComponent {
this.fosSelectionModal.alertTitle = "Please select FOS that are the most relevant for this publication."; this.fosSelectionModal.alertTitle = "Please select FOS that are the most relevant for this publication.";
this.fosSelectionModal.open(); this.fosSelectionModal.open();
} }
public sdgModalOutput() {
this.sdgFosSuggest.sdgModalOutput();
}
} }

View File

@ -36,6 +36,8 @@ import {IconsService} from "../../utils/icons/icons.service";
import {graph, link, quotes, cite, link_to, versions, rocket, fire, landmark, open_access, closed_access} from "../../utils/icons/icons"; import {graph, link, quotes, cite, link_to, versions, rocket, fire, landmark, open_access, closed_access} from "../../utils/icons/icons";
import {InputModule} from "../../sharedComponents/input/input.module"; import {InputModule} from "../../sharedComponents/input/input.module";
import {EGIDataTransferModule} from "../../utils/dataTransfer/transferData.module"; import {EGIDataTransferModule} from "../../utils/dataTransfer/transferData.module";
import {RecaptchaModule} from 'ng-recaptcha';
import {SdgFosSuggestModule} from '../landing-utils/sdg-fos-suggest/sdg-fos-suggest.module';
@NgModule({ @NgModule({
imports: [ imports: [
@ -44,7 +46,8 @@ import {EGIDataTransferModule} from "../../utils/dataTransfer/transferData.modul
MetricsModule, AltMetricsModule, Schema2jsonldModule, SEOServiceModule, MetricsModule, AltMetricsModule, Schema2jsonldModule, SEOServiceModule,
DeletedByInferenceModule, ShowAuthorsModule, HelperModule, ResultLandingUtilsModule, AlertModalModule, DeletedByInferenceModule, ShowAuthorsModule, HelperModule, ResultLandingUtilsModule, AlertModalModule,
AnnotationModule, LandingHeaderModule, NoLoadPaging, ResultPreviewModule, FeedbackModule, TabsModule, LoadingModule, AnnotationModule, LandingHeaderModule, NoLoadPaging, ResultPreviewModule, FeedbackModule, TabsModule, LoadingModule,
OrcidModule, MatFormFieldModule, MatSelectModule, IconsModule, InputModule, EGIDataTransferModule OrcidModule, MatFormFieldModule, MatSelectModule, IconsModule, InputModule, EGIDataTransferModule, RecaptchaModule,
SdgFosSuggestModule
], ],
declarations: [ declarations: [
ResultLandingComponent ResultLandingComponent

View File

@ -6,8 +6,8 @@
<div> <div>
<div *ngFor="let item of firstColumn; let i = index" <div *ngFor="let item of firstColumn; let i = index"
class="uk-margin-bottom"> class="uk-margin-bottom">
<label> <label [class.uk-text-bolder]="subjects.includes(item.id)">
<input [checked]="subjects.includes(item.id)" <input [(ngModel)]="item.checked"
type="checkbox" class="uk-checkbox uk-margin-small-right"> type="checkbox" class="uk-checkbox uk-margin-small-right">
<span class="uk-text-uppercase uk-margin-xsmall-right">Goal</span> <span class="uk-text-uppercase uk-margin-xsmall-right">Goal</span>
<span>{{item.id}}</span> <span>{{item.id}}</span>
@ -17,8 +17,8 @@
<div> <div>
<div *ngFor="let item of secondColumn; let i = index" <div *ngFor="let item of secondColumn; let i = index"
class="uk-margin-bottom"> class="uk-margin-bottom">
<label> <label [class.uk-text-bolder]="subjects.includes(item.id)">
<input [checked]="subjects.includes(item.id)" <input [(ngModel)]="item.checked"
type="checkbox" class="uk-checkbox uk-margin-small-right"> type="checkbox" class="uk-checkbox uk-margin-small-right">
<span *ngIf="i !== secondColumn.length - 1" <span *ngIf="i !== secondColumn.length - 1"
class="uk-text-uppercase uk-margin-xsmall-right">Goal</span> class="uk-text-uppercase uk-margin-xsmall-right">Goal</span>

View File

@ -1,5 +1,6 @@
import {HttpClient} from "@angular/common/http"; import {HttpClient} from "@angular/common/http";
import {Component, Input} from "@angular/core"; import {Component, Input} from "@angular/core";
import {properties} from "../../../../environments/environment";
import {EnvProperties} from "../../utils/properties/env-properties"; import {EnvProperties} from "../../utils/properties/env-properties";
@Component({ @Component({
@ -8,7 +9,7 @@ import {EnvProperties} from "../../utils/properties/env-properties";
styleUrls: ['sdg-selection.component.less'] styleUrls: ['sdg-selection.component.less']
}) })
export class SdgSelectionComponent { export class SdgSelectionComponent {
@Input() properties: EnvProperties; public properties: EnvProperties = properties;
@Input() subjects: string[]; @Input() subjects: string[];
public loading: boolean; public loading: boolean;
@ -21,9 +22,10 @@ export class SdgSelectionComponent {
ngOnInit() { ngOnInit() {
this.loading = true; this.loading = true;
this.httpClient.get(this.properties.domain+'/assets/common-assets/vocabulary/sdg.json').subscribe(data => { this.httpClient.get(this.properties.domain+'/assets/common-assets/vocabulary/sdg.json').subscribe(data => {
this.sdgs = data['sdg']; data['sdg'].forEach(element => {
console.log(this.sdgs); this.sdgs.push({code: element.code, id: element.id, label: element.label, html: element.html, checked: this.subjects.includes(element.id)});
this.sdgs.push({code: '18', id: 'No SDGs are relevant for this publication', label: 'No SDG relevant', html: 'No SDG relevant'}) });
this.sdgs.push({code: '18', id: 'No SDGs are relevant for this publication', label: 'Not relevant', html: 'Not relevant', checked: false});
}); });
this.loading = false; this.loading = false;
} }

View File

@ -3,21 +3,20 @@ import {NgModule} from "@angular/core";
import {FormsModule} from "@angular/forms"; import {FormsModule} from "@angular/forms";
import {InputModule} from "../../sharedComponents/input/input.module"; import {InputModule} from "../../sharedComponents/input/input.module";
import {LoadingModule} from "../../utils/loading/loading.module"; import {LoadingModule} from "../../utils/loading/loading.module";
import {SdgSelectionComponent} from "./sdg-selection.component";
// import {SdgSelectionComponent} from './sdg-selection.component';
@NgModule({ @NgModule({
imports: [ imports: [
CommonModule, FormsModule, LoadingModule, InputModule CommonModule, FormsModule, LoadingModule, InputModule
], ],
declarations: [ declarations: [
// SdgSelectionComponent SdgSelectionComponent
], ],
providers: [ providers: [
], ],
exports: [ exports: [
// SdgSelectionComponent SdgSelectionComponent
] ]
}) })
export class SdgSelectionModule { export class SdgSelectionModule {

View File

@ -137,6 +137,20 @@ export class Composer {
return email; return email;
} }
public static composeEmailForSdgsSuggestion(info: {name: string, url: string, email: string, sdgs: any[]}, recipients: string[]): Email {
let email: Email = new Email();
email.subject = 'Feedback report for ' + info.name;
email.body = "<div style='font-size:" + this.noteBodySize + "'>"
+ "<p>A user" + ((info.email)?(" with email " + info.email):"") + " has reported the following SDG(s) for "
+ "<a href=\'" + info.url + "\'>" + info.name + "</a></p><ul>";
info.sdgs.forEach((issue, index) => {
email.body += "<br><li><span><b><u>" + issue + "</u></b></span></li>";
});
email.body += "</ul></div>";
email.recipients = recipients;
return email;
}
public static composeEmailForUserAfterFeedback(recipients: string[]): Email { public static composeEmailForUserAfterFeedback(recipients: string[]): Email {
let email: Email = new Email(); let email: Email = new Email();
email.subject = 'Feedback report received'; email.subject = 'Feedback report received';