open-learning-exchange/planet

View on GitHub
src/app/shared/forms/planet-rating.component.ts

Summary

Maintainability
A
3 hrs
Test Coverage
import { Component, Input, OnChanges } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { CouchService } from '../couchdb.service';
import { PlanetMessageService } from '../planet-message.service';
import { UserService } from '../user.service';
import { map } from 'rxjs/operators';
import { DialogsFormService } from '../dialogs/dialogs-form.service';
import { debug } from '../../debug-operator';
import { RatingService } from './rating.service';
import { StateService } from '../state.service';

const popupFormFields = [
  {
    'label': $localize`Rate`,
    'type': 'rating',
    'name': 'rate',
    'placeholder': $localize`Your Rating`,
    'required': false
  },
  {
    'label': $localize`Comment`,
    'type': 'textarea',
    'name': 'comment',
    'placeholder': $localize`Would you like to leave a comment?`,
    'required': false
  }
];

@Component({
  templateUrl: './planet-rating.component.html',
  styles: [ ` .list-item-rating {
    max-width: 225px;
  } ` ],
  selector: 'planet-rating'
})
export class PlanetRatingComponent implements OnChanges {

  @Input() rating: any = { userRating: {} };
  @Input() item: any;
  @Input() parent;
  @Input() ratingType = '';
  @Input() disabled = false;

  rateForm: FormGroup;
  popupForm: FormGroup;
  isPopupOpen = false;
  stackedBarData = [];
  get rateFormField() {
    return { rate: this.rating.userRating.rate || 0 };
  }
  get commentField() {
    return { comment: this.rating.userRating.comment || '' };
  }

  private dbName = 'ratings';

  constructor(
    private fb: FormBuilder,
    private couchService: CouchService,
    private planetMessage: PlanetMessageService,
    private userService: UserService,
    private dialogsForm: DialogsFormService,
    private ratingService: RatingService,
    private stateService: StateService
  ) {
    this.rateForm = this.fb.group(this.rateFormField);
    this.popupForm = this.fb.group(Object.assign({}, this.rateFormField, this.commentField));
  }

  ngOnChanges() {
    // After any changes to ratings ensures all properties are set
    this.rating = Object.assign({ rateSum: 0, totalRating: 0, maleRating: 0, femaleRating: 0, userRating: {} }, this.rating);
    this.stackedBarData = [
      { class: 'primary-color', amount: this.rating.maleRating },
      { class: 'primary-light-color',
        amount: this.rating.totalRating === 0 ? 1
          : this.rating.totalRating - this.rating.maleRating - this.rating.femaleRating,
        noLabel: true
      },
      { class: 'accent-color', amount: this.rating.femaleRating, align: 'right' }
    ];
    this.rateForm.setValue(this.rateFormField);
    this.popupForm.setValue(Object.assign({}, this.rateFormField, this.commentField));
  }

  onStarClick(form = this.rateForm) {
    if (this.disabled || form.controls.rate.value === 0) {
      return;
    }
    this.updateRating(form).subscribe(res => {
      if (!this.isPopupOpen) {
        this.openDialog();
        this.planetMessage.showMessage($localize`Thank you, your rating is submitted!`);
      } else {
        this.rateForm.setValue({ rate: this.popupForm.controls.rate.value });
        this.isPopupOpen = false;
        if (this.popupForm.controls.comment.dirty && this.popupForm.controls.comment.value !== '') {
          this.planetMessage.showMessage($localize`Thank you for your additional comments`);
        }
      }
    }, (err) => {
      this.ratingError();
    });
  }

  updateRating(form) {
    // Later parameters of Object.assign will overwrite values from previous objects
    const configuration = this.stateService.configuration;
    const newRating = {
      type: this.ratingType,
      item: this.item._id,
      title: this.item.title || this.item.courseTitle,
      createdTime: this.couchService.datePlaceholder,
      ...this.rating.userRating,
      ...form.value,
      time: this.couchService.datePlaceholder,
      user: this.userService.get(),
      createdOn: configuration.code,
      parentCode: configuration.parentCode
    };
    // Use call because 'this' will be undefined otherwise
    return this.couchService.updateDocument(this.dbName, newRating).pipe(map((res: any) => {
      newRating._rev = res.rev;
      newRating._id = res.id;
      this.rating.userRating = newRating;
      this.ratingService.newRatings(false);
      return res;
    }));
  }

  openDialog() {
    this.popupForm.patchValue(this.rateForm.value);
    this.isPopupOpen = true;
    this.dialogsForm
      .confirm($localize`Rating`, popupFormFields, this.popupForm)
      .pipe(debug('Dialog confirm'))
      .subscribe((res) => {
        if (res) {
          this.onStarClick(this.popupForm);
        }
      });
  }

  ratingError() {
    this.planetMessage.showAlert($localize`There was an issue updating your rating`);
    this.rateForm.patchValue({ rate: this.rating.userRating.rate || 0 });
    // If the dialog is open, then there will also be a comment control to reset
    if (this.rateForm.controls.comment) {
      this.rateForm.patchValue({ comment: this.rating.userRating.comment || '' });
    }
  }
}