open-learning-exchange/planet

View on GitHub
src/app/users/users-achievements/users-achievements-update.component.ts

Summary

Maintainability
A
0 mins
Test Coverage
import { Component, OnInit, ViewEncapsulation, OnDestroy } from '@angular/core';
import { FormBuilder, FormGroup, FormArray, Validators } from '@angular/forms';
import { CouchService } from '../../shared/couchdb.service';
import { ActivatedRoute, Router } from '@angular/router';
import { UserService } from '../../shared/user.service';
import { PlanetMessageService } from '../../shared/planet-message.service';
import { UsersAchievementsService } from './users-achievements.service';
import { DialogsFormService } from '../../shared/dialogs/dialogs-form.service';
import { StateService } from '../../shared/state.service';
import { catchError, takeUntil } from 'rxjs/operators';
import { CustomValidators } from '../../validators/custom-validators';
import { ValidatorService } from '../../validators/validator.service';
import { forkJoin, Subject } from 'rxjs';
import { PlanetStepListService } from '../../shared/forms/planet-step-list.component';
import { showFormErrors } from '../../shared/table-helpers';

@Component({
  templateUrl: './users-achievements-update.component.html',
  styleUrls: [ 'users-achievements-update.scss' ],
  encapsulation: ViewEncapsulation.None
})
export class UsersAchievementsUpdateComponent implements OnInit, OnDestroy {

  user = this.userService.get();
  configuration = this.stateService.configuration;
  docInfo = { '_id': this.user._id + '@' + this.configuration.code, '_rev': undefined };
  readonly dbName = 'achievements';
  editForm: FormGroup;
  profileForm: FormGroup;
  private onDestroy$ = new Subject<void>();
  get achievements(): FormArray {
    return <FormArray>this.editForm.controls.achievements;
  }
  get references(): FormArray {
    return <FormArray>this.editForm.controls.references;
  }
  get links(): FormArray {
    return <FormArray>this.editForm.controls.links;
  }
  minBirthDate: Date = this.userService.minBirthDate;

  constructor(
    private fb: FormBuilder,
    private couchService: CouchService,
    private route: ActivatedRoute,
    private router: Router,
    private userService: UserService,
    private planetMessageService: PlanetMessageService,
    private usersAchievementsService: UsersAchievementsService,
    private dialogsFormService: DialogsFormService,
    private stateService: StateService,
    private validatorService: ValidatorService,
    private planetStepListService: PlanetStepListService
  ) {
    this.createForm();
    this.createProfileForm();
  }

  ngOnInit() {
    this.profileForm.patchValue(this.user);
    this.usersAchievementsService.getAchievements(this.docInfo._id)
    .pipe(catchError(() => this.usersAchievementsService.getAchievements(this.user._id)))
    .subscribe((achievements) => {
      this.editForm.patchValue(achievements);
      this.editForm.controls.achievements = this.fb.array(achievements.achievements || []);
      this.editForm.controls.references = this.fb.array(achievements.references || []);
      this.editForm.controls.links = this.fb.array(achievements.links || []);
      // Keeping older otherInfo property so we don't lose this info on database
      this.editForm.controls.otherInfo = this.fb.array(achievements.otherInfo || []);
      if (this.docInfo._id === achievements._id) {
        this.docInfo._rev = achievements._rev;
      }
    }, (error) => {
      console.log(error);
    });
    this.planetStepListService.stepMoveClick$.pipe(takeUntil(this.onDestroy$)).subscribe(
      () => this.editForm.controls.dateSortOrder.setValue('none')
    );
  }

  ngOnDestroy() {
    this.onDestroy$.next();
    this.onDestroy$.complete();
  }

  createForm() {
    this.editForm = this.fb.group({
      purpose: '',
      goals: '',
      achievementsHeader: '',
      achievements: this.fb.array([]),
      references: this.fb.array([]),
      links: this.fb.array([]),
      // Keeping older otherInfo property so we don't lose this info on database
      otherInfo: this.fb.array([]),
      sendToNation: false,
      dateSortOrder: 'none'
    });
  }

  createProfileForm() {
    this.profileForm = this.fb.group({
      firstName: [ '', CustomValidators.required ],
      middleName: '',
      lastName: [ '', CustomValidators.required ],
      birthDate: [
        '',
        [ CustomValidators.dateValidRequired ],
        ac => this.validatorService.notDateInFuture$(ac)
      ],
      birthplace: ''
    });
  }

  addAchievement(index = -1, achievement = { title: '', description: '', link: '', date: '' }) {
    if (typeof achievement === 'string') {
      achievement = { title: '', description: achievement, link: '', date: '' };
    }
    this.dialogsFormService.openDialogsForm(
      achievement.title !== '' ? $localize`Edit Achievement` : $localize`Add Achievement`,
      [
        { 'type': 'textbox', 'name': 'title', 'placeholder': $localize`Title`, required: true },
        { 'type': 'date', 'name': 'date', 'placeholder': $localize`Date`, 'required': false },
        { 'type': 'textbox', 'name': 'link', 'placeholder': $localize`Link`, required: false },
        { 'type': 'textarea', 'name': 'description', 'placeholder': $localize`Description`, 'required': false },
      ],
      this.fb.group({
        ...achievement,
        title: [ achievement.title, CustomValidators.required ],
        description: [ achievement.description ],
        link: [ achievement.link, [], CustomValidators.validLink ],
        date: [ achievement.date, null, ac => this.validatorService.notDateInFuture$(ac) ]
      }),
      { onSubmit: (formValue, formGroup) => {
        const achievedAt = formGroup.controls.date.value instanceof Date ? formGroup.controls.date.value.toISOString() :
         formGroup.controls.date.value;
        formGroup.controls.date.setValue(achievedAt);
        this.onDialogSubmit(this.achievements, index)(formValue, formGroup);
      }, closeOnSubmit: true }
    );
  }

  addReference(index = -1, reference: any = { name: '' }) {
    this.dialogsFormService.openDialogsForm(
      reference.name !== '' ? $localize`Edit Reference` : $localize`Add Reference`,
      [
        { 'type': 'textbox', 'name': 'name', 'placeholder': $localize`Name`, required: true },
        { 'type': 'textbox', 'name': 'relationship', 'placeholder': $localize`Relationship`, 'required': false },
        { 'type': 'textbox', 'name': 'phone', 'placeholder': $localize`Phone Number`, 'required': false },
        { 'type': 'textbox', 'name': 'email', 'placeholder': $localize`Email`, 'required': false }
      ],
      this.fb.group({
        relationship: '',
        phone: '',
        ...reference,
        name: [ reference.name, CustomValidators.required ],
        email: [ reference.email, Validators.email ],
      }),
      { onSubmit: this.onDialogSubmit(this.references, index), closeOnSubmit: true }
    );
  }

  addLink(index = -1, link: any = { title: '', url: '' }) {
    this.dialogsFormService.openDialogsForm(
      link.title !== '' ? $localize`Edit Link` : $localize`Add Link`,
      [
        { 'type': 'textbox', 'name': 'title', 'placeholder': $localize`Link Title`, required: true },
        { 'type': 'textbox', 'name': 'url', 'placeholder': $localize`URL`, 'required': true }
      ],
      this.fb.group({
        ...link,
        title: [ link.title, CustomValidators.required ],
        url: [ link.url, CustomValidators.required, CustomValidators.validLink ],
      }),
      { onSubmit: this.onDialogSubmit(this.links, index), closeOnSubmit: true }
    );
  }

  onDialogSubmit(formArray, index) {
    return (formValue, formGroup) => {
      if (formValue === undefined) {
        return;
      }
      this.updateFormArray(formArray, formGroup, index);
    };
  }

  updateFormArray(formArray: FormArray, value, index = -1) {
    if (index === -1) {
      formArray.push(value);
    } else {
      formArray.setControl(index, value);
    }
    if (value.contains('date')) {
      formArray.setValue(this.sortDate(formArray.value, this.editForm.controls.dateSortOrder.value || 'none'));
    }
    this.editForm.updateValueAndValidity();
  }

  sortAchievements() {
    const sort = this.editForm.controls.dateSortOrder.value === 'asc' ? 'desc' : 'asc';
    this.editForm.controls.dateSortOrder.setValue(sort);
    this.achievements.setValue(this.sortDate(this.achievements.value, sort));
  }

  sortDate(achievements, sortOrder = 'none') {
    if (sortOrder === 'none') {
      return achievements;
    }
    return achievements.sort((a, b) => {
      if (!a.date) {
        return 1;
      }
      const order = sortOrder === 'desc' ? 1 : -1;
      return (a.date < b.date || !b.date) ? order * 1 : order * -1;
    });
  }

  onSubmit() {
    this.editForm.updateValueAndValidity();
    this.profileForm.updateValueAndValidity();
    if (this.editForm.valid && this.profileForm.valid) {
      this.updateAchievements(this.docInfo, this.editForm.value, { ...this.user, ...this.profileForm.value });
    } else {
      this.markAsInvalid(this.editForm);
      this.markAsInvalid(this.profileForm);
    }
  }

  markAsInvalid(userForm) {
    if (!userForm.valid) {
      showFormErrors(userForm.controls);
    }
  }

  updateAchievements(docInfo, achievements, userInfo) {
    // ...is the rest syntax for object destructuring
    forkJoin([
      this.couchService.post(this.dbName, { ...docInfo, ...achievements,
        'createdOn': this.configuration.code, 'username': this.user.name, 'parentCode': this.configuration.parentCode }),
      this.userService.updateUser(userInfo)
    ]).subscribe(() => {
      this.planetMessageService.showMessage($localize`Achievements successfully updated`);
      this.goBack();
    }, (err) => {
      this.planetMessageService.showAlert($localize`There was an error updating your achievements`);
    });
  }

  goBack() {
    this.router.navigate([ '..' ], { relativeTo: this.route });
  }

}