Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/attributes page #154

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 47 additions & 1 deletion cypress/e2e/attributes.page.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ describe('Attributes Page', () => {
cy.intercept('GET', 'api/attributes/' + userId, (req) => {
req.reply({
statusCode: 200,
body: [{"phrase":{"id":3,"adverb":"","verb":"sculpts","preposition":"with","noun":"clay"},"userCount":1},{"phrase":{"id":2,"adverb":"","verb":"plays","preposition":"","noun":"chess"},"userCount":2}]
body: [{"phrase":{"id":3,"adverb":"","verb":"sculpts","preposition":"with","noun":"clay"},"sequence":1,"userCount":1},
{"phrase":{"id":2,"adverb":"","verb":"plays","preposition":"","noun":"chess"},"sequence":2,"userCount":2}]
});
});

Expand Down Expand Up @@ -117,4 +118,49 @@ describe('Attributes Page', () => {
})
})
})
describe('Reorder Attributes', () => {

it('should move an attribute up the list', () => {
cy.goToAttributesPage();
cy.get('[data-test="attributeItem"]').eq(1).click();
cy.get('[data-test="upButton"]').click();
cy.get('[data-test="attributeItem"]').eq(0).contains(' plays chess (2 users)x');
cy.get('[data-test="attributeItem"]').eq(1).contains( ' sculpts with clay (1 users)x');
});

it('should move an attribute down the list', () => {
cy.goToAttributesPage();
cy.get('[data-test="attributeItem"]').eq(0).click();
cy.get('[data-test="downButton"]').click();
cy.get('[data-test="attributeItem"]').eq(0).contains(' plays chess');
cy.get('[data-test="attributeItem"]').eq(1).contains( ' sculpts with clay (1 users)x');
});

it('should disable the "Up" button for the first item', () => {
cy.goToAttributesPage();
cy.get('[data-test="attributeItem"]').eq(0).click();
cy.get('[data-test="upButton"]').should('have.attr','disabled');
});

it('should disable the "Down" button for the last item', () => {
cy.goToAttributesPage();
cy.get('[data-test="attributeItem"]').eq(1).click();
cy.get('[data-test="downButton"]').should('have.attr','disabled');
});

it('should enable and save changes after reordering', () => {
cy.goToAttributesPage();
cy.get('[data-test="attributeItem"]').eq(1).click();
cy.get('[data-test="upButton"]').click();
cy.get('[data-test="saveButton"]').should('not.be.disabled');
cy.intercept('POST', '/api/attributes/update', {
statusCode: 200,
body: { success: true }
}).as('saveAttributesOrder');
cy.get('[data-test="saveButton"]').click();
cy.wait('@saveAttributesOrder');
});
});


})
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,8 @@ export class AttributesApiService {
);
});
}
saveSequence(data: {phrases: {sequence: number, phraseId: number}[]}) {
saveAttributeSequences(data: {phrases: {sequence: number, phraseId: number}[]}) {
const url = environment.apiUrl + '/api/attributes/update';
console.log(data);

return new Promise((resolve, reject) => {
this._apiService.post(url, data).subscribe(
(response: boolean) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Injectable } from '@angular/core';
import {AuthService, JWTApiService} from '@savvato-software/savvato-javascript-services';
import {AuthService, JWTApiService, SequenceService} from '@savvato-software/savvato-javascript-services';

import { AttributesApiService } from "./attributes.api.service";
import {Attribute} from '../../../_type/attribute.type'
Expand All @@ -13,10 +13,12 @@ export class AttributesModelService {

model:Attribute[] = [];
originalAttributes: Attribute[] = [];
selectedAttr: Attribute | null = null;

constructor(private _apiService: JWTApiService,
private _authService: AuthService,
private _attributesApiService: AttributesApiService,
private _sequenceService: SequenceService,
private _constants: Constants) {

}
Expand All @@ -37,13 +39,45 @@ export class AttributesModelService {


get() {
return this.model;
return this.model.sort((a, b) => a.sequence - b.sequence);
}

isDirty(): boolean{
return JSON.stringify(this.model) !== JSON.stringify(this.originalAttributes);
}

setSelectedAttr(attr: Attribute) {
this.selectedAttr = attr;
}

isSelected(attr: Attribute): boolean {
return this.selectedAttr && attr && (this.selectedAttr.phrase.id === attr.phrase.id);
}

canMoveUp() {
if (this.model.length > 0 && this.selectedAttr) {
return this._sequenceService.isAbleToMove(this.model, this.selectedAttr, this._sequenceService.UP);
}

return false;
}

canMoveDown() {
if (this.model.length > 0 && this.selectedAttr) {
return this._sequenceService.isAbleToMove(this.model, this.selectedAttr, this._sequenceService.DOWN);
}

return false;
}

moveUp() {
this._sequenceService.moveSequenceByOne(this.model, this.selectedAttr, this._sequenceService.UP);
}

moveDown() {
this._sequenceService.moveSequenceByOne(this.model, this.selectedAttr, this._sequenceService.DOWN);
}

save(model:Attribute) {
return new Promise((resolve, reject) => {
this._attributesApiService.save(model).then(
Expand All @@ -58,15 +92,15 @@ export class AttributesModelService {
});
}

saveAttributeSequence() {
saveAttributeSequences() {
return new Promise((resolve, reject) => {
let phrase = this.model.map(item => {return {
let listOfPhraseIdSequencePairs = this.model.map(item => {return {
'sequence': item.sequence,
'phraseId': item.phrase.id
};
})
let data = {'phrases': phrase}
this._attributesApiService.saveSequence(data).then(
let data = {'phrases': listOfPhraseIdSequencePairs}
this._attributesApiService.saveAttributeSequences(data).then(
(booleanMessage: boolean) => {
resolve(booleanMessage);
console.log("Call to attributeApiService was successful(model) + (booleanMessage)")
Expand Down
9 changes: 4 additions & 5 deletions src/app/pages/attributes-page/attributes.page.html
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
<app-header [currentPageTitle]="headerPageTitle" [displayPrimaryActionButton]="true"
[primaryActionButtonText]="headerPagePrimaryActionButtonText" [primaryActionButtonFunc]="getCreateBtnClickFunc()"></app-header>
<ion-toolbar>
<ion-button (click)="moveUp()" [disabled]="!selectedAttr || !canMoveUp()">Up</ion-button>
<ion-button (click)="moveDown()" [disabled]="!selectedAttr || !canMoveDown()">Down</ion-button>
<ion-button (click)="saveChanges()" [disabled]="!isSaveEnabled()">Save</ion-button>
<ion-button data-test="upButton" (click)="moveUp()" [disabled]="!canMoveUp()">Up</ion-button>
<ion-button data-test="downButton" (click)="moveDown()" [disabled]="!canMoveDown()">Down</ion-button>
<ion-button data-test="saveButton" (click)="saveChanges()" [disabled]="!isSaveEnabled()">Save</ion-button>
</ion-toolbar>
<ion-content>
<!--change attributes to getAttributes()-->
<ion-card class="attributeItem" color="warning" *ngFor="let attr of getAttributes()" [ngClass]="{'selected': selectedAttr === attr}" (click)="selectAttribute(attr)">
<ion-card data-test="attributeItem" class="attributeItem" color="warning" *ngFor="let attr of getAttributes()" [ngClass]="{'selected': isSelected(attr)}" (click)="selectAttribute(attr)">
<ion-card-content>
<ion-card-title>{{attr['phrase']['adverb'] || ''}} {{attr['phrase']['verb'] || ''}} {{attr['phrase']['preposition'] || ''}} {{attr['phrase']['noun'] || ''}}
<span class="user-count">({{attr['userCount'] || '0'}} users)</span>
Expand Down
28 changes: 10 additions & 18 deletions src/app/pages/attributes-page/attributes.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { LoadingService } from "../../_services/loading-spinner/loading.service"
import { AttributesModelService } from "./_services/attributes.model.service";
import { SequenceService, Sequenceable } from '@savvato-software/savvato-javascript-services';
import {Attribute} from '../../_type/attribute.type'
import {Phrase} from '../../_type/phrase.type'

@Component({
selector: 'app-attributes',
Expand All @@ -28,7 +27,6 @@ export class AttributesPage implements OnInit {
private _loadingService: LoadingService,
private _attributesModelService: AttributesModelService,
private router: Router,
private sequenceService: SequenceService,
) {}

public ngOnInit() {
Expand All @@ -43,49 +41,43 @@ export class AttributesPage implements OnInit {
});
}

get attributes(): Attribute[] {
const attributes: Attribute[] = this._attributesModelService.get();
return attributes;
}

getAttributes():Attribute[] {
const attributes: Attribute[] = this._attributesModelService.get();
return attributes;
}

selectAttribute(attr: Attribute) {
this.selectedAttr = attr;
this._attributesModelService.setSelectedAttr(attr);
}

isSelected(attr: Attribute): boolean {
return this._attributesModelService.isSelected(attr);
}

canMoveUp(): boolean {
return this.selectedAttr && this.selectedAttr.sequence > 1;
return this._attributesModelService.canMoveUp();
}

canMoveDown(): boolean {
return this.selectedAttr && this.selectedAttr.sequence < this.attributes.length;
return this._attributesModelService.canMoveDown();
}

isSaveEnabled(): boolean {
//returns true if there is a change
let isDirty = this._attributesModelService.isDirty();
console.log(isDirty)
return isDirty;
}

moveUp() {
if (this.selectedAttr && this.canMoveUp()) {
this.sequenceService.moveSequenceByOne(this._attributesModelService.get(), this.selectedAttr, this.sequenceService.UP);
}
this._attributesModelService.moveUp();
}

moveDown() {
if (this.selectedAttr && this.canMoveDown()) {
this.sequenceService.moveSequenceByOne(this._attributesModelService.get(), this.selectedAttr, this.sequenceService.DOWN);
}
this._attributesModelService.moveDown();
}

saveChanges() {
this._attributesModelService.saveAttributeSequence()
this._attributesModelService.saveAttributeSequences()
.then((response) => {
console.log("Call to attributeApiService was successful");
return this._attributesModelService.init()
Expand Down
Loading