diff --git a/dmp-frontend/src/app/core/model/dmp/cost.ts b/dmp-frontend/src/app/core/model/dmp/cost.ts new file mode 100644 index 000000000..ab432f02b --- /dev/null +++ b/dmp-frontend/src/app/core/model/dmp/cost.ts @@ -0,0 +1,9 @@ +import { FormGroup, FormBuilder, Validators } from '@angular/forms'; +import { ValidationContext } from '@common/forms/validation/validation-context'; + +export interface CostModel { + code: string; + description: string; + title: string; + value: number; +} diff --git a/dmp-frontend/src/app/ui/dmp/dmp.module.ts b/dmp-frontend/src/app/ui/dmp/dmp.module.ts index d331894da..67a9a3f76 100644 --- a/dmp-frontend/src/app/ui/dmp/dmp.module.ts +++ b/dmp-frontend/src/app/ui/dmp/dmp.module.ts @@ -32,6 +32,8 @@ import { FormValidationErrorsDialogModule } from '@common/forms/form-validation- import { CommonUiModule } from '@common/ui/common-ui.module'; import { MultipleChoiceDialogModule } from '@common/modules/multiple-choice-dialog/multiple-choice-dialog.module'; import { AddOrganizationComponent } from './editor/add-organization/add-organization.component'; +import { AddCostComponent } from './editor/cost-editor/add-cost/add-cost.component'; +import { CostListingComponent } from './editor/cost-editor/cost-listing/cost-listing.component'; @NgModule({ imports: [ @@ -69,7 +71,9 @@ import { AddOrganizationComponent } from './editor/add-organization/add-organiza GrantTabComponent, DatasetsTabComponent, DmpCloneComponent, - AddOrganizationComponent + AddOrganizationComponent, + AddCostComponent, + CostListingComponent ], entryComponents: [ DmpInvitationDialogComponent, @@ -77,7 +81,8 @@ import { AddOrganizationComponent } from './editor/add-organization/add-organiza AvailableProfilesComponent, DmpFinalizeDialogComponent, DmpUploadDialogue, - AddOrganizationComponent + AddOrganizationComponent, + AddCostComponent ] }) export class DmpModule { } diff --git a/dmp-frontend/src/app/ui/dmp/editor/cost-editor/add-cost/add-cost.component.html b/dmp-frontend/src/app/ui/dmp/editor/cost-editor/add-cost/add-cost.component.html new file mode 100644 index 000000000..fca4f3c07 --- /dev/null +++ b/dmp-frontend/src/app/ui/dmp/editor/cost-editor/add-cost/add-cost.component.html @@ -0,0 +1,28 @@ +
+

{{'ADDEDITCOST-EDITOR.ADD-TITLE' | translate}}

+
+ + + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + +
+
+
+
+
+
+
+
diff --git a/dmp-frontend/src/app/ui/dmp/editor/cost-editor/add-cost/add-cost.component.ts b/dmp-frontend/src/app/ui/dmp/editor/cost-editor/add-cost/add-cost.component.ts new file mode 100644 index 000000000..e6f8d57e7 --- /dev/null +++ b/dmp-frontend/src/app/ui/dmp/editor/cost-editor/add-cost/add-cost.component.ts @@ -0,0 +1,60 @@ +import { Component, Inject, OnInit } from '@angular/core'; +import { FormGroup } from '@angular/forms'; +import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { ExternalResearcherService } from '@app/core/services/external-sources/researcher/external-researcher.service'; +import { BaseComponent } from '@common/base/base.component'; +import { takeUntil } from 'rxjs/operators'; +import { CostEditorModel } from './add-cost.model'; +import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration'; +import { Observable } from 'rxjs'; +import { LocalFetchModel } from '@app/core/model/local-fetch/local-fetch.model'; +import { CurrencyService } from '@app/core/services/currency/currency.service'; + +@Component({ + selector: 'app-add-cost-component', + templateUrl: 'add-cost.component.html', +}) +export class AddCostComponent extends BaseComponent implements OnInit { + + public formGroup: FormGroup; + + currencyAutoCompleteConfiguration: SingleAutoCompleteConfiguration = { + filterFn: this.searchCurrency.bind(this), + initialItems: () => this.searchCurrency(''), + displayFn: (item) => typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name, + titleFn: (item) => typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name, + valueAssign: (item) => typeof (item) == 'string' ? JSON.parse(item)['value'] : item.value + }; + + constructor( + private externalResearcherService: ExternalResearcherService, + public dialogRef: MatDialogRef, + private currencyService: CurrencyService, + @Inject(MAT_DIALOG_DATA) public data: any + ) { super(); } + + ngOnInit(): void { + const cost = new CostEditorModel(); + this.formGroup = cost.buildForm(); + } + + send(value: any) { + this.externalResearcherService.createResearcher(this.formGroup.value) + .pipe(takeUntil(this._destroyed)) + .subscribe( + null, null, () => this.dialogRef.close() + ); + } + + addCost() { + this.dialogRef.close(this.formGroup.value); + } + + isFormValid() { + return this.formGroup.valid; + } + + searchCurrency(like: string): Observable { + return this.currencyService.get(like); + } +} diff --git a/dmp-frontend/src/app/ui/dmp/editor/cost-editor/add-cost/add-cost.model.ts b/dmp-frontend/src/app/ui/dmp/editor/cost-editor/add-cost/add-cost.model.ts new file mode 100644 index 000000000..252e4950d --- /dev/null +++ b/dmp-frontend/src/app/ui/dmp/editor/cost-editor/add-cost/add-cost.model.ts @@ -0,0 +1,44 @@ +import { FormBuilder, FormGroup } from '@angular/forms'; +import { ResearcherModel } from '@app/core/model/researcher/researcher'; +import { BackendErrorValidator } from '@common/forms/validation/custom-validator'; +import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model'; +import { ValidationContext } from '@common/forms/validation/validation-context'; +import { OrganizationModel } from '@app/core/model/organisation/organization'; +import { CostModel } from '@app/core/model/dmp/cost'; + +export class CostEditorModel implements CostModel{ + public code: string; + public description: string; + public title: string; + public value: number; + public validationErrorModel: ValidationErrorModel = new ValidationErrorModel(); + + fromModel(item: CostModel): CostEditorModel { + this.code = item.code; + this.description = item.description; + this.title = item.title; + this.value = item.value; + return this; + } + + buildForm(context: ValidationContext = null, disabled: boolean = false): FormGroup { + if (context == null) { context = this.createValidationContext(); } + const formGroup = new FormBuilder().group({ + code: [{ value: this.code, disabled: disabled }, context.getValidation('code').validators], + description: [{ value: this.description, disabled: disabled }, context.getValidation('description').validators], + title: [{ value: this.title, disabled: disabled }, context.getValidation('title').validators], + value: [{ value: this.value, disabled: disabled }, context.getValidation('value').validators] + }); + + return formGroup; + } + + createValidationContext(): ValidationContext { + const baseContext: ValidationContext = new ValidationContext(); + baseContext.validation.push({ key: 'code', validators: [] }); + baseContext.validation.push({ key: 'description', validators: [] }); + baseContext.validation.push({ key: 'title', validators: [BackendErrorValidator(this.validationErrorModel, 'title')] }); + baseContext.validation.push({ key: 'value', validators: [] }); + return baseContext; + } +} diff --git a/dmp-frontend/src/app/ui/dmp/editor/general-tab/extra-properties-form.model.ts b/dmp-frontend/src/app/ui/dmp/editor/general-tab/extra-properties-form.model.ts index 89d32c5ce..5d4d4d0a9 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/general-tab/extra-properties-form.model.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/general-tab/extra-properties-form.model.ts @@ -1,18 +1,26 @@ import { ValidationContext } from '@common/forms/validation/validation-context'; import { FormGroup, FormBuilder, Validators } from '@angular/forms'; import { BackendErrorValidator } from '@common/forms/validation/custom-validator'; +import { CostModel } from '@app/core/model/dmp/cost'; +import { isNullOrUndefined } from 'util'; export class ExtraPropertiesFormModel { public language: string; public license: string; public visible: boolean; public publicDate: Date; + public contact: string; + public costs: CostModel[] = []; fromModel(item: any): ExtraPropertiesFormModel { this.language = item.language; this.license = item.license; this.visible = item.visible; this.publicDate = item.publicDate; + this.contact = item.contact; + if (!isNullOrUndefined(item.costs)) { + this.costs = item.costs; + } return this; } @@ -23,7 +31,9 @@ export class ExtraPropertiesFormModel { language: [{ value: this.language, disabled: disabled }, context.getValidation('language').validators], license: [{ value: this.license, disabled: disabled }, context.getValidation('license').validators], visible: [{ value: this.visible, disabled: disabled }, context.getValidation('visible').validators], - publicDate: [{ value: this.publicDate, disabled: disabled }, context.getValidation('publicDate').validators] + publicDate: [{ value: this.publicDate, disabled: disabled }, context.getValidation('publicDate').validators], + contact: [{ value: this.contact, disabled: disabled }, context.getValidation('contact').validators], + costs: [{ value: this.costs, disabled: disabled }, context.getValidation('costs').validators] }); return formGroup; } @@ -34,6 +44,8 @@ export class ExtraPropertiesFormModel { baseContext.validation.push({ key: 'license', validators: [] }); baseContext.validation.push({ key: 'visible', validators: [] }); baseContext.validation.push({ key: 'publicDate', validators: [] }); + baseContext.validation.push({ key: 'contact', validators: [] }); + baseContext.validation.push({ key: 'costs', validators: [] }); return baseContext; } diff --git a/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.html b/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.html index ce433d868..5e18a75dd 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.html +++ b/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.html @@ -88,7 +88,7 @@ - {{formGroup.get('extraProperties').get('language').getError('backendError').message}} + {{formGroup.get('extraProperties').get('license').getError('backendError').message}} {{'GENERAL.VALIDATION.REQUIRED' | translate}} @@ -117,13 +117,34 @@ - - {{formGroup.get('extraProperties').get('visible').getError('backendError').message}} - + + {{formGroup.get('extraProperties').get('publicDate').getError('backendError').message}} + {{'GENERAL.VALIDATION.REQUIRED' | translate}} +
+ + + + + {{vis.name | translate}} + + + + {{formGroup.get('extraProperties').get('contact').getError('backendError').message}} + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + + +
+
+ +
diff --git a/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts b/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts index 0dee0573f..54387fa92 100644 --- a/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts +++ b/dmp-frontend/src/app/ui/dmp/editor/general-tab/general-tab.component.ts @@ -26,6 +26,7 @@ import { ConfigurationService } from '@app/core/services/configuration/configura import { LanguageInfoService } from '@app/core/services/culture/language-info-service'; import { LanguageInfo } from '@app/core/model/language-info'; import { LicenseCriteria } from '@app/core/query/license/license-criteria'; +import { AddCostComponent } from '../cost-editor/add-cost/add-cost.component'; interface Visible { value: boolean; @@ -253,4 +254,25 @@ export class GeneralTabComponent extends BaseComponent implements OnInit { getLanguageInfos(): LanguageInfo[] { return this.languageInfoService.getLanguageInfoValues(); } + + getAssociates(): any[] { + let associates: any[] = []; + //associates = (this.formGroup.get('researchers').value as any[]); + associates = associates.concat(this.formGroup.get('associatedUsers').value); + return associates; + } + + addCost(event: MouseEvent) { + event.stopPropagation(); + const dialogRef = this.dialog.open(AddCostComponent, { + data: this.formGroup.get('extraProperties').get('costs') + }); + dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => { + if (result) { + const costsArray = this.formGroup.get('extraProperties').get('costs').value || []; + costsArray.push(result); + this.formGroup.get('extraProperties').get('costs').setValue(costsArray); + } + }); + } } diff --git a/dmp-frontend/src/assets/i18n/en.json b/dmp-frontend/src/assets/i18n/en.json index 9c5ff334a..31a07273d 100644 --- a/dmp-frontend/src/assets/i18n/en.json +++ b/dmp-frontend/src/assets/i18n/en.json @@ -711,7 +711,8 @@ "LANGUAGE": "Language", "LICENSE": "License", "VISIBILITY": "Visibility", - "PUBLICATION": "Publication Date" + "PUBLICATION": "Publication Date", + "CONTACT": "Contact" }, "ACTIONS": { "GO-TO-GRANT": "Go To DMP Grant", @@ -986,6 +987,18 @@ "CANCEL": "Cancel" } }, + "ADDEDITCOST-EDITOR": { + "ADD-TITLE": "Add a Cost", + "EDIT-TITLE": "Edit the Cost", + "CODE": "Code", + "DESCRIPTION": "Description", + "TITLE": "Title", + "VALUE": "Value", + "ACTIONS": { + "SAVE": "Save", + "CANCEL": "Cancel" + } + }, "DMP-WIZARD": { "FIRST-STEP": { "DMP": "DMP Editor",