+import {constants} from '../constants.js';
+const {DEFAULT_ATTRIBUTES} = constants;
+
export default class workout {
constructor() {
- this.attributes = {
- lower:false,
- core:false,
- back:false,
- upper:false,
- cardio:false,
- martial:false,
- other:false
- };
+ this.attributes = {...DEFAULT_ATTRIBUTES};
this.datesDone = [];
- this.name = "New workout";
+ this.name = "New Workout";
+ this.description = "";
}
add(dates) { // add new workout to
if(!(dates instanceof Array)) {
];
this.datesDone.sort();
}
+ changeDescription(str) {
+ if(typeof str != "string") {
+ throw new TypeError('Workout::changeDescription(str) expects parameter `str` to be a string');
+ }
+ this.description = str;
+ }
export() {
-
+ throw new Error("Not implemented");
+ }
+ get last_done() {
+ throw new Error('Not implemented');
+ }
+ remove(date) {
+ throw new Error("Not implemented");
}
setName(name) {
if(typeof name != "string") {
- throw new TypeErorr('Workout::setName(name) expects parameter `name` to be a string');
+ throw new TypeError('Workout::setName(name) expects parameter `name` to be a string');
}
+ this.name = name;
}
toggleAttribute(attr) {
- if(this.attributes[attr] == void(0)) {
+ if(this.attributes[attr] === void(0)) {
throw new TypeError('Workout::toggleAttribute(attr) expects parameter `attr` to be a valid attribute');
}
this.attributes[attr] = !this.attributes[attr];
--- /dev/null
+const constants = {
+ ADD_WORKOUT:"ADD_WORKOUT",
+ CHANGE_ATTRIBUTE:"CHANGE_ATTRIBUTE",
+ CHANGE_VIEW:"CHANGE_VIEW",
+ CHANGE_WORKOUT_DESCRIPTION:"CHANGE_WORKOUT_DESCRIPTION",
+ CHANGE_WORKOUT_NAME:"CHANGE_WORKOUT_NAME",
+ DEFAULT_ATTRIBUTES:{
+ lower:false,
+ core:false,
+ back:false,
+ upper:false,
+ cardio:false,
+ martial:false,
+ other:false
+ },
+ DELETE_WORKOUT:"DELETE_WORKOUT",
+ NEW_WORKOUT:"NEW_WORKOUT",
+ REMOVE_WORKOUT:"REMOVE_WORKOUT",
+ SORT_VIEW:"SORT_VIEW"
+};
+Object.freeze(constants);
+export constants;
\ No newline at end of file
--- /dev/null
+import {combineReducers} from 'redux';
+
+import workouts from './workouts.js';
+import view from './view.js';
+
+export default combineReducers({
+ workouts,
+ view
+});
\ No newline at end of file
--- /dev/null
+import workout from '../classes/workout.js';
+
+import {constants} from '../constants.js';
+
+const {DEFAULT_ATTRIBUTES} = constants;
+const defaultDaysAgo = {...DEFAULT_ATTRIBUTES};
+Object.keys(defaultDaysAgo).map((attr) => {
+ defaultDaysAgo[attr] = -1;
+});
+const defaultState = {
+ view:"manage",
+ daysAgo:defaultDaysAgo,
+ data:[],
+ sortKey:"last_done",
+ sortOrder:"desc"
+};
+
+export default function view(state = defaultState,action) {
+ const {CHANGE_VIEW,SORT_VIEW} = constants;
+ if((action.workouts == void(0))||(!(action.workouts instanceof Array))) {
+ return state;
+ }
+ if(!action.workouts.every((x) => x instanceof workout)) {
+ return state;
+ }
+ switch(action.type) {
+ case CHANGE_VIEW:
+ if((action.view === void(0))||(action.view == state.view)) {
+ return state;
+ }
+ switch(action.view) {
+ case "manage":
+ const newStateManageView = {...state};
+ newStateManageView.data = [];
+ for(let i=0;i<action.workouts.length;i++) {
+ newStateManageView.data.push({
+ attributes:actions.workouts[i].attributes,
+ name:actions.workouts[i].name,
+ last_done:actions.workouts[i].last_done,
+ description:actions.workouts[i].description
+ });
+ }
+ return newStateManageView;
+ case "recent":
+ const newStateRecentView = {...state};
+ newStateRecentView.data = [];
+ for(let i=0;i<action.workouts.length;i++) {
+ for(let j=0;j<action.workouts[i].datesDone;j++) {
+ newStateRecentView.data.push({
+ name:actions.workouts[i].name,
+ date:actions.workouts[i].datesDone[j]
+ });
+ }
+ }
+ return newStateRecentView;
+ default:
+ return state;
+ }
+ case SORT_VIEW:
+ /*if(action.key === void(0)) {
+ return state;
+ }
+ if(action.order === void(0)) {
+ return state;
+ }
+ let newSortKey = [...state.sortKey];
+ let newSortOrder = [...state.sortOrder];
+ const sortIndex = state.sortKey.indexOf(action.key);
+ if(sortIndex>-1) {
+ newSortOrder[sortIndex] = (newSortOrder[sortIndex]=="asc")?"desc":"asc";
+ } else {
+ newSortkey*/
+ return state;
+ default:
+ return state;
+ }
+}
\ No newline at end of file
--- /dev/null
+import {constants} from '../constants.js';
+
+export default function workouts(state = {},action) {
+ const {ADD_WORKOUT,CHANGE_ATTRIBUTE,CHANGE_WORKOUT_NAME,DEFAULT_ATTRIBUTES,DELETE_WORKOUT,NEW_WORKOUT,REMOVE_WORKOUT} = constants;
+ if(typeof action != "object") {
+ return state;
+ }
+ switch(action.type) {
+ case ADD_WORKOUT:
+ if(action.name === void(0)) {
+ return state;
+ }
+ if(!(state[action.name] instanceof workout)) {
+ return state;
+ }
+ const newStateAfterAdd = {...state};
+ try {
+ newStateAfterAdd[action.name].add(action.toAdd);
+ return newStateAfterAdd;
+ } catch(err) {
+ return state;
+ }
+ case CHANGE_ATTRIBUTE:
+ if((action.workout === void(0))||(action.attribute === void(0))) {
+ return state;
+ }
+ if(state[action.workout] === void(0)) {
+ return state;
+ }
+ try {
+ const newStateAfterChangeAttribute = {...state};
+ newStateAfterChangeAttribute[action.workout].toggleAttribute(action.attribute);
+ return newStateAfterChangeAttribute;
+ } catch(err) {
+ return state;
+ }
+ case CHANGE_WORKOUT_NAME:
+ if(action.workout === void(0)) {
+ return state;
+ }
+ if(state[action.workout] === void(0)) {
+ return state;
+ }
+ try {
+ const newStateAfterNameChange = {...state};
+ newStateAfterNameChange[action.workout].setName(action.name);
+ return newStateAfterNameChange;
+ } catch(err) {
+ return state;
+ }
+ case DELETE_WORKOUT:
+ if(action.name === void(0)) {
+ return state;
+ }
+ if(!(state[action.name] instanceof workout)) {
+ return state;
+ }
+ try {
+ const newStateAfterDelete = {...state};
+ newStateAfterDelete[action.workout].remove(toDel);
+ return newStateAfterDelete;
+ } catch(err) {
+ return state;
+ }
+ case NEW_WORKOUT:
+ if(state["New Workout"] !== void(0)) {
+ return state;
+ }
+ const newStateAfterNew = {...state};
+ const newWorkout = new workout();
+ newStateAfterNew[newWorkout.name] = newWorkout;
+ return newStateAfterNew;
+ case REMOVE_WORKOUT:
+ if(action.toRemove === void(0)) {
+ return state;
+ }
+ if(state[action.toRemove] === void(0)) {
+ return state;
+ }
+ const newStateAfterRemove = {...state};
+ delete(newStateAfterRemove[action.toRemove]);
+ return newStateAfterRemove;
+ default:
+ return state;
+ }
+}
\ No newline at end of file
--- /dev/null
+import assert from 'assert';
+
+import view from '../src/reducers/view.js';
+
+import {constants} from '../src/constants.js';
+const {CHANGE_VIEW,SORT_VIEW} = constants;
+
+describe('view reducers',() => {
+
+ describe(CHANGE_VIEW,() => {
+
+ it('should not change the state when an invalid action is given',() => {
+ assert.fail('Not implemented');
+ });
+
+ it('should successfully change the state to the `manage` view',() => {
+ assert.fail('Not implemented');
+ });
+
+ it('should successfully change the state to the `recent` view',() => {
+ assert.fail('Not implemented');
+ });
+
+ });
+
+ describe(SORT_VIEW,() => {
+
+ it('should not change the state when an invalid action is given',() => {
+ assert.fail('Not implemented');
+ });
+
+ it('should successfully sort the view',() => {
+ assert.fail('Not implemented');
+ });
+
+ });
+
+});
\ No newline at end of file
assert.fail('Not implemented');
});
+ it('should successfully add dates', () => {
+ assert.fail('Not implemented');
+ });
+
+ it('should successfully change description',() => {
+ assert.fail('Not implemented');
+ });
+
it('should successfully export', () => {
assert.fail('Not implemented');
});
- it('should successfully add dates', () => {
+ it('should successfully output the last time the workout was completed',() => {
+ assert.fail('Not implemented');
+ });
+
+ it('should successfully remove dates', () => {
assert.fail('Not implemented');
});
--- /dev/null
+import assert from 'assert';
+
+import workouts from '../src/reducers/workouts.js';
+
+import {constants} from '../src/constants.js';
+const {ADD_WORKOUT,CHANGE_ATTRIBUTE,CHANGE_WORKOUT_NAME,DELETE_WORKOUT,NEW_WORKOUT,REMOVE_WORKOUT} = constants;
+
+describe('workouts reducer',() => {
+
+ describe(ADD_WORKOUT,() => {
+
+ it('should not change the state when invalid action is given',() => {
+ assert.fail('Not implemented');
+ });
+
+ it('should successfully add a workout to an already existing workout',() => {
+ assert.fail('Not implemented');
+ });
+
+ });
+
+ describe(CHANGE_ATTRIBUTE,() => {
+
+ it('should not change the state when an invalid action is given',() => {
+ assert.fail('Not implemented');
+ });
+
+ it('should not change the state when trying to change an attribute for a nonexistent workout',() => {
+ assert.fail('Not implemented');
+ });
+
+ it('should successfully change the attribute of an already existing workout',() => {
+ assert.fail('Not implemented');
+ });
+
+ });
+
+ describe(CHANGE_WORKOUT_NAME,() => {
+
+ it('should not change the state when an invalid action is given',() => {
+ assert.fail('Not implemented');
+ });
+
+ it('should not change the state when trying to change the name for a nonexistent workout',() => {
+ assert.fail('Not implemented');
+ });
+
+ it('should successfully change the name of an already existing workout',() => {
+ assert.fail('Not implemented');
+ });
+
+ });
+
+ describe(DELETE_WORKOUT,() => {
+
+ it('should not change the state when an invalid action is given',() => {
+ assert.fail('Not implemented');
+ });
+
+ it('should not change the state when action.name refers to a nonexistent workout',() => {
+ assert.fail('Not implemented');
+ });
+
+ it('should successfully delete a workout from an existent workout',() => {
+ assert.fail('Not implemented');
+ });
+
+ });
+
+ describe(NEW_WORKOUT,() => {
+
+ it('should not change the state when an invalid action is given',() => {
+ assert.fail('Not implemented');
+ });
+
+ it('should not change the state when "New Workout" workout already exists',() => {
+ assert.fail('Not implemented');
+ });
+
+ it('should successfully add a new workout',() => {
+ assert.fail('Not implemented');
+ });
+ });
+
+ describe(REMOVE_WORKOUT,() => {
+
+ it('should not change the state when an invalid action is given',() => {
+ assert.fail('Not implemented');
+ });
+
+ it('should fail when action.toRemove refers to a nonexistent workout',() => {
+ assert.fail('Not implemented');
+ });
+
+ it('should successfully remove a workout',() => {
+ assert.fail('Not implemented');
+ });
+
+ });
+
+});
\ No newline at end of file