From 04ebb5d0d4e7a50ac3f1b66566f3b32aa54bd462 Mon Sep 17 00:00:00 2001 From: Edwin ANDRIVET Date: Tue, 10 Oct 2017 15:55:54 +0200 Subject: [PATCH 01/10] Added little memento about mongodb. --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 89eb9a8..59437e7 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,9 @@ > Babyfoo project +## Environment setup +This project uses [MongoDB](https://www.mongodb.com) so don't forget to install it first. + ## Build Setup ``` bash From d902d52c810bdd6e9ed31df6e3477f100245d7a3 Mon Sep 17 00:00:00 2001 From: Edwin ANDRIVET Date: Tue, 10 Oct 2017 15:57:22 +0200 Subject: [PATCH 02/10] Updated outdated dependencies. kcors update will allow a smooth transition to koa v3. --- package.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 3795a63..9aadb3e 100644 --- a/package.json +++ b/package.json @@ -14,8 +14,8 @@ }, "dependencies": { "axios": "^0.16.0", - "cross-env": "^3.1.4", - "kcors": "^1.3.2", + "cross-env": "^5.0.5", + "kcors": "^2.2.1", "koa": "^2.0.0", "koa-bodyparser": "^4.2.0", "koa-json": "^2.0.2", @@ -31,11 +31,11 @@ "vuex": "^2.3.1" }, "devDependencies": { - "babel-eslint": "^7.1.1", - "eslint": "^3.19.0", - "eslint-config-airbnb-base": "^11.1.0", - "eslint-plugin-html": "^2.0.0", - "eslint-plugin-import": "^2.2.0", + "babel-eslint": "^8.0.1", + "eslint": "^4.8.0", + "eslint-config-airbnb-base": "^12.0.2", + "eslint-plugin-html": "^3.2.2", + "eslint-plugin-import": "^2.7.0", "nodemon": "^1.11.0", "scmp": "^2.0.0" }, From a50e5f09bd898cde1fa9b4a41178197bc6902ec0 Mon Sep 17 00:00:00 2001 From: Edwin ANDRIVET Date: Tue, 10 Oct 2017 16:02:40 +0200 Subject: [PATCH 03/10] Moved nuxt dev config from app.js. Fixed paths. --- nuxt.config.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/nuxt.config.js b/nuxt.config.js index 684bfad..7639656 100644 --- a/nuxt.config.js +++ b/nuxt.config.js @@ -1,4 +1,5 @@ module.exports = { + dev: (process.env.NODE_ENV !== 'production'), /* ** Headers of the page */ @@ -14,14 +15,14 @@ module.exports = { ** Global CSS */ css: [ - { src: '~assets/scss/main.scss', lang: 'scss' }, + { src: '~/assets/scss/main.scss', lang: 'scss' }, ], /* ** Customize the progress-bar color */ loading: { color: '#3B8070' }, plugins: [ - { src: '~plugins/toast', ssr: false }, + { src: '~/plugins/toast', ssr: false }, ], env: { baseUrl: process.env.BASE_URL || 'http://localhost:3000', From 73ba93b4fc3d05bb082614755e1ced67b29cc6e8 Mon Sep 17 00:00:00 2001 From: Edwin ANDRIVET Date: Tue, 10 Oct 2017 16:07:38 +0200 Subject: [PATCH 04/10] Fixed nuxt.js and nuxt.js as koa middleware. Updated semver nuxt.js broke the app : - Importing nuxt.js changed a bit, deconstructor needed. - See issue #1206 for the koa middleware integration. --- app.js | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/app.js b/app.js index 605d776..58c492b 100644 --- a/app.js +++ b/app.js @@ -4,7 +4,7 @@ const koaBody = require('koa-bodyparser'); const cors = require('kcors'); const mongoose = require('koa-mongoose'); const json = require('koa-json'); -const Nuxt = require('nuxt'); +const { Builder, Nuxt } = require('nuxt'); const config = require('./nuxt.config.js'); const genericCRUD = require('./server/generic.js'); @@ -12,13 +12,12 @@ const genericCRUD = require('./server/generic.js'); const app = new Koa(); app.use(cors()); const router = new KoaRouter(); -config.dev = !(app.env === 'production'); - const nuxt = new Nuxt(config); // Build only in dev mode -if (config.dev) { - nuxt.build() +if (nuxt.options.dev) { + new Builder(nuxt) + .build() .catch((error) => { console.error(error); // eslint-disable-line no-console process.exit(1); @@ -48,9 +47,18 @@ router.use('/api/scores', genericCRUD('Score').routes()); app.use(router.routes()); app.use(router.allowedMethods()); -app.use(async (ctx) => { +app.use((ctx) => { ctx.status = 200; // koa defaults to 404 when it sees that status is unset - await nuxt.render(ctx.req, ctx.res); + + // Solves nuxt.js issue #1206 + return new Promise((resolve, reject) => { + ctx.res.on('close', resolve); + ctx.res.on('finish', resolve); + nuxt.render(ctx.req, ctx.res, (promise) => { + // nuxt.render passes a rejected promise into callback on error. + promise.then(resolve).catch(reject); + }); + }); }); app.listen(3000); From e14c95e534b6e33fd1f1c06807fdb30c4451c99e Mon Sep 17 00:00:00 2001 From: Edwin ANDRIVET Date: Tue, 10 Oct 2017 16:15:52 +0200 Subject: [PATCH 05/10] Updated nuxt.js needs to export the state as a function. Fixed some import paths. --- store/index.js | 2 +- store/score.js | 6 +++--- store/user.js | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/store/index.js b/store/index.js index 6ed20c3..aaf8b40 100644 --- a/store/index.js +++ b/store/index.js @@ -1,4 +1,4 @@ -export const state = {}; +export const state = () => {}; export const getters = {}; diff --git a/store/score.js b/store/score.js index 1c72ded..dae4605 100644 --- a/store/score.js +++ b/store/score.js @@ -1,8 +1,8 @@ -import ScoreAPI from '~plugins/api/score'; +import ScoreAPI from '~/plugins/api/score'; -export const state = { +export const state = () => ({ scores: [], -}; +}); export const getters = { scores: state => state.scores, diff --git a/store/user.js b/store/user.js index 966e6b6..207ec83 100644 --- a/store/user.js +++ b/store/user.js @@ -1,10 +1,10 @@ import slug from 'slug'; -import UserAPI from '~plugins/api/user'; +import UserAPI from '~/plugins/api/user'; -export const state = { +export const state = () => ({ usersCache: {}, users: [], -}; +}); export const getters = { getUser: state => id => state.usersCache[id], From 4ab195ab7f6c09c8a41499c22a8737ef03e88a8c Mon Sep 17 00:00:00 2001 From: Edwin ANDRIVET Date: Thu, 12 Oct 2017 15:27:02 +0200 Subject: [PATCH 06/10] Fixed inverted color of winner team. Added a :key asked by v-for, where possible. --- pages/scores/index.vue | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pages/scores/index.vue b/pages/scores/index.vue index f848089..ee3fb39 100644 --- a/pages/scores/index.vue +++ b/pages/scores/index.vue @@ -18,7 +18,7 @@ {{ score.red.join(', ') }} {{ score.score.blue }} {{ score.score.red }} - + {{ score.score.blue > score.score.red ? 'Blue' : 'Red' }} @@ -31,17 +31,17 @@
- - + +
From dd7d0a6d8253aee6a598be59e739e8961f576373 Mon Sep 17 00:00:00 2001 From: Edwin ANDRIVET Date: Thu, 12 Oct 2017 15:29:26 +0200 Subject: [PATCH 07/10] Fixed v-model editing vuex store variable. Added :key binding asked by v-for. --- pages/users/index.vue | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/pages/users/index.vue b/pages/users/index.vue index 00dfe31..e54ad00 100644 --- a/pages/users/index.vue +++ b/pages/users/index.vue @@ -10,14 +10,14 @@ - + {{ user.name }} - + @@ -36,7 +36,7 @@ function generateFreshUserToEdit() { return { name: '', - _id: null, + _id: undefined, }; } export default { @@ -65,11 +65,12 @@ ...mapActions({ userSave: 'user/save', }), - changeCurrentUser(user = null) { - if (!user) { + changeCurrentUser(user = undefined) { + if (user === undefined) { this.userToEdit = generateFreshUserToEdit(); } else { - this.userToEdit = this.getUser(user._id); + const real_user = this.getUser(user._id); + this.userToEdit = { ...real_user }; } }, }, From e0d1fed3e9370b26c74292f6fff322fc4a94ad40 Mon Sep 17 00:00:00 2001 From: Edwin ANDRIVET Date: Thu, 12 Oct 2017 15:35:32 +0200 Subject: [PATCH 08/10] Added the ability to change existing user name. Added early return in case no name was sent. --- store/user.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/store/user.js b/store/user.js index 207ec83..d8ff7cc 100644 --- a/store/user.js +++ b/store/user.js @@ -22,10 +22,18 @@ export const mutations = { export const actions = { async save({ commit }, user) { + if (!user.name) { + return; + } if (!user._id) { user._id = slug(user.name).toLowerCase(); } - user = (await UserAPI.create(user)).data; + const userExists = (await UserAPI.fetchOne(user._id)).data; + if (!userExists) { + user = (await UserAPI.create(user)).data; + } else { + (await UserAPI.update(user)).data; + } commit('SET_USER', user); commit('REFRESH_USERS'); }, From 1815bac3403324c6d4fe6202d406666d96598de1 Mon Sep 17 00:00:00 2001 From: Edwin ANDRIVET Date: Thu, 12 Oct 2017 15:37:12 +0200 Subject: [PATCH 09/10] Added router and API functions for username updating. --- plugins/api/user.js | 6 ++++++ server/generic.js | 13 +++++++++++++ 2 files changed, 19 insertions(+) diff --git a/plugins/api/user.js b/plugins/api/user.js index 2a9f606..cdb7b91 100644 --- a/plugins/api/user.js +++ b/plugins/api/user.js @@ -9,5 +9,11 @@ export default Object.assign( fetchAll() { return this.get('/users'); }, + fetchOne(id) { + return this.get(`/users/${id}`); + }, + update(user) { + return this.put('/users', user); + }, }, ); diff --git a/server/generic.js b/server/generic.js index b1e2253..e1e9d14 100644 --- a/server/generic.js +++ b/server/generic.js @@ -14,5 +14,18 @@ module.exports = function generic(modelName) { const User = model(modelName); ctx.body = await User.find(); }); + router.get('/:id', async (ctx) => { + const { model, params } = ctx; + const User = model(modelName); + const user = await User.findById(params.id); + ctx.body = user; + }); + router.put('/', async (ctx) => { + const { model, request } = ctx; + const User = model(modelName); + const user = request.body; + await User.update({ _id: user._id }, user); + ctx.body = { success: 'ok' }; + }); return router; }; From bb5683ddcd5e154dde6d9225247f44164eeef752 Mon Sep 17 00:00:00 2001 From: Edwin ANDRIVET Date: Thu, 19 Oct 2017 12:04:39 +0200 Subject: [PATCH 10/10] Added one of possible statistics on its own page. --- app.js | 2 +- layouts/default.vue | 3 +- pages/index.vue | 1 + pages/scores/index.vue | 19 +++++--- pages/statistics/index.vue | 90 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 107 insertions(+), 8 deletions(-) create mode 100644 pages/statistics/index.vue diff --git a/app.js b/app.js index 58c492b..fea4e79 100644 --- a/app.js +++ b/app.js @@ -50,7 +50,7 @@ app.use(router.allowedMethods()); app.use((ctx) => { ctx.status = 200; // koa defaults to 404 when it sees that status is unset - // Solves nuxt.js issue #1206 + // Solves nuxt.js issue #1206 return new Promise((resolve, reject) => { ctx.res.on('close', resolve); ctx.res.on('finish', resolve); diff --git a/layouts/default.vue b/layouts/default.vue index 5b78801..d1fe862 100644 --- a/layouts/default.vue +++ b/layouts/default.vue @@ -3,8 +3,9 @@ diff --git a/pages/index.vue b/pages/index.vue index 5b1bd27..a71c17f 100644 --- a/pages/index.vue +++ b/pages/index.vue @@ -3,5 +3,6 @@

Babyfoo score board

Users Scores + Statistics diff --git a/pages/scores/index.vue b/pages/scores/index.vue index ee3fb39..9af0ce2 100644 --- a/pages/scores/index.vue +++ b/pages/scores/index.vue @@ -56,9 +56,9 @@ blue: [], red: [], score: { - red: null, - blue: null, - } + red: undefined, + blue: undefined, + }, }; } @@ -77,10 +77,17 @@ }), }, methods: { + areSameArrays(a, b) { + return !a.some((value, index) => value !== b[index]) + }, async create(score) { + if (this.areSameArrays(score.red, score.blue)) { + this.$toasted.error("You can't play against yourself, duuh!"); + return; + } try { await this.scoreCreate(score); - this.$toasted.success('Score saved !'); + this.$toasted.success('Score saved!'); this.newScore = generateFreshScore(); } catch (e) { this.$toasted.error(e.response.data); @@ -90,8 +97,8 @@ scoreCreate: 'score/create', }), flushNewScore() { - this.newScore = generateFreshScore(); + this.newScore = generateFreshScore(); }, }, }; - \ No newline at end of file + diff --git a/pages/statistics/index.vue b/pages/statistics/index.vue new file mode 100644 index 0000000..ae9e180 --- /dev/null +++ b/pages/statistics/index.vue @@ -0,0 +1,90 @@ + + + + + \ No newline at end of file