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
diff --git a/app.js b/app.js
index 605d776..fea4e79 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);
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/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',
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"
},
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 f848089..9af0ce2 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 @@
@@ -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 @@
+
+
+ Statistics
+
+
+
+
+ | Team |
+ Total score |
+ Games won / Games played |
+
+
+
+
+ | {{ statistic.team }} |
+ {{ statistic.score }} |
+ {{ Math.round(statistic.statistics) }}% |
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
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 };
}
},
},
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;
};
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..d8ff7cc 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],
@@ -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');
},