mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 18:14:17 +00:00
69432: Profile page intermediate commit
This commit is contained in:
@@ -1411,6 +1411,40 @@
|
||||
|
||||
|
||||
|
||||
"profile.breadcrumbs": "Update Profile",
|
||||
|
||||
"profile.card.identify": "Identify",
|
||||
|
||||
"profile.card.security": "Security",
|
||||
|
||||
"profile.form.submit": "Update Profile",
|
||||
|
||||
"profile.head": "Update Profile",
|
||||
|
||||
"profile.metadata.form.error.firstname": "First Name is required",
|
||||
|
||||
"profile.metadata.form.error.lastname": "Last Name is required",
|
||||
|
||||
"profile.metadata.form.label.email": "Email Address",
|
||||
|
||||
"profile.metadata.form.label.firstname": "First Name",
|
||||
|
||||
"profile.metadata.form.label.language": "Language",
|
||||
|
||||
"profile.metadata.form.label.lastname": "Last Name",
|
||||
|
||||
"profile.metadata.form.label.phone": "Contact Telephone",
|
||||
|
||||
"profile.security.form.info": "Optionally, you can enter a new password in the box below, and confirm it by typing it again into the second box. It should be at least six characters long.",
|
||||
|
||||
"profile.security.form.label.password": "Password",
|
||||
|
||||
"profile.security.form.label.passwordrepeat": "Retype to confirm",
|
||||
|
||||
"profile.title": "Update Profile",
|
||||
|
||||
|
||||
|
||||
"project.listelement.badge": "Research Project",
|
||||
|
||||
"project.page.contributor": "Contributors",
|
||||
|
@@ -68,6 +68,7 @@ export function getDSOPath(dso: DSpaceObject): string {
|
||||
{ path: 'submit', loadChildren: './+submit-page/submit-page.module#SubmitPageModule' },
|
||||
{ path: 'workspaceitems', loadChildren: './+workspaceitems-edit-page/workspaceitems-edit-page.module#WorkspaceitemsEditPageModule' },
|
||||
{ path: 'workflowitems', loadChildren: './+workflowitems-edit-page/workflowitems-edit-page.module#WorkflowItemsEditPageModule' },
|
||||
{ path: 'profile', loadChildren: './profile-page/profile-page.module#ProfilePageModule', canActivate: [AuthenticatedGuard] },
|
||||
{ path: '**', pathMatch: 'full', component: PageNotFoundComponent },
|
||||
])
|
||||
],
|
||||
|
@@ -0,0 +1,5 @@
|
||||
<ds-form *ngIf="formModel"
|
||||
[formId]="'profile-page-metadata-form-id'"
|
||||
[formModel]="formModel"
|
||||
[displaySubmit]="false">
|
||||
</ds-form>
|
@@ -0,0 +1,147 @@
|
||||
import { Component, Inject, Input, OnInit } from '@angular/core';
|
||||
import {
|
||||
DynamicFormControlModel,
|
||||
DynamicFormService, DynamicFormValueControlModel,
|
||||
DynamicInputModel, DynamicSelectModel
|
||||
} from '@ng-dynamic-forms/core';
|
||||
import { FormGroup } from '@angular/forms';
|
||||
import { EPerson } from '../../core/eperson/models/eperson.model';
|
||||
import { Location } from '@angular/common';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { hasValue, isNotEmpty } from '../../shared/empty.util';
|
||||
import { GLOBAL_CONFIG, GlobalConfig } from '../../../config';
|
||||
import { LangConfig } from '../../../config/lang-config.interface';
|
||||
import { EPersonDataService } from '../../core/eperson/eperson-data.service';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { getRemoteDataPayload, getSucceededRemoteData } from '../../core/shared/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-profile-page-metadata-form',
|
||||
templateUrl: './profile-page-metadata-form.component.html'
|
||||
})
|
||||
export class ProfilePageMetadataFormComponent implements OnInit {
|
||||
/**
|
||||
* The user to display the form for
|
||||
*/
|
||||
@Input() user: EPerson;
|
||||
|
||||
formModel: DynamicFormControlModel[] = [
|
||||
new DynamicInputModel({
|
||||
id: 'email',
|
||||
name: 'email',
|
||||
readOnly: true
|
||||
}),
|
||||
new DynamicInputModel({
|
||||
id: 'firstname',
|
||||
name: 'eperson.firstname',
|
||||
required: true,
|
||||
validators: {
|
||||
required: null
|
||||
},
|
||||
errorMessages: {
|
||||
required: 'This field is required'
|
||||
},
|
||||
}),
|
||||
new DynamicInputModel({
|
||||
id: 'lastname',
|
||||
name: 'eperson.lastname',
|
||||
required: true,
|
||||
validators: {
|
||||
required: null
|
||||
},
|
||||
errorMessages: {
|
||||
required: 'This field is required'
|
||||
},
|
||||
}),
|
||||
new DynamicInputModel({
|
||||
id: 'phone',
|
||||
name: 'eperson.phone'
|
||||
}),
|
||||
new DynamicSelectModel<string>({
|
||||
id: 'language',
|
||||
name: 'eperson.language'
|
||||
})
|
||||
];
|
||||
|
||||
/**
|
||||
* The form group of this form
|
||||
*/
|
||||
formGroup: FormGroup;
|
||||
|
||||
LABEL_PREFIX = 'profile.metadata.form.label.';
|
||||
|
||||
ERROR_PREFIX = 'profile.metadata.form.error.';
|
||||
|
||||
/**
|
||||
* All of the configured active languages
|
||||
*/
|
||||
activeLangs: LangConfig[];
|
||||
|
||||
constructor(@Inject(GLOBAL_CONFIG) protected config: GlobalConfig,
|
||||
protected location: Location,
|
||||
protected formService: DynamicFormService,
|
||||
protected translate: TranslateService,
|
||||
protected epersonService: EPersonDataService) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.activeLangs = this.config.languages.filter((MyLangConfig) => MyLangConfig.active === true);
|
||||
this.formModel.forEach(
|
||||
(fieldModel: DynamicInputModel | DynamicSelectModel<string>) => {
|
||||
if (fieldModel.name === 'email') {
|
||||
fieldModel.value = this.user.email;
|
||||
} else {
|
||||
fieldModel.value = this.user.firstMetadataValue(fieldModel.name);
|
||||
}
|
||||
if (fieldModel.id === 'language') {
|
||||
(fieldModel as DynamicSelectModel<string>).options =
|
||||
this.activeLangs.map((langConfig) => Object.assign({ value: langConfig.code, label: langConfig.label }))
|
||||
}
|
||||
}
|
||||
);
|
||||
this.formGroup = this.formService.createFormGroup(this.formModel);
|
||||
this.updateFieldTranslations();
|
||||
this.translate.onLangChange
|
||||
.subscribe(() => {
|
||||
this.updateFieldTranslations();
|
||||
});
|
||||
}
|
||||
|
||||
updateFieldTranslations() {
|
||||
this.formModel.forEach(
|
||||
(fieldModel: DynamicInputModel) => {
|
||||
fieldModel.label = this.translate.instant(this.LABEL_PREFIX + fieldModel.id);
|
||||
if (isNotEmpty(fieldModel.validators)) {
|
||||
fieldModel.errorMessages = {};
|
||||
Object.keys(fieldModel.validators).forEach((key) => {
|
||||
fieldModel.errorMessages[key] = this.translate.instant(this.ERROR_PREFIX + fieldModel.id + '.' + key);
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
updateProfile() {
|
||||
const newMetadata = Object.assign({}, this.user.metadata);
|
||||
this.formModel.forEach((fieldModel: DynamicFormValueControlModel<string>) => {
|
||||
if (newMetadata.hasOwnProperty(fieldModel.name) && newMetadata[fieldModel.name].length > 0) {
|
||||
if (hasValue(fieldModel.value)) {
|
||||
newMetadata[fieldModel.name][0].value = fieldModel.value;
|
||||
} else {
|
||||
newMetadata[fieldModel.name] = [];
|
||||
}
|
||||
} else if (hasValue(fieldModel.value)) {
|
||||
newMetadata[fieldModel.name] = [{
|
||||
value: fieldModel.value,
|
||||
language: null
|
||||
} as any];
|
||||
}
|
||||
});
|
||||
this.epersonService.update(Object.assign(cloneDeep(this.user), { metadata: newMetadata })).pipe(
|
||||
getSucceededRemoteData(),
|
||||
getRemoteDataPayload()
|
||||
).subscribe((user) => {
|
||||
this.user = user;
|
||||
});
|
||||
}
|
||||
}
|
15
src/app/profile-page/profile-page-routing.module.ts
Normal file
15
src/app/profile-page/profile-page-routing.module.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { I18nBreadcrumbResolver } from '../core/breadcrumbs/i18n-breadcrumb.resolver';
|
||||
import { ProfilePageComponent } from './profile-page.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
RouterModule.forChild([
|
||||
{ path: '', pathMatch: 'full', component: ProfilePageComponent, resolve: { breadcrumb: I18nBreadcrumbResolver }, data: { breadcrumbKey: 'profile', title: 'profile.title' } }
|
||||
])
|
||||
]
|
||||
})
|
||||
export class ProfilePageRoutingModule {
|
||||
|
||||
}
|
@@ -0,0 +1,6 @@
|
||||
<div class="container-fluid mb-4">{{'profile.security.form.info' | translate}}</div>
|
||||
<ds-form *ngIf="formModel"
|
||||
[formId]="'profile-page-security-form-id'"
|
||||
[formModel]="formModel"
|
||||
[displaySubmit]="false">
|
||||
</ds-form>
|
@@ -0,0 +1,56 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import {
|
||||
DynamicFormControlModel,
|
||||
DynamicFormService,
|
||||
DynamicInputModel
|
||||
} from '@ng-dynamic-forms/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { FormGroup } from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-profile-page-security-form',
|
||||
templateUrl: './profile-page-security-form.component.html'
|
||||
})
|
||||
export class ProfilePageSecurityFormComponent implements OnInit {
|
||||
|
||||
formModel: DynamicFormControlModel[] = [
|
||||
new DynamicInputModel({
|
||||
id: 'password',
|
||||
name: 'password',
|
||||
inputType: 'password'
|
||||
}),
|
||||
new DynamicInputModel({
|
||||
id: 'passwordrepeat',
|
||||
name: 'passwordrepeat',
|
||||
inputType: 'password'
|
||||
})
|
||||
];
|
||||
|
||||
/**
|
||||
* The form group of this form
|
||||
*/
|
||||
formGroup: FormGroup;
|
||||
|
||||
LABEL_PREFIX = 'profile.security.form.label.';
|
||||
|
||||
constructor(protected formService: DynamicFormService,
|
||||
protected translate: TranslateService) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.formGroup = this.formService.createFormGroup(this.formModel);
|
||||
this.updateFieldTranslations();
|
||||
this.translate.onLangChange
|
||||
.subscribe(() => {
|
||||
this.updateFieldTranslations();
|
||||
});
|
||||
}
|
||||
|
||||
updateFieldTranslations() {
|
||||
this.formModel.forEach(
|
||||
(fieldModel: DynamicInputModel) => {
|
||||
fieldModel.label = this.translate.instant(this.LABEL_PREFIX + fieldModel.id);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
18
src/app/profile-page/profile-page.component.html
Normal file
18
src/app/profile-page/profile-page.component.html
Normal file
@@ -0,0 +1,18 @@
|
||||
<ng-container *ngVar="(user$ | async) as user">
|
||||
<div class="container" *ngIf="user">
|
||||
<h3 class="mb-4">{{'profile.head' | translate}}</h3>
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">{{'profile.card.identify' | translate}}</div>
|
||||
<div class="card-body">
|
||||
<ds-profile-page-metadata-form [user]="user"></ds-profile-page-metadata-form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">{{'profile.card.security' | translate}}</div>
|
||||
<div class="card-body">
|
||||
<ds-profile-page-security-form></ds-profile-page-security-form>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn btn-outline-primary" (click)="updateProfile()">{{'profile.form.submit' | translate}}</button>
|
||||
</div>
|
||||
</ng-container>
|
35
src/app/profile-page/profile-page.component.ts
Normal file
35
src/app/profile-page/profile-page.component.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { Observable } from 'rxjs/internal/Observable';
|
||||
import { EPerson } from '../core/eperson/models/eperson.model';
|
||||
import { select, Store } from '@ngrx/store';
|
||||
import { getAuthenticatedUser } from '../core/auth/selectors';
|
||||
import { AppState } from '../app.reducer';
|
||||
import { ProfilePageMetadataFormComponent } from './profile-page-metadata-form/profile-page-metadata-form.component';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-profile-page',
|
||||
templateUrl: './profile-page.component.html'
|
||||
})
|
||||
/**
|
||||
* Component for a user to edit their profile information
|
||||
*/
|
||||
export class ProfilePageComponent implements OnInit {
|
||||
|
||||
@ViewChild(ProfilePageMetadataFormComponent, { static: false }) metadataForm: ProfilePageMetadataFormComponent;
|
||||
|
||||
/**
|
||||
* The authenticated user
|
||||
*/
|
||||
user$: Observable<EPerson>;
|
||||
|
||||
constructor(private store: Store<AppState>) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.user$ = this.store.pipe(select(getAuthenticatedUser));
|
||||
}
|
||||
|
||||
updateProfile() {
|
||||
this.metadataForm.updateProfile();
|
||||
}
|
||||
}
|
23
src/app/profile-page/profile-page.module.ts
Normal file
23
src/app/profile-page/profile-page.module.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { SharedModule } from '../shared/shared.module';
|
||||
import { ProfilePageRoutingModule } from './profile-page-routing.module';
|
||||
import { ProfilePageComponent } from './profile-page.component';
|
||||
import { ProfilePageMetadataFormComponent } from './profile-page-metadata-form/profile-page-metadata-form.component';
|
||||
import { ProfilePageSecurityFormComponent } from './profile-page-security-form/profile-page-security-form.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
ProfilePageRoutingModule,
|
||||
CommonModule,
|
||||
SharedModule
|
||||
],
|
||||
declarations: [
|
||||
ProfilePageComponent,
|
||||
ProfilePageMetadataFormComponent,
|
||||
ProfilePageSecurityFormComponent
|
||||
]
|
||||
})
|
||||
export class ProfilePageModule {
|
||||
|
||||
}
|
Reference in New Issue
Block a user