[ADF-4552][ADF-4482] Social component refactoring, add ability to unRate, added e2e automation (#4749)

* [ADF-4552] Rating component refactoring, add ability to unRate

* [ADF-4552] RTL support added

* [ADF-4552] Improve behaviour and styling structure in RTL languages

* [ADF-4552] Improve behaviour and styling structure in RTL languages

* [ADF-4552] Added refresh rating when the node Id input changes

* [ADF-4552][ADF-4482] Refactor social component, add ability to unrate, add e2e automation

* [ADF-4552][ADF-4482] Added unsibscribe from Observables, added css variables, removed unused class id's

* [ADF-4552][ADF-4482] Improve structure and behaviour of e2e automation tests

* [ADF-4552][ADF-4482] Improve structure and behaviour of e2e automation tests

* [ADF-4552][ADF-4482] fix expected single space

* [ADF-4552][ADF-4482] fix lint check failure

* Fix circular dependency error
This commit is contained in:
arditdomi
2019-06-03 14:27:13 +01:00
committed by Eugenio Romano
parent b19646d201
commit 3d67d9dc75
17 changed files with 571 additions and 124 deletions

View File

@@ -5,7 +5,9 @@
<mat-icon>thumb_up</mat-icon>
</span>
</div>
<div id="adf-like-counter" class="adf-like-counter">{{likesCounter}}</div>
<div class="adf-left" *ngIf="likesCounter<=1">Like</div>
<div class="adf-left" *ngIf="likesCounter>1">Likes</div>
<div class="adf-like-counter-container">
<div id="adf-like-counter" class="adf-like-counter">{{likesCounter}}</div>
<div class="adf-left" *ngIf="likesCounter<=1">Like</div>
<div class="adf-left" *ngIf="likesCounter>1">Likes</div>
</div>
</div>

View File

@@ -1,42 +1,41 @@
@mixin selected {
color: #2196f3;
}
@mixin unselected {
color: #808080;
}
.adf-like-container {
display: flex;
overflow: hidden;
width: 100%;
align-items: center;
margin-top: 13px;
.adf-like {
padding: 5px;
cursor: pointer;
float: left;
margin: 5px 0 5px 5px;
.adf-like-counter-container {
display: inherit;
padding: 0 6px;
}
.adf-left {
padding: 0 6px;
}
.adf-like-select {
cursor: pointer;
color: #2196f3;
}
.adf-like-select:hover {
cursor: pointer;
color: #808080;
@include selected;
&:hover {
@include unselected;
}
}
.adf-like-grey {
cursor: pointer;
color: #808080;
}
.adf-like-grey:hover {
cursor: pointer;
color: #2196f3;
}
.adf-like-counter {
float: left;
padding: 13px 0 0;
}
.adf-left {
float: left;
padding: 13px 0 0 4px;
@include unselected;
&:hover {
@include selected;
}
}
}

View File

@@ -1,12 +1,18 @@
<mat-list id="adf-rating-container" class="adf-rating-container">
<mat-list-item class="adf-rating-star" *ngFor="let currentRate of stars; let idx = index">
<mat-list-item class="adf-rating-star" *ngFor="let currentRate of stars; let idx = index;">
<span id="adf-rate-{{idx}}">
<mat-icon id="adf-grey-star-{{idx}}" *ngIf="currentRate.fill" class="adf-colored-star"
(click)="updateVote(idx + 1)">star_rate
<mat-icon id="adf-colored-star-{{idx}}" *ngIf="currentRate.fill" class="adf-colored-star"
[ngClass]="{'adf-average-star': !ratingValue}"
(click)="updateVote(idx + 1)">star_rate
</mat-icon>
<mat-icon id="adf-colored-star-{{idx}}" *ngIf="!currentRate.fill" class="adf-grey-star"
(click)="updateVote(idx + 1)">star_border
<mat-icon id="adf-grey-star-{{idx}}" *ngIf="!currentRate.fill" class="adf-grey-star"
(click)="updateVote(idx + 1)">star_border
</mat-icon>
</span>
</mat-list-item>
<div class="adf-rating-counter-container">
<div id="adf-rating-counter" class="adf-rating-counter">{{ratingsCounter}}</div>
<div class="adf-rating-left" *ngIf="ratingsCounter<=1">Rating</div>
<div class="adf-rating-left" *ngIf="ratingsCounter>1">Ratings</div>
</div>
</mat-list>

View File

@@ -1,35 +1,54 @@
$adf-rated-star-color: #ffe944;
$adf-average-star-color: #808080;
.adf-rating-container {
overflow: hidden;
width: 100%;
display: flex;
overflow: hidden;
width: 100%;
.adf-rating-counter-container {
display: flex;
align-items: center;
padding: 0 6px;
}
.adf-rating-left {
padding: 0 6px;
}
.adf-rating-star {
float: left;
display: flex;
justify-content: center;
transition: all 0.3s;
padding: 1px;
cursor: pointer;
width: 25px !important;
width: 25px;
.mat-list-item-content {
padding: 0 2px !important;
padding: 0 !important;
}
&:hover {
transform: rotate(13deg) scale(1.2);
}
}
.adf-colored-star {
color: #ffe944;
color: $adf-rated-star-color;
}
.adf-grey-star {
color: #808080;
}
.adf-stars-container {
padding: 0 !important;
margin: 0 !important;
display: inline-block;
}
.adf-rating-star:hover {
transform: rotate(13deg) scale(1.2);
.adf-grey-star, .adf-average-star {
color: $adf-average-star-color !important;
}
}
[dir='rtl'] .adf-rating-container {
.adf-rating-star {
transform: rotate(145deg);
}
.adf-rating-star:hover {
transform: rotate(158deg) scale(1.2);
}
}

View File

@@ -61,75 +61,87 @@ describe('Rating component', () => {
}
}));
component.ngOnChanges();
fixture.detectChanges();
component.ngOnChanges().subscribe(() => {
expect(element.querySelector('#adf-rating-container')).not.toBe(null);
done();
});
expect(element.querySelector('#adf-rating-container')).not.toBe(null);
done();
});
it('should the star rating filled with the right grey/colored star', (done) => {
spyOn(service, 'getRating').and.returnValue(of({
entry: {
id: 'fiveStar',
aggregate: {
numberOfRatings: 4,
average: 3
}
}
}));
fixture.detectChanges();
component.ngOnChanges().subscribe(() => {
fixture.detectChanges();
expect(element.querySelectorAll('.adf-colored-star').length).toBe(3);
expect(element.querySelectorAll('.adf-grey-star').length).toBe(2);
done();
});
});
it('should click on a star change your vote', (done) => {
spyOn(service, 'getRating').and.returnValue(of({
'entry': {
myRating: 1,
myRating: 3,
'ratedAt': '2017-04-06T14:34:28.061+0000',
'id': 'fiveStar',
'aggregate': { 'numberOfRatings': 1, 'average': 1.0 }
'aggregate': {'numberOfRatings': 1, 'average': 3.0}
}
}));
spyOn(service, 'postRating').and.returnValue(of({
'entry': {
'myRating': 3,
'ratedAt': '2017-04-06T14:36:40.731+0000',
'id': 'fiveStar',
'aggregate': { 'numberOfRatings': 1, 'average': 3.0 }
}
}));
component.ngOnChanges();
fixture.detectChanges();
component.ngOnChanges().subscribe(() => {
fixture.detectChanges();
expect(element.querySelectorAll('.adf-colored-star').length).toBe(3);
expect(element.querySelectorAll('.adf-grey-star').length).toBe(2);
done();
});
});
expect(element.querySelectorAll('.adf-colored-star').length).toBe(1);
it('should click on a star to change your vote', (done) => {
spyOn(service, 'getRating').and.returnValue(of({
'entry': {
myRating: 1,
'ratedAt': '2017-04-06T14:34:28.061+0000',
'id': 'fiveStar',
'aggregate': {'numberOfRatings': 1, 'average': 1.0}
}
}));
component.changeVote.subscribe(() => {
fixture.detectChanges();
const rateSpy = spyOn(service, 'postRating').and.returnValue(of({
'entry': {
'myRating': 3,
'ratedAt': '2017-04-06T14:36:40.731+0000',
'id': 'fiveStar',
'aggregate': {'numberOfRatings': 1, 'average': 3.0}
}
}));
expect(element.querySelectorAll('.adf-colored-star').length).toBe(3);
component.ngOnChanges();
fixture.detectChanges();
done();
});
expect(element.querySelectorAll('.adf-colored-star').length).toBe(1);
const starThree: any = element.querySelector('#adf-colored-star-3');
starThree.click();
});
component.changeVote.subscribe(() => {
fixture.detectChanges();
expect(rateSpy).toHaveBeenCalled();
expect(element.querySelectorAll('.adf-colored-star').length).toBe(3);
done();
});
const starThree: any = element.querySelector('#adf-grey-star-2');
starThree.click();
});
it('should click on the rated star to remove your vote', () => {
spyOn(service, 'getRating').and.returnValue(of({
'entry': {
myRating: 3,
'ratedAt': '2017-04-06T14:34:28.061+0000',
'id': 'fiveStar',
'aggregate': {'numberOfRatings': 1, 'average': 3.0}
}
}));
const deleteSpy = spyOn(service, 'deleteRating');
component.ngOnChanges();
fixture.detectChanges();
const starThree: any = element.querySelector('#adf-colored-star-2');
starThree.click();
expect(element.querySelectorAll('.adf-colored-star').length).toBe(3);
expect(deleteSpy).toHaveBeenCalled();
});
});

View File

@@ -18,6 +18,8 @@
import { Component, EventEmitter, Input, OnChanges, Output, ViewEncapsulation } from '@angular/core';
import { RatingService } from './services/rating.service';
import { RatingEntry } from '@alfresco/js-api';
import { takeUntil } from 'rxjs/operators';
import { Subject } from 'rxjs';
@Component({
selector: 'adf-rating',
@@ -33,56 +35,87 @@ export class RatingComponent implements OnChanges {
average: number = 0;
ratingsCounter = 0;
ratingType: string = 'fiveStar';
ratingValue: number;
/** Emitted when the "vote" gets changed. */
@Output()
changeVote = new EventEmitter();
stars: Array<any> = [];
onDestroy$ = new Subject<boolean>();
constructor(private ratingService: RatingService) {
}
ngOnChanges() {
const ratingObserver = this.ratingService.getRating(this.nodeId, this.ratingType);
ratingObserver.subscribe(
this.ratingService.getRating(this.nodeId, this.ratingType)
.pipe(takeUntil(this.onDestroy$))
.subscribe(
(ratingEntry: RatingEntry) => {
if (ratingEntry.entry.aggregate) {
this.average = ratingEntry.entry.aggregate.average;
this.calculateStars();
}
this.refreshRating(ratingEntry);
}
);
}
return ratingObserver;
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
calculateStars() {
this.stars = [];
const roundedAverage = Math.round(this.average);
for (let i = 0; i < 5; i++) {
if (i < this.average) {
this.stars.push({ fill: true });
if (i < roundedAverage) {
this.stars.push({fill: true});
} else {
this.stars.push({ fill: false });
this.stars.push({fill: false});
}
}
this.changeVote.emit(this.average);
}
updateVote(vote: number) {
this.ratingService.postRating(this.nodeId, this.ratingType, vote).subscribe(
if (this.ratingValue === vote) {
this.unRateItem();
} else {
this.rateItem(vote);
}
}
rateItem(vote: number) {
this.ratingService.postRating(this.nodeId, this.ratingType, vote)
.pipe(takeUntil(this.onDestroy$))
.subscribe(
(ratingEntry: RatingEntry) => {
if (ratingEntry.entry.aggregate) {
if (this.average !== ratingEntry.entry.aggregate.average) {
this.average = ratingEntry.entry.aggregate.average;
this.calculateStars();
}
}
this.refreshRating(ratingEntry);
}
);
}
unRateItem() {
this.ratingService.deleteRating(this.nodeId, this.ratingType).subscribe(
() => {
this.ratingService.getRating(this.nodeId, this.ratingType)
.pipe(takeUntil(this.onDestroy$))
.subscribe(
(ratingEntry: RatingEntry) => {
this.refreshRating(ratingEntry);
}
);
});
}
refreshRating(ratingEntry: RatingEntry) {
this.ratingValue = Number.parseFloat(ratingEntry.entry.myRating);
this.average = ratingEntry.entry.aggregate.average;
this.ratingsCounter = ratingEntry.entry.aggregate.numberOfRatings;
this.calculateStars();
this.changeVote.emit(this.average);
}
}