[Explore & Library | explore-redesign]: Updated component for suggest SDGs or FoS.

1. alert.ts: Added previous button option.
2. composer.ts: Set feedback values in body | Make method "composeEmailForSdgsSuggestion()" generic to send feedback for either SDGs or FoS. - TODO: Rename method.
3. sdg-selection.component: Added some checks | Added method "getSelectedSubjects()".
4. sdg-fos-suggest.component: Updated component for suggestion | Send suggested subjects to composer | Add modal here | Make file generic for FoS or SDGs suggestion.
5. resultLanding.component: Updated how <sdg-fos-suggest> is called | Moved SDGs / FoS suggest modal inside <sdg-fos-suggest>.
This commit is contained in:
Konstantina Galouni 2023-02-18 10:52:24 +02:00
parent 79bcf402d6
commit 1ca647f56e
8 changed files with 196 additions and 83 deletions

View File

@ -1,5 +1,4 @@
import {HttpClient} from "@angular/common/http";
import {Component, Input, ViewChild} from "@angular/core";
import {ChangeDetectorRef, 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";
@ -7,53 +6,67 @@ import {EnvProperties} from "../../../utils/properties/env-properties";
import {EmailService} from "../../../utils/email/email.service";
import {Subscription} from "rxjs";
import {Composer} from "../../../utils/email/composer";
import {AlertModal} from "../../../utils/modal/alert";
import {StringUtils} from "../../../utils/string-utils.class";
@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>
`
<modal-alert #selectionModal [large]="true" (alertOutput)="modalOutput()" (cancelOutput)="modalCancel()"
[okDisabled]="!sent && !selectionStep1 && (form.invalid || sending)">
<sdg-selection *ngIf="subjectType == 'sdg'" #selection [class.uk-hidden]="!selectionStep1"
[subjects]="subjects"></sdg-selection>
<!-- <fos-selection *ngIf="subjectType == 'fos'" #selection [class.uk-hidden]="!selectionStep1"-->
<!-- [subjects]="subjects"></fos-selection>-->
<div [class.uk-hidden]="selectionStep1">
<div class="uk-flex uk-flex-column uk-flex-middle">
<ng-container *ngIf="!sent && !error">
<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>
</ng-container>
<ng-container *ngIf="sent">
<p>Your feedback is successfully received and it will soon be reviewed by our graph experts!</p>
<icon customClass="uk-text-background" name="check" [ratio]="4"></icon>
</ng-container>
<div *ngIf="error" class="uk-alert uk-alert-danger uk-text-center uk-width-large ng-star-inserted"
role="alert">Email sent failed! Please try again.
</div>
</div>
</div>
</modal-alert>
`
})
export class SdgFosSuggestComponent {
@Input("subjects") subjects;
@Input() entityType: string;
@Input() title;
public subjectType: "fos" | "sdg" = "sdg";
public subjects;
public properties: EnvProperties = properties;
public sdgSelectionStep1: boolean = true;
@ViewChild("sdgSelection") sdgSelection: SdgSelectionComponent;
public selectionStep1: boolean = true;
@ViewChild("selectionModal") selectionModal: AlertModal;
@ViewChild("selection") selection: SdgSelectionComponent;// | FosSelectionComponent;
public form: UntypedFormGroup;
public url: string = null;
public sending: boolean = false;
public sent: boolean = false;
public error: boolean = false;
subscriptions: Subscription[] = [];
constructor(
private emailService: EmailService,
private fb: FormBuilder
) {}
constructor(private emailService: EmailService, private fb: FormBuilder, private cdr: ChangeDetectorRef) {}
ngOnInit() {
let url;
if (typeof window !== "undefined") {
url = window.location.href;
this.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),
});
this.init();
}
ngOnDestroy() {
@ -64,16 +77,52 @@ export class SdgFosSuggestComponent {
});
}
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);
init() {
this.form = this.fb.group({
name: this.fb.control(this.title),
url: this.fb.control(this.url),
email: this.fb.control('', Validators.email),
subjects: this.fb.control([]),
recaptcha: this.fb.control('', Validators.required),
});
}
public openSelectionModal() {
this.sent = false;
this.sending = false;
this.error = false;
this.selectionStep1 = true;
this.init();
this.selectionModal.cancelButton = false;
if(this.subjectType == "sdg") {
this.selectionModal.alertTitle = "Please select SDGs that are the most relevant for this "+this.getEntityName(this.entityType)+".";
} else {
this.selectionModal.alertTitle = "Please select Fields of Science that are the most relevant for this "+this.getEntityName(this.entityType)+".";
}
this.selectionModal.okButtonText = "Next";
this.selectionModal.stayOpen = true;
this.cdr.detectChanges();
this.selectionModal.open();
}
public modalOutput() {
this.selectionModal.previousButton = true;
this.selectionModal.okButtonText = "Send feedback";
if(this.selectionStep1) {
this.selectionStep1 = false;
if(this.subjectType == "sdg") {
this.selectionModal.alertTitle = "Please send your feedback on most relevant SDGs for this "+this.getEntityName(this.entityType)+".";
} else {
this.selectionModal.alertTitle = "Please send your feedback on most relevant Fields of Science for this "+this.getEntityName(this.entityType)+".";
}
} else {
// email functionality
this.form.get("subjects").setValue(this.selection.getSelectedSubjects().map(subject => subject.id));
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;
Composer.composeEmailForSdgsSuggestion(this.form.value, [this.properties.feedbackmail], this.subjectType), 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,
@ -83,19 +132,41 @@ export class SdgFosSuggestComponent {
}
}));
}
// this.init();
// this.sent = true;
this.init();
this.sent = true;
this.selectionModal.alertTitle = "Thank you for your feedback";
this.selectionModal.okButtonText = "OK";
this.selectionModal.previousButton = false;
this.selectionModal.stayOpen = false;
}
// this.sending = false;
}, error => {
console.log(error);
// this.error = true;
// this.sending = false;
this.error = true;
this.sending = false;
}));
}
}
public modalCancel() {
if(this.subjectType == "sdg") {
this.selectionModal.alertTitle = "Please select SDGs that are the most relevant for this "+this.getEntityName(this.entityType)+".";
} else {
this.selectionModal.alertTitle = "Please select Fields of Science that are the most relevant for this "+this.getEntityName(this.entityType)+".";
}
this.selectionStep1 = true;
this.selectionModal.previousButton = false;
this.selectionModal.okButtonText = "Next";
this.selectionModal.stayOpen = true;
this.error = false;
}
public handleRecaptcha(captchaResponse: string) {
this.form.get('recaptcha').setValue(captchaResponse);
}
private getEntityName (entityType:string) {
return StringUtils.getEntityName(entityType, false);
}
}

View File

@ -5,11 +5,13 @@ 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";
import {AlertModalModule} from "../../../utils/modal/alertModal.module";
import {IconsModule} from "../../../utils/icons/icons.module";
@NgModule({
imports: [
CommonModule, FormsModule, InputModule, SdgSelectionModule, RecaptchaModule
],
imports: [
CommonModule, FormsModule, InputModule, SdgSelectionModule, RecaptchaModule, AlertModalModule, IconsModule
],
declarations: [
SdgFosSuggestComponent
],

View File

@ -794,7 +794,7 @@
<sdg [subjects]="resultLandingInfo.sdg" (viewAllClicked)="viewAll=$event" (suggestClicked)="suggestClicked($event)"></sdg>
</div>
<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)="viewAll=$event" (feedbackClicked)="suggestClicked('fos')"></fos>
</div>
<!-- Funded By -->
<div *ngIf="resultLandingInfo.fundedByProjects && resultLandingInfo.fundedByProjects.length > 0 && (!viewAll || viewAll=='fundedBy')">
@ -985,15 +985,17 @@
<div [innerHTML]="resultLandingInfo.description"></div>
</modal-alert>
<modal-alert *ngIf="resultLandingInfo && resultLandingInfo.sdg?.length > 0"
#sdgSelectionModal [large]="true" (alertOutput)="sdgModalOutput()">
<sdg-fos-suggest #sdgFosSuggest [subjects]="resultLandingInfo.sdg" [title]="resultLandingInfo.title"></sdg-fos-suggest>
</modal-alert>
<!--<modal-alert *ngIf="resultLandingInfo && resultLandingInfo.sdg?.length > 0"-->
<!-- #sdgSelectionModal [large]="true" (alertOutput)="sdgModalOutput()" (cancelOutput)="sdgModalCancel()">-->
<sdg-fos-suggest *ngIf="resultLandingInfo && (resultLandingInfo.sdg?.length > 0 || resultLandingInfo.fos?.length > 0)"
#sdgFosSuggest [title]="resultLandingInfo.title" [entityType]="resultLandingInfo.resultType">
</sdg-fos-suggest>
<!--</modal-alert>-->
<modal-alert *ngIf="resultLandingInfo && resultLandingInfo.fos?.length > 0"
#fosSelectionModal [large]="true">
<div>
<fos-selection [subjects]="resultLandingInfo.fos" [properties]="properties"></fos-selection>
<!-- <fos-selection [subjects]="resultLandingInfo.fos" [properties]="properties"></fos-selection>-->
</div>
</modal-alert>

View File

@ -115,7 +115,7 @@ export class ResultLandingComponent {
'Publisher information', 'Funding Information',
'Persistent identifiers', 'Sustainable Development Goals (SDGs)',
'Fields of Science and Technology (FOS)', 'Other'];
public pidsArrayString: string = "";
public identifier: Identifier;
@ -143,8 +143,6 @@ export class ResultLandingComponent {
// public shouldSticky: boolean = true;
public viewAll: string = "";
@ViewChild("sdgSelectionModal") sdgSelectionModal;
@ViewChild("fosSelectionModal") fosSelectionModal;
@ViewChild("sdgFosSuggest") sdgFosSuggest: SdgFosSuggestComponent;
public noCommunities: boolean = false;
@ -915,11 +913,15 @@ export class ResultLandingComponent {
public suggestClicked(value: string) {
if(value == 'sdg') {
this.openSdgSelectionModal();
this.sdgFosSuggest.subjects=this.resultLandingInfo.sdg;
this.sdgFosSuggest.subjectType="sdg";
} else if(value == 'fos') {
this.openFosSelectionModal();
console.log(this.resultLandingInfo.fos);
this.sdgFosSuggest.subjects=this.resultLandingInfo.fos;
this.sdgFosSuggest.subjectType="fos";
}
}
this.sdgFosSuggest.openSelectionModal();
}
public openDescriptionModal() {
this.descriptionModal.alertFooter = false;
@ -938,13 +940,13 @@ export class ResultLandingComponent {
return formatted.number + formatted.size;
}
private openSdgSelectionModal() {
this.sdgSelectionModal.cancelButton = false;
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();
}
// private openSdgSelectionModal() {
// this.sdgSelectionModal.cancelButton = false;
// this.sdgSelectionModal.alertTitle = "Please select SDGs that are the most relevant for this publication.";
// this.sdgSelectionModal.okButtonText = "Next";
// this.sdgSelectionModal.stayOpen = true;
// this.sdgSelectionModal.open();
// }
private openFosSelectionModal() {
this.fosSelectionModal.cancelButton = false;

View File

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

View File

@ -23,7 +23,7 @@ export class SdgSelectionComponent {
this.loading = true;
this.httpClient.get(this.properties.domain+'/assets/common-assets/vocabulary/sdg.json').subscribe(data => {
data['sdg'].forEach(element => {
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: 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: 'Not relevant', html: 'Not relevant', checked: false});
});
@ -37,4 +37,8 @@ export class SdgSelectionComponent {
public get secondColumn() {
return this.sdgs.slice(this.sdgs.length/2, this.sdgs.length);
}
public getSelectedSubjects() {
return this.sdgs.filter(sub => sub.checked == true);
}
}

View File

@ -137,15 +137,26 @@ export class Composer {
return email;
}
public static composeEmailForSdgsSuggestion(info: {name: string, url: string, email: string, sdgs: any[]}, recipients: string[]): Email {
public static composeEmailForSdgsSuggestion(info: {name: string, url: string, email: string, subjects: any[]}, recipients: string[], subjectType: "sdg" | "fos"): Email {
let typeName: string = "";
if(subjectType == "sdg") {
typeName = "Sustainable Development Goals (SDGs)";
} else {
typeName = "Fields of Science and Technology (FoS)";
}
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 "
+ "<p>A user" + ((info.email)?(" with email " + info.email):"") + " has reported the following "+typeName+" 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>";
});
if(info.subjects && info.subjects.length > 0) {
info.subjects.forEach((subject, index) => {
email.body += "<br><li><span><b>" + subject + "</b></span></li>";
});
} else {
email.body += "<br><b>No "+typeName+" selected</b>";
}
email.body += "</ul></div>";
email.recipients = recipients;
return email;

View File

@ -27,15 +27,21 @@ declare var UIkit: any;
<span class="uk-margin-small-left">Don't show this message again</span>
</label>
<div [ngClass]="(choice)?'uk-width-auto':'uk-width-1-1'">
<div class="uk-flex-right uk-grid uk-grid-small" uk-grid>
<span *ngIf="okButton" [class.uk-flex-last]="!okButtonLeft">
<button class="uk-button uk-button-primary" [disabled]="okDisabled"
[class.uk-disabled]="okDisabled" (click)="ok()">{{okButtonText}}</button>
</span>
<span *ngIf="cancelButton">
<div class="uk-width-1-1" [ngClass]="(previousButton && (cancelButton || okButton)) ? 'uk-flex uk-flex-between uk-grid' : ''">
<div *ngIf="previousButton" class="uk-flex-left">
<button class="uk-button uk-button-default uk-margin-small-left"
(click)="cancel()">{{cancelButtonText}}</button>
</span>
(click)="previous()">{{previousButtonText}}</button>
</div>
<div class="uk-flex-right uk-grid uk-grid-small" uk-grid>
<span *ngIf="okButton" [class.uk-flex-last]="!okButtonLeft">
<button class="uk-button uk-button-primary" [disabled]="okDisabled"
[class.uk-disabled]="okDisabled" (click)="ok()">{{okButtonText}}</button>
</span>
<span *ngIf="cancelButton">
<button class="uk-button uk-button-default uk-margin-small-left"
(click)="cancel()">{{cancelButtonText}}</button>
</span>
</div>
</div>
</div>
</div>
@ -85,6 +91,17 @@ export class AlertModal {
/**
* if the alertMessage is true it will show the contentString inside alert body.
*/
/**
* Describes if the alert contains Previous Button.
* The default Previous button will emit the callback.
* Defaults to false.
*/
public previousButton: boolean = false;
/**
* Caption for the Previous button.
* Default: Previous
*/
public previousButtonText: string = 'Previous';
public alertMessage: boolean = true;
/**
* Some message/content can be set in message which will be shown in alert body.
@ -188,4 +205,8 @@ export class AlertModal {
UIkit.modal(this.element.nativeElement).hide();
this.cancelOutput.emit(true);
}
previous() {
this.cancelOutput.emit();
}
}