Project

General

Profile

1
import {Component, Input, OnDestroy, ViewChild} from "@angular/core";
2
import {Stakeholder} from "../../openaireLibrary/monitor/entities/stakeholder";
3
import {FormBuilder, FormGroup, Validators} from "@angular/forms";
4
import {StakeholderUtils} from "../../utils/indicator-utils";
5
import {Option} from "../../openaireLibrary/sharedComponents/input/input.component";
6
import {Subscriber, Subscription} from "rxjs";
7
import {EnvProperties} from "../../openaireLibrary/utils/properties/env-properties";
8
import {properties} from "../../../environments/environment";
9
import {StakeholderService} from "../../openaireLibrary/monitor/services/stakeholder.service";
10
import {UtilitiesService} from "../../openaireLibrary/services/utilities.service";
11
import {Role, Session, User} from "../../openaireLibrary/login/utils/helper.class";
12
import {UserManagementService} from "../../openaireLibrary/services/user-management.service";
13
import {StringUtils} from "../../openaireLibrary/utils/string-utils.class";
14
import {NotifyFormComponent} from "../../openaireLibrary/notifications/notify-form/notify-form.component";
15
import {NotificationUtils} from "../../openaireLibrary/notifications/notification-utils";
16
import {Notification} from "../../openaireLibrary/notifications/notifications";
17

    
18
declare var UIkit;
19

    
20
@Component({
21
  selector: 'edit-stakeholder',
22
  template: `
23
    <div [ngStyle]="{'max-height': maxHeight}"
24
         [class.uk-padding-small]="!paddingLarge" [class.uk-padding-large]="paddingLarge"
25
         class="uk-overflow-auto uk-padding-remove-bottom">
26
      <form *ngIf="stakeholderFb" [formGroup]="stakeholderFb">
27
        <div class="uk-grid" [class.uk-margin-small-bottom]="!paddingLarge"
28
             [class.uk-margin-large-bottom]="paddingLarge" uk-grid uk-height-match=".uk-form-hint">
29
          <div dashboard-input id="name" class="uk-width-1-2@m" [formInput]="stakeholderFb.get('name')" label="Name"
30
               placeholder="Write a name..."
31
               hint="Set a name for your profile."></div>
32
          <div dashboard-input class="uk-width-1-2@m" [formInput]="stakeholderFb.get('alias')"
33
               hint="Set an URL alias for your profile."
34
               label="URL Alias" placeholder="Write an alias..."></div>
35
          <div dashboard-input class="uk-width-1-3@m" [formInput]="stakeholderFb.get('index_id')"
36
               label="Index ID" placeholder="Write index ID.">
37
          </div>
38
          <div dashboard-input class="uk-width-1-3@m" [formInput]="stakeholderFb.get('index_name')"
39
               label="Index Name" placeholder="Write index name.">
40
          </div>
41
          <div dashboard-input class="uk-width-1-3@m" [formInput]="stakeholderFb.get('index_shortName')"
42
               label="Index Short Name" placeholder="Write index short name.">
43
          </div>
44
          <div dashboard-input class="uk-width-1-1" [type]="'textarea'" placeholder="Write a description..."
45
               hint="Write a description for your profile"
46
               [rows]="4" [formInput]="stakeholderFb.get('description')" label="Description"></div>
47
          <input #file id="photo" type="file" class="uk-hidden" (change)="fileChangeEvent($event)"/>
48
          <div dashboard-input class="uk-width-1-1" type="logoURL" flex="top" [hideControl]="stakeholderFb.get('isUpload').value"
49
               hint="Upload or link the logo of your profile" [placeholder]="'Write link to the logo'"
50
               [formInput]="stakeholderFb.get('logoUrl')" label="Logo">
51
            <div *ngIf="!stakeholderFb.get('isUpload').value" style="margin-top: 7px;" class="uk-width-2-5@l uk-width-1-1">
52
              <div class="uk-grid uk-flex uk-flex-middle" uk-grid>
53
                <div class="uk-width-3-4@l uk-width-1-1 uk-flex uk-flex-center">
54
                  <button class="uk-button uk-button-secondary uk-flex uk-flex-middle uk-flex-wrap"
55
                          (click)="file.click()">
56
                    <icon name="cloud_upload" [flex]="true"></icon>
57
                    <span class="uk-margin-small-left">Upload a file</span>
58
                  </button>
59
                </div>
60
                <div class="uk-text-center uk-text-bold uk-width-expand">
61
                  OR
62
                </div>
63
              </div>
64
            </div>
65
            <div *ngIf="stakeholderFb.get('isUpload').value" class="uk-width-1-1 uk-flex uk-flex-middle">
66
              <div class="uk-card uk-card-default uk-text-center uk-border-circle">
67
                <img class="uk-position-center" [src]="photo">
68
              </div>
69
              <div class="uk-margin-left">
70
                <button (click)="remove()" class="uk-button-secondary outlined uk-icon-button">
71
                  <icon name="remove"></icon>
72
                </button>
73
              </div>
74
              <div class="uk-margin-small-left">
75
                <button class="uk-button-secondary uk-icon-button" (click)="file.click()">
76
                  <icon name="edit"></icon>
77
                </button>
78
              </div>
79
            </div>
80
          </div>
81
          <div *ngIf="uploadError" class="uk-text-danger uk-width-1-1">{{uploadError}}</div>
82
          <div class="uk-width-1-1 uk-grid uk-child-width-1-1" [class.uk-child-width-1-2@m]="!canChooseType"
83
               [class.uk-child-width-1-3@m]="canChooseType" uk-grid>
84
            <div dashboard-input [formInput]="stakeholderFb.get('visibility')"
85
                 [placeholder]="'Select a status'"
86
                 label="Status" hint="Select the visibility status of your profile"
87
                 [options]="stakeholderUtils.statuses" type="select">
88
            </div>
89
            <div dashboard-input [formInput]="stakeholderFb.get('type')"
90
                 [placeholder]="'Select a type'" hint="Select the type of your profile"
91
                 label="Type" [options]="types" type="select">
92
            </div>
93
            <ng-container *ngIf="canChooseType">
94
              <div [placeholder]="'Select a template'"
95
                   hint="Select a template for your profile"
96
                   dashboard-input class="uk-width-1-3@m" [formInput]="stakeholderFb.get('defaultId')"
97
                   label="Template" [options]="defaultStakeholdersOptions" type="select"></div>
98
            </ng-container>
99
          </div>
100
        </div>
101
      </form>
102
      <div #notify notify-form [class.uk-hidden]="properties.environment === 'production'" class="uk-width-1-1 uk-margin-medium-top uk-margin-medium-bottom"></div>
103
    </div>`,
104
  styleUrls: ['edit-stakeholder.component.css']
105
})
106
export class EditStakeholderComponent implements OnDestroy {
107
  @Input()
108
  public maxHeight = 'none';
109
  @Input()
110
  public paddingLarge: boolean = false;
111
  @Input()
112
  public disableAlias: boolean = false;
113
  public stakeholderFb: FormGroup;
114
  public secure: boolean = false;
115
  public stakeholderUtils: StakeholderUtils = new StakeholderUtils();
116
  public defaultStakeholdersOptions: Option[];
117
  public defaultStakeholders: Stakeholder[];
118
  public alias: string[];
119
  public stakeholder: Stakeholder;
120
  public isDefault: boolean;
121
  public isNew: boolean;
122
  public types: Option[];
123
  public properties: EnvProperties = properties;
124
  private subscriptions: any[] = [];
125
  /**
126
   * Photo upload
127
   * */
128
  public file: File;
129
  public photo: string | ArrayBuffer;
130
  public uploadError: string;
131
  public deleteCurrentPhoto: boolean = false;
132
  private maxsize: number = 200 * 1024;
133
  user: User;
134
  @ViewChild('notify', { static: true }) notify: NotifyFormComponent;
135
  private notification: Notification;
136
  
137
  constructor(private fb: FormBuilder,
138
              private stakeholderService: StakeholderService,
139
              private utilsService: UtilitiesService, private userManagementService: UserManagementService,) {
140
  }
141
  
142
  ngOnDestroy() {
143
    this.reset();
144
  }
145
  
146
  public init(stakeholder: Stakeholder, alias: string[], defaultStakeholders: Stakeholder[], isDefault: boolean, isNew: boolean) {
147
    this.reset();
148
    this.deleteCurrentPhoto = false;
149
    this.stakeholder = stakeholder;
150
    this.alias = alias;
151
    this.defaultStakeholders = defaultStakeholders;
152
    this.isDefault = isDefault;
153
    this.isNew = isNew;
154
    this.subscriptions.push(this.userManagementService.getUserInfo().subscribe(user => {
155
        this.user = user;
156
        this.types = this.stakeholderUtils.getTypesByUserRoles(this.user, this.stakeholder.alias);
157
        this.stakeholderFb = this.fb.group({
158
          _id: this.fb.control(this.stakeholder._id),
159
          defaultId: this.fb.control(this.stakeholder.defaultId),
160
          name: this.fb.control(this.stakeholder.name, Validators.required),
161
          description: this.fb.control(this.stakeholder.description),
162
          index_name: this.fb.control(this.stakeholder.index_name, Validators.required),
163
          index_id: this.fb.control(this.stakeholder.index_id, Validators.required),
164
          index_shortName: this.fb.control(this.stakeholder.index_shortName, Validators.required),
165
          creationDate: this.fb.control(this.stakeholder.creationDate),
166
          alias: this.fb.control(this.stakeholder.alias,
167
            [
168
              Validators.required,
169
              this.stakeholderUtils.aliasValidatorString(
170
                this.alias.filter(alias => alias !== this.stakeholder.alias)
171
              )]
172
          ),
173
          isDefault: this.fb.control((this.isDefault)),
174
          visibility: this.fb.control(this.stakeholder.visibility, Validators.required),
175
          type: this.fb.control(this.stakeholder.type, Validators.required),
176
          topics: this.fb.control(this.stakeholder.topics),
177
          isUpload: this.fb.control(this.stakeholder.isUpload),
178
          logoUrl: this.fb.control(this.stakeholder.logoUrl),
179
        });
180
        if (this.stakeholder.isUpload) {
181
          this.stakeholderFb.get('logoUrl').clearValidators();
182
          this.stakeholderFb.get('logoUrl').updateValueAndValidity();
183
        } else {
184
          this.stakeholderFb.get('logoUrl').setValidators([StringUtils.urlValidator()]);
185
          this.stakeholderFb.get('logoUrl').updateValueAndValidity();
186
        }
187
        this.subscriptions.push(this.stakeholderFb.get('isUpload').valueChanges.subscribe(value => {
188
          if (value == true) {
189
            this.stakeholderFb.get('logoUrl').clearValidators();
190
            this.stakeholderFb.updateValueAndValidity();
191
          } else {
192
            this.stakeholderFb.get('logoUrl').setValidators([StringUtils.urlValidator()]);
193
            this.stakeholderFb.updateValueAndValidity();
194
          }
195
        }));
196
        this.secure = (!this.stakeholderFb.get('logoUrl').value || this.stakeholderFb.get('logoUrl').value.includes('https://'));
197
        this.subscriptions.push(this.stakeholderFb.get('logoUrl').valueChanges.subscribe(value => {
198
          this.secure = (!value || value.includes('https://'));
199
        }));
200
        this.initPhoto();
201
        if (!isDefault) {
202
          this.subscriptions.push(this.stakeholderFb.get('type').valueChanges.subscribe(value => {
203
            this.onTypeChange(value, defaultStakeholders);
204
          }));
205
          this.stakeholderFb.setControl('defaultId', this.fb.control(stakeholder.defaultId, Validators.required));
206
        }
207
        if (!isNew) {
208
          this.notification = NotificationUtils.editStakeholder(this.user.firstname + ' ' + this.user.lastname, this.stakeholder.name);
209
          this.notify.reset(this.notification.message);
210
          if (this.isAdmin) {
211
            if (this.disableAlias) {
212
              setTimeout(() => {
213
                this.stakeholderFb.get('alias').disable();
214
              }, 0);
215
            }
216
          } else {
217
            setTimeout(() => {
218
              this.stakeholderFb.get('alias').disable();
219
              this.stakeholderFb.get('index_id').disable();
220
              this.stakeholderFb.get('index_name').disable();
221
              this.stakeholderFb.get('index_shortName').disable();
222
            }, 0);
223
          }
224
          setTimeout(() => {
225
            this.stakeholderFb.get('type').disable();
226
          }, 0);
227
        } else {
228
          this.notification = NotificationUtils.createStakeholder(this.user.firstname + ' ' + this.user.lastname);
229
          this.notify.reset(this.notification.message);
230
          setTimeout(() => {
231
            this.stakeholderFb.get('type').enable();
232
          }, 0);
233
        }
234
      }
235
    ));
236
  }
237
  
238
  public get isAdmin() {
239
    return Session.isPortalAdministrator(this.user);
240
  }
241
  
242
  public get disabled(): boolean {
243
    return (this.stakeholderFb && this.stakeholderFb.invalid) ||
244
      (this.stakeholderFb && this.stakeholderFb.pristine && !this.isNew && !this.file) ||
245
      (this.uploadError && this.uploadError.length > 0);
246
  }
247
  
248
  public get dirty(): boolean {
249
    return this.stakeholderFb && this.stakeholderFb.dirty;
250
  }
251
  
252
  public get canChooseType(): boolean {
253
    return !this.stakeholderFb.get('isDefault').value && this.isNew && this.stakeholderFb.get('type').valid && !!this.defaultStakeholdersOptions;
254
  }
255
  
256
  reset() {
257
    this.uploadError = null;
258
    this.stakeholderFb = null;
259
    this.subscriptions.forEach(subscription => {
260
      if (subscription instanceof Subscription) {
261
        subscription.unsubscribe();
262
      }
263
    });
264
  }
265
  
266
  onTypeChange(value, defaultStakeholders: Stakeholder[]) {
267
    this.stakeholderFb.setControl('defaultId', this.fb.control(this.stakeholder.defaultId, Validators.required));
268
    this.defaultStakeholdersOptions = [{
269
      label: 'New blank profile',
270
      value: '-1'
271
    }];
272
    defaultStakeholders.filter(stakeholder => stakeholder.type === value).forEach(stakeholder => {
273
      this.defaultStakeholdersOptions.push({
274
        label: 'Use ' + stakeholder.name + ' profile',
275
        value: stakeholder._id
276
      })
277
    });
278
  }
279
  
280
  public save(callback: Function, errorCallback: Function = null) {
281
    if (this.file) {
282
      this.stakeholderFb.get('alias').enable();
283
      this.subscriptions.push(this.utilsService.uploadPhoto(this.properties.utilsService + "/upload/stakeholder/" + encodeURIComponent(this.stakeholderFb.value.alias), this.file).subscribe(res => {
284
        this.deletePhoto();
285
        this.removePhoto();
286
        this.stakeholderFb.get('logoUrl').setValue(res.filename);
287
        this.saveStakeholder(callback, errorCallback);
288
      }, error => {
289
        this.uploadError = "An error has been occurred during upload your image. Try again later";
290
        this.saveStakeholder(callback, errorCallback);
291
      }));
292
    } else if (this.deleteCurrentPhoto) {
293
      this.deletePhoto();
294
      this.saveStakeholder(callback, errorCallback);
295
    } else {
296
      this.saveStakeholder(callback, errorCallback);
297
    }
298
  }
299
  
300
  public saveStakeholder(callback: Function, errorCallback: Function = null) {
301
    if (this.isNew) {
302
      if (!this.stakeholderFb.value.isDefault) {
303
        let stakeholder = this.defaultStakeholders.find(value => value._id === this.stakeholderFb.value.defaultId);
304
        this.stakeholderFb.setValue(this.stakeholderUtils.createFunderFromDefaultProfile(this.stakeholderFb.value,
305
          (stakeholder ? stakeholder.topics : [])));
306
      }
307
      this.removePhoto();
308
      this.subscriptions.push(this.stakeholderService.buildStakeholder(this.properties.monitorServiceAPIURL,
309
        this.stakeholderFb.value).subscribe(stakeholder => {
310
        this.notification.entity = stakeholder._id;
311
        this.notification.stakeholder = stakeholder.alias;
312
        this.notification.stakeholderType = stakeholder.type;
313
        this.notification.groups = [Role.curator(stakeholder.type)];
314
        this.notify.sendNotification(this.notification);
315
        UIkit.notification(stakeholder.name + ' has been <b>successfully created</b>', {
316
          status: 'success',
317
          timeout: 6000,
318
          pos: 'bottom-right'
319
        });
320
        callback(stakeholder);
321
      }, error => {
322
        UIkit.notification('An error has occurred. Please try again later', {
323
          status: 'danger',
324
          timeout: 6000,
325
          pos: 'bottom-right'
326
        });
327
        if (errorCallback) {
328
          errorCallback(error)
329
        }
330
      }));
331
    } else {
332
      this.stakeholderFb.get('alias').enable();
333
      this.stakeholderFb.get('type').enable();
334
      this.stakeholderFb.get('index_id').enable();
335
      this.stakeholderFb.get('index_name').enable();
336
      this.stakeholderFb.get('index_shortName').enable();
337
      this.subscriptions.push(this.stakeholderService.saveElement(this.properties.monitorServiceAPIURL, this.stakeholderFb.value).subscribe(stakeholder => {
338
        this.notification.entity = stakeholder._id;
339
        this.notification.stakeholder = stakeholder.alias;
340
        this.notification.stakeholderType = stakeholder.type;
341
        this.notification.groups = [Role.curator(stakeholder.type), Role.manager(stakeholder.type, stakeholder.alias)];
342
        this.notify.sendNotification(this.notification);
343
        UIkit.notification(stakeholder.name + ' has been <b>successfully saved</b>', {
344
          status: 'success',
345
          timeout: 6000,
346
          pos: 'bottom-right'
347
        });
348
        callback(stakeholder);
349
      }, error => {
350
        UIkit.notification('An error has occurred. Please try again later', {
351
          status: 'danger',
352
          timeout: 6000,
353
          pos: 'bottom-right'
354
        });
355
      }));
356
    }
357
  }
358
  
359
  fileChangeEvent(event) {
360
    if (event.target.files && event.target.files[0]) {
361
      this.file = event.target.files[0];
362
      if (this.file.type !== 'image/png' && this.file.type !== 'image/jpeg') {
363
        this.uploadError = 'You must choose a file with type: image/png or image/jpeg!';
364
        this.stakeholderFb.get('isUpload').setValue(false);
365
        this.stakeholderFb.get('isUpload').markAsDirty();
366
        this.removePhoto();
367
      } else if (this.file.size > this.maxsize) {
368
        this.uploadError = 'File exceeds size\'s limit! Maximum resolution is 256x256 pixels.';
369
        this.stakeholderFb.get('isUpload').setValue(false);
370
        this.stakeholderFb.get('isUpload').markAsDirty();
371
        this.removePhoto();
372
      } else {
373
        this.uploadError = null;
374
        const reader = new FileReader();
375
        reader.readAsDataURL(this.file);
376
        reader.onload = () => {
377
          this.photo = reader.result;
378
          this.stakeholderFb.get('isUpload').setValue(true);
379
          this.stakeholderFb.get('isUpload').markAsDirty();
380
        };
381
      }
382
    }
383
  }
384
  
385
  initPhoto() {
386
    if (this.stakeholderFb.value.isUpload) {
387
      this.photo = this.properties.utilsService + "/download/" + this.stakeholderFb.get('logoUrl').value;
388
    }
389
  }
390
  
391
  removePhoto() {
392
    if (this.file) {
393
      if (typeof document != 'undefined') {
394
        (<HTMLInputElement>document.getElementById("photo")).value = "";
395
      }
396
      this.initPhoto();
397
      this.file = null;
398
    }
399
  }
400
  
401
  remove() {
402
    this.stakeholderFb.get('isUpload').setValue(false);
403
    this.stakeholderFb.get('isUpload').markAsDirty();
404
    this.removePhoto();
405
    this.stakeholderFb.get('logoUrl').setValue(null);
406
    if (this.stakeholder.isUpload) {
407
      this.deleteCurrentPhoto = true;
408
    }
409
  }
410
  
411
  public deletePhoto() {
412
    if (this.stakeholder.logoUrl) {
413
      this.subscriptions.push(this.utilsService.deletePhoto(this.properties.utilsService + '/delete/stakeholder/' + this.stakeholder.logoUrl).subscribe());
414
    }
415
  }
416
}
(2-2/3)