Project

General

Profile

« Previous | Next » 

Revision 60536

[Admin | New-UI]: Finish personal-info. Delete old curator component

View differences:

personal-info.component.ts
5 5
import {CuratorService} from "../../../openaireLibrary/connect/curators/curator.service";
6 6
import {UtilitiesService} from "../../../openaireLibrary/services/utilities.service";
7 7
import {UserManagementService} from "../../../openaireLibrary/services/user-management.service";
8
import {FormArray, FormBuilder, FormGroup, Validators} from "@angular/forms";
9
import {Subscriber} from "rxjs";
10
import {EnvProperties} from "../../../openaireLibrary/utils/properties/env-properties";
11
import {properties} from "../../../../environments/environment";
12
import {User} from "../../../openaireLibrary/login/utils/helper.class";
13
import {Affiliation, Curator} from "../../../openaireLibrary/utils/entities/CuratorInfo";
14
import {HelpContentService} from "../../../services/help-content.service";
15
import {Page} from "../../../domain/page";
8 16

  
17
declare var UIkit;
18

  
9 19
@Component({
10 20
  selector: 'personal-info',
11 21
  template: `
......
14 24
        <users-tabs tab="personal"></users-tabs>
15 25
      </div>
16 26
      <div inner>
17
        test
27
        <div class="uk-card-header">
28
          <div class="uk-flex uk-child-width-1-1 uk-child-width-1-2@m uk-grid" uk-grid>
29
            <div>
30
              <div class="uk-text-small title">
31
                Personal Info & Affiliations
32
                <span *ngIf="!loading && (curatorFb && curatorFb.dirty && !newCurator)"> (unsaved changes)</span>
33
              </div>
34
            </div>
35
            <div class="uk-text-right@m uk-text-center">
36
              <button class="uk-button uk-button-secondary outlined uk-margin-right"
37
                      (click)="reset()"
38
                      [disabled]="loading || !hasChanged">Reset
39
              </button>
40
              <button class="uk-button uk-button-secondary"
41
                      (click)="updateCurator()"
42
                      [disabled]="loading || !hasChanged || curatorFb.invalid">Save
43
              </button>
44
            </div>
45
          </div>
46
        </div>
47
        <div class="uk-card uk-card-default uk-position-relative" style="min-height: 60vh">
48
          <div [class.hidden]="loading" class="uk-overflow-auto uk-padding-remove-bottom uk-padding-large">
49
            <form *ngIf="curatorFb" [formGroup]="curatorFb">
50
              <div class="uk-grid uk-margin-large-bottom" uk-grid>
51
                <div class="uk-grid uk-width-1-1 uk-flex-middle" uk-grid>
52
                  <div>
53
                    <div class="image">
54
                      <img [src]="photo"/>
55
                      <input #fileInput id="photo" type="file" class="uk-hidden" (change)="fileChangeEvent($event)"/>
56
                      <icon class="uk-text-secondary clickable" name="photo" ratio="1.5"
57
                            (click)="$event.stopPropagation();uploadPhoto(fileInput);$event.preventDefault()"></icon>
58
                      <div *ngIf="curator.photo || file" #element
59
                           uk-dropdown="mode: click; pos: bottom-left; delay-hide: 0; flip: false">
60
                        <ul class="uk-nav uk-dropdown-nav">
61
                          <li><a (click)="fileInput.click();hide(element)">Upload a new photo</a></li>
62
                          <li><a (click)="removePhoto();hide(element)">Remove this photo</a></li>
63
                        </ul>
64
                      </div>
65
                    </div>
66
                  </div>
67
                  <div class="uk-width-expand">
68
                    <h5 class="uk-text-secondary uk-text-bold">{{user.firstname + ' ' + user.lastname}}</h5>
69
                    <!--<div>
70
                      <span class="connected">Connected with: </span>
71
                      <span class="uk-text-secondary uk-text-bold">{{user.email}}</span>
72
                    </div>-->
73
                  </div>
74
                </div>
75
                <div dashboard-input class="uk-width-1-1" label="Display Name" placeholder="Write your name"
76
                     [formInput]="curatorFb.get('name')"></div>
77
                <div dashboard-input class="uk-width-1-1" label="Biography" placeholder="Write biography..."
78
                     [formInput]="curatorFb.get('bio')" type="textarea" rows="4"></div>
79
                <div class="uk-width-1-1">
80
                  <h5 class="uk-margin-large uk-text-bold">My Affiliations</h5>
81
                  <div class="uk-flex uk-flex-center">
82
                    <a (click)="editAffiliationOpen()" class="uk-flex uk-flex-middle uk-text-uppercase">
83
                      <button class="large uk-icon-button uk-button-secondary">
84
                        <icon name="add"></icon>
85
                      </button>
86
                      <button class="uk-button uk-button-link uk-margin-small-left uk-text-secondary">
87
                        Add New Affiliation
88
                      </button>
89
                    </a>
90
                  </div>
91
                  <div class="uk-margin-medium">
92
                    <div *ngFor="let affiliation of affiliations.controls; let i=index"
93
                         class="uk-card uk-card-default uk-card-body uk-text-small uk-margin-bottom">
94
                      <div class="uk-grid uk-grid-divider uk-flex-middle" uk-grid>
95
                        <div class="uk-width-expand@m uk-width-1-1 uk-grid uk-flex-middle" uk-grid>
96
                          <div class="uk-width-small">
97
                            <img [src]="affiliation.value.logo_url">
98
                          </div>
99
                          <div class="uk-width-auto">
100
                            <h6>{{affiliation.value.name}}</h6>
101
                            URL: <a [href]="affiliation.value.website_url">{{affiliation.value.website_url}}</a>
102
                          </div>
103
                        </div>
104
                        <div class="uk-width-auto@m uk-width-1-1">
105
                          <div class="uk-width-1-1 uk-flex uk-flex-center">
106
                            <div class="uk-padding-small uk-padding-remove-horizontal">
107
                              <a (click)="editAffiliationOpen(i)" class="uk-button action uk-flex uk-flex-middle">
108
                                <icon name="edit" ratio="0.7"></icon>
109
                                <span class="uk-margin-small-left">Edit Affiliation</span>
110
                              </a>
111
                              <a (click)="deleteAffiliationOpen(i)" class="uk-button action uk-flex uk-flex-middle uk-margin-small-top">
112
                                <icon name="remove" ratio="0.7"></icon>
113
                                <span class="uk-margin-small-left">Delete Affiliation</span>
114
                              </a>
115
                            </div>
116
                          </div>
117
                        </div>
118
                      </div>
119
                    </div>
120
                  </div>
121
                </div>
122
                <div class="uk-width-1-1 uk-text-small">
123
                  Your personal info will be visible in the Curators' page of your Community Gateway.
124
                  Read <a (click)="privacy()">privacy policy statement</a>.
125
                </div>
126
              </div>
127
            </form>
128
          </div>
129
          <div *ngIf="loading" class="uk-position-center">
130
            <loading *ngIf="loading"></loading>
131
          </div>
132
        </div>
18 133
      </div>
19 134
    </div>
20
  `
135
    <modal-alert #privacyStatement (alertOutput)="privacyStatement.cancel()">
136
      <div class="uk-text-small">
137
        Your personal data and photo are processed by OpenAIRE in conformity with personal data protection legal
138
        framework.
139
        They will be stored safely in our system for as long as OpenAIRE exists. Since you press the "save" button,
140
        you give us the consent to make them public in your Community Gateway to let users know who is
141
        configuring the platform. You always have the right to exercise your rights and ask for access,
142
        rectification, erasure and restriction of your data. Please contact <a href="mailto:rcd-helpdesk@openaire.eu">rcd-helpdesk@openaire.eu</a>
143
        if you have any inquiries.
144
      </div>
145
    </modal-alert>
146
    <modal-alert #affiliationModal [okDisabled]="affiliationFb && affiliationFb.invalid" (alertOutput)="editAffiliation()">
147
      <form *ngIf="affiliationFb" [formGroup]="affiliationFb">
148
        <div class="uk-grid uk-padding-large uk-padding-remove-horizontal uk-child-width-1-1" uk-grid>
149
          <div dashboard-input label="Name" placeholder="Write affiliation's name" [formInput]="affiliationFb.get('name')"></div>
150
          <div dashboard-input label="Logo URL" placeholder="Write your affiliation's logo URL" [formInput]="affiliationFb.get('logo_url')"></div>
151
          <div dashboard-input label="Website URL" placeholder="Write your affiliation's website URL" [formInput]="affiliationFb.get('website_url')"></div>
152
        </div>
153
      </form>
154
    </modal-alert>
155
    <modal-alert #removeAffiliationModal (alertOutput)="removeAffiliation()">
156
    </modal-alert>
157
    <modal-alert #enableCuratorsModal (alertOutput)="enableCurators()">
158
      <div class="uk-padding uk-padding-remove-horizontal">
159
        Your personal information has been successfully saved.<br><br>
160
        This information will be visible in <span class="uk-text-bold">Curators page</span> of Research Community Dashboard, which is <span class="uk-text-bold">disabled</span>.
161
        Do you want to <span class="uk-text-bold">enable</span> it now?
162
      </div>
163
    </modal-alert>
164
  `,
165
  styleUrls: ['personal-info.component.css']
21 166
})
22 167
export class PersonalInfoComponent implements OnInit, OnDestroy {
23

  
168
  /** Curator information */
169
  public loading = false;
170
  public user: User;
171
  public curator: Curator;
172
  public curatorFb: FormGroup;
173
  public properties: EnvProperties = properties;
174
  public curatorsPage: Page;
175
  public newCurator = false;
176
  public communityId: string;
177
  /** Photo */
178
  public photo: any = null;
179
  private photoChanged: boolean = false;
180
  public file: File = null;
181
  private maxsize: number = 200 * 1024;
182
  private deletePhoto = false;
183
  private subs: any[] = [];
184
  /** Affiliations */
185
  public affiliationFb: FormGroup;
186
  public index: number = -1;
187
  @ViewChild('fileInput') fileInput: ElementRef;
24 188
  @ViewChild('privacyStatement') privacyStatement: AlertModal;
25

  
189
  @ViewChild('affiliationModal') affiliationModal: AlertModal;
190
  @ViewChild('removeAffiliationModal') removeAffiliationModal: AlertModal;
191
  @ViewChild('enableCuratorsModal') enableCuratorsModal: AlertModal;
192
  
26 193
  constructor(private element: ElementRef,
27 194
              private route: ActivatedRoute,
28 195
              private _router: Router,
29 196
              private title: Title,
197
              private fb: FormBuilder,
30 198
              private curatorService: CuratorService,
31 199
              private utilitiesService: UtilitiesService,
200
              private helpContentService: HelpContentService,
32 201
              private userManagementService: UserManagementService) {
33 202
  }
34

  
35

  
203
  
204
  
36 205
  ngOnInit() {
206
    this.subs.push(this.route.params.subscribe(params => {
207
      this.communityId = params['community'];
208
      this.subs.push(this.userManagementService.getUserInfo().subscribe(user => {
209
        this.user = user;
210
        if (this.user) {
211
          this.loading = true;
212
          this.subs.push(this.curatorService.getCurator(properties).subscribe(curator => {
213
            this.initCurator(curator);
214
            this.reset();
215
            this.loading = false;
216
          }, error => {
217
            if (error.status === 404) {
218
              this.initCurator(null);
219
              this.reset();
220
            } else {
221
              console.error(error);
222
            }
223
            this.loading = false;
224
          }));
225
        }
226
      }));
227
    }));
37 228
  }
38 229
  
39 230
  ngOnDestroy() {
231
    this.subs.forEach(subscription => {
232
      if (subscription instanceof Subscriber) {
233
        subscription.unsubscribe();
234
      }
235
    })
40 236
  }
237
  
238
  hide(element: any) {
239
    UIkit.dropdown(element).hide();
240
  }
241
  
242
  initCurator(curator: Curator) {
243
    if (curator) {
244
      this.curator = curator;
245
      this.curator.email = this.user.email;
246
    } else {
247
      this.newCurator = true;
248
      this.curator = new Curator();
249
      this.curator._id = this.user.id;
250
      this.curator.email = this.user.email;
251
      this.curator.name = this.user.fullname;
252
      this.curator.affiliations = [];
253
      this.curator.bio = '';
254
      this.curator.photo = null;
255
    }
256
    this.curatorsPageStatus();
257
  }
258
  
259
  reset() {
260
    this.photoChanged = false;
261
    this.file = null;
262
    if (this.fileInput) {
263
      this.fileInput.nativeElement.value = null;
264
    }
265
    let affiliations: FormArray = this.fb.array([]);
266
    this.curator.affiliations.forEach(affiliation => {
267
      affiliations.push(this.fb.group({
268
        id: this.fb.control(affiliation.id),
269
        name: this.fb.control(affiliation.name, Validators.required),
270
        logo_url: this.fb.control(affiliation.logo_url, Validators.required),
271
        website_url: this.fb.control(affiliation.website_url, Validators.required),
272
      }));
273
    });
274
    this.curatorFb = this.fb.group({
275
      _id: this.fb.control(this.curator._id),
276
      name: this.fb.control(this.curator.name, Validators.required),
277
      bio: this.fb.control(this.curator.bio),
278
      email: this.fb.control(this.curator.email),
279
      photo: this.fb.control(this.curator.photo),
280
      affiliations: affiliations
281
    });
282
    if (this.curator.photo) {
283
      this.photo = this.properties.utilsService + '/download/' + this.curator.photo;
284
    } else {
285
      this.photo = 'assets/common-assets/curator-default.png';
286
    }
287
  }
288
  
289
  get affiliations(): FormArray {
290
    return this.curatorFb.get('affiliations') as FormArray;
291
  }
292
  
293
  saveCurator() {
294
    this.curatorService.updateCurator(this.properties, this.curatorFb.value).subscribe((curator) => {
295
        if (curator) {
296
          UIkit.notification('Your data has been <b>saved successfully</b>', {
297
            status: 'success',
298
            timeout: 6000,
299
            pos: 'bottom-right'
300
          });
301
          this.newCurator = false;
302
          this.deletePhoto = false;
303
          this.initCurator(curator);
304
          this.reset();
305
          if(!this.curatorsEnabled) {
306
            this.curatorsEnabledOpen();
307
          }
308
          this.loading = false;
309
        }
310
      },
311
      error => {
312
        this.handleUpdateError('An error has occurred. Try again later!');
313
        this.reset();
314
      });
315
  }
316
  
317
  
318
  updateCurator() {
319
    if (this.curatorFb.valid) {
320
      this.loading = true;
321
      if (this.file) {
322
        this.utilitiesService.uploadPhoto(this.properties.utilsService + '/upload/' + this.curator._id, this.file).subscribe((res) => {
323
            if (this.curator.photo) {
324
              this.utilitiesService.deletePhoto(this.properties.utilsService + '/delete/' + this.curator.photo).subscribe();
325
            }
326
            this.curatorFb.get('photo').setValue(res.filename);
327
            this.saveCurator();
328
          }, error => {
329
            this.handleUpdateError('An error has occurred during photo uploading.');
330
          }
331
        );
332
      } else {
333
        if (this.deletePhoto && this.curator.photo) {
334
          this.utilitiesService.deletePhoto(this.properties.utilsService + '/delete/' + this.curator.photo).subscribe();
335
          this.curatorFb.get('photo').setValue(null);
336
        }
337
        this.saveCurator();
338
      }
339
    }
340
  }
341
  
342
  private curatorsPageStatus() {
343
    this.helpContentService.getCommunityPagesByRoute(this.communityId, '/curators', this.properties.adminToolsAPIURL).subscribe((page) => {
344
      this.curatorsPage = page;
345
    });
346
  }
347
  
348
  public get curatorsEnabled(): boolean {
349
    return !!this.curatorsPage && this.curatorsPage.isEnabled;
350
  }
351
  
352
  fileChangeEvent(event) {
353
    this.loading = true;
354
    if (event.target.files && event.target.files[0]) {
355
      this.file = event.target.files[0];
356
      if (this.file.type !== 'image/png' && this.file.type !== 'image/jpeg') {
357
        this.handleUpdateError('You must choose a file with type: image/png or image/jpeg!');
358
        this.file = null;
359
      } else if (this.file.size > this.maxsize) {
360
        this.handleUpdateError('File exceeds size\'s limit! Maximum size 200KB.');
361
        this.file = null;
362
      } else {
363
        const reader = new FileReader();
364
        reader.readAsDataURL(this.file);
365
        reader.onload = () => {
366
          this.photo = reader.result;
367
          this.photoChanged = true;
368
          this.loading = false;
369
        };
370
      }
371
    } else {
372
      this.loading = false;
373
    }
374
  }
375
  
376
  removePhoto() {
377
    this.deletePhoto = true;
378
    this.file = null;
379
    this.fileInput.nativeElement.value = null;
380
    this.photoChanged = !!this.curator.photo;
381
    this.photo = 'assets/common-assets/curator-default.png';
382
  }
383
  
384
  handleUpdateError(message: string) {
385
    UIkit.notification(message, {
386
      status: 'danger',
387
      timeout: 6000,
388
      pos: 'bottom-right'
389
    });
390
    this.loading = false;
391
  }
392
  
393
  privacy() {
394
    this.privacyStatement.cancelButton = false;
395
    this.privacyStatement.okButtonText = 'Close';
396
    this.privacyStatement.alertTitle = 'Privacy policy statement';
397
    this.privacyStatement.open();
398
  }
399
  
400
  uploadPhoto(fileInput: HTMLInputElement) {
401
    if (!this.curator.photo && !this.file) {
402
      fileInput.click();
403
    }
404
  }
405
  
406
  get hasChanged(): boolean {
407
    return (this.curatorFb && this.curatorFb.dirty) || this.newCurator || this.photoChanged;
408
  }
409
  
410
  editAffiliationOpen(index = -1) {
411
    this.index = index;
412
    let affiliation: Affiliation = new Affiliation();
413
    if(index === -1) {
414
      this.affiliationModal.alertTitle = 'Add Affiliation';
415
      this.affiliationModal.okButtonText = 'Add';
416
    } else {
417
      this.affiliationModal.alertTitle = 'Edit Affiliation';
418
      this.affiliationModal.okButtonText = 'Update';
419
      affiliation = this.affiliations.at(index).value;
420
    }
421
    this.affiliationFb = this.fb.group({
422
      id: this.fb.control(affiliation.id),
423
      name: this.fb.control(affiliation.name, Validators.required),
424
      logo_url: this.fb.control(affiliation.logo_url, Validators.required),
425
      website_url: this.fb.control(affiliation.website_url, Validators.required)
426
    });
427
    this.affiliationModal.okButtonLeft = false;
428
    this.affiliationModal.cancelButtonText = 'Cancel';
429
    this.affiliationModal.open();
430
  }
431
  
432
  deleteAffiliationOpen(index: number) {
433
    this.index = index;
434
    let affiliation: Affiliation = this.affiliations.at(index).value;
435
    this.removeAffiliationModal.alertTitle = 'Delete Affiliation';
436
    this.removeAffiliationModal.message = 'Do you want to remove <b>' +
437
      affiliation.name +  '</b> from your Affiliations?';
438
    this.removeAffiliationModal.okButtonText = 'Yes';
439
    this.removeAffiliationModal.cancelButtonText = 'No';
440
    this.removeAffiliationModal.open();
441
  }
442
  
443
  editAffiliation() {
444
    if(this.index === -1) {
445
      this.affiliations.push(this.affiliationFb);
446
    } else {
447
      this.affiliations.at(this.index).setValue(this.affiliationFb.value);
448
    }
449
    this.curatorFb.markAsDirty();
450
  }
451
  
452
  removeAffiliation() {
453
    this.affiliations.removeAt(this.index);
454
    this.curatorFb.markAsDirty();
455
  }
456
  
457
  private curatorsEnabledOpen() {
458
    this.enableCuratorsModal.okButtonLeft = false;
459
    this.enableCuratorsModal.alertTitle = 'Enable Curators Page';
460
    this.enableCuratorsModal.okButtonText = 'Yes';
461
    this.enableCuratorsModal.cancelButtonText = 'No';
462
    this.enableCuratorsModal.open();
463
  }
464
  
465
  enableCurators() {
466
    this.helpContentService.togglePages(this.communityId, [this.curatorsPage._id], true, this.properties.adminToolsAPIURL).subscribe(() => {
467
      this.curatorsPage.isEnabled = true;
468
    });
469
  }
41 470
}

Also available in: Unified diff