Browse Source

Parse data to table

main
Haris Razis 4 years ago
parent
commit
e7c5c54de7
  1. 5
      client/services/socket.js
  2. 5
      server/routes/data.js
  3. 2
      server/schemas/joi.js
  4. 2
      server/services/socket.js
  5. 1
      web/src/assets/undraw_data_trends_b0wg.svg
  6. 9
      web/src/components/Navbar.vue
  7. 10
      web/src/router/index.ts
  8. 20
      web/src/store/index.ts
  9. 56
      web/src/store/modules/athletes.ts
  10. 79
      web/src/store/modules/backend.ts
  11. 88
      web/src/store/modules/user.ts
  12. 50
      web/src/views/Athlete.vue
  13. 80
      web/src/views/Athletes.vue
  14. 2
      web/src/views/Chart.vue
  15. 18
      web/src/views/Dashboard.vue
  16. 6
      web/src/views/DashboardHome.vue
  17. 21
      web/src/views/Login.vue
  18. 20
      web/src/views/Profile.vue
  19. 32
      web/src/views/Table.vue

5
client/services/socket.js

@ -9,7 +9,7 @@ const mac = getMAC();
console.log(chalk.green(` console.log(chalk.green(`
ID: ${mac} ID: ${mac}
Use this ID, to adopt the athlete on the user dashboard. Use this ID, to adopt the athlete on the user dashboard.
`)) `));
socket.on('connect', () => { socket.on('connect', () => {
console.log(chalk.green('Connected to server!')); console.log(chalk.green('Connected to server!'));
@ -35,6 +35,5 @@ socket.on('closeConn', () => {
}); });
setInterval(() => { setInterval(() => {
socket.emit('data', {measurement: 5, mac, pointName: 'leg-measurement'}); socket.emit('data', {measurement: Date.now(), mac, pointName: 'test-measure'});
}, 3 * 1000); }, 3 * 1000);

5
server/routes/data.js

@ -1,11 +1,13 @@
const express = require('express') const express = require('express')
const router = express.Router(); const router = express.Router();
const mongoose = require('mongoose'); const mongoose = require('mongoose');
const {requireAuth} = require('../middlewares/middleware'); const {celebrate} = require('celebrate');
const {requireAuth} = require('../middlewares/middleware');
const Athlete = mongoose.model('Athlete'); const Athlete = mongoose.model('Athlete');
const {influx_bucket} = require('../config/keys') const {influx_bucket} = require('../config/keys')
const {iQuery} = require('../actions/influx_actions') const {iQuery} = require('../actions/influx_actions')
const {guid} = require('../schemas/joi')
router.get('/api/data', router.get('/api/data',
requireAuth, requireAuth,
@ -18,6 +20,7 @@ router.get('/api/data',
router.get('/api/data/:id', router.get('/api/data/:id',
requireAuth, requireAuth,
celebrate(guid),
async (req, res) => { async (req, res) => {
const athlete = await Athlete.findById(req.params.id); const athlete = await Athlete.findById(req.params.id);

2
server/schemas/joi.js

@ -34,7 +34,7 @@ const athleteUpdateSchema = {
socketID: Joi.string().required(), socketID: Joi.string().required(),
name: Joi.string().required(), name: Joi.string().required(),
__v: Joi.number().integer(), __v: Joi.number().integer(),
_trainer: Joi.string().allow(''), _trainer: Joi.string().allow('').default(''),
} }
} }

2
server/services/socket.js

@ -39,7 +39,7 @@ module.exports = (server) => {
socket.on('data', (data) => { socket.on('data', (data) => {
const {measurement, pointName, mac} = data; const {measurement, pointName, mac} = data;
io.emit('console', {measurement}) io.emit('console', {measurement, pointName})
iWrite(pointName, mac, measurement) iWrite(pointName, mac, measurement)
}); });

1
web/src/assets/undraw_data_trends_b0wg.svg

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 90 KiB

9
web/src/components/Navbar.vue

@ -3,7 +3,7 @@
<div class="navbar-brand"> <div class="navbar-brand">
<router-link to="/"> <router-link to="/">
<a class="navbar-item"> <a class="navbar-item">
<img height="150" src="../assets/undraw_server_q2pb.svg" width="60"/> <img height="150" src="../assets/undraw_data_trends_b0wg.svg" width="60"/>
<h3 class="is-size-4 has-text-white">Ichnaea</h3> <h3 class="is-size-4 has-text-white">Ichnaea</h3>
</a> </a>
</router-link> </router-link>
@ -47,16 +47,13 @@ export default class Navbar extends Vue {
private user = <UserInterface>{}; private user = <UserInterface>{};
created() { created() {
this.user = this.$store.getters.currentUser this.user = this.$store.getters.user_current
} }
private logout() { private logout() {
this.$store.dispatch('logout') this.$store.dispatch('logout')
.then(() => this.$router.push('/')) .then(() => this.$router.push('/'))
.catch((err: any) => { .catch(() => this.$router.push('/'));
console.log(err)
this.$router.push('/')
})
} }
} }
</script> </script>

10
web/src/router/index.ts

@ -80,13 +80,13 @@ const router = createRouter({
router.beforeEach((to, from, next) => { router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) { if (to.matched.some(record => record.meta.requiresAuth)) {
if (store.getters.isLoggedIn) { if (store.getters.user_loggedIn) {
next() next();
return return;
} }
next('/login') next('/login');
} else { } else {
next() next();
} }
}) })

20
web/src/store/index.ts

@ -4,6 +4,7 @@ import createPersistedState from "vuex-persistedstate";
import user from './modules/user' import user from './modules/user'
import backend from './modules/backend' import backend from './modules/backend'
import athletes from './modules/athletes' import athletes from './modules/athletes'
import axios, {AxiosResponse} from "axios";
export default createStore({ export default createStore({
modules: { modules: {
@ -11,5 +12,24 @@ export default createStore({
backend, backend,
athletes, athletes,
}, },
actions: {
logout({commit}) {
return new Promise((resolve, reject) => {
axios({
method: 'POST',
url: '/auth/logout',
})
.then((resp: AxiosResponse) => {
commit('auth_logout');
commit('athletes_logout');
commit('server_logout');
resolve(resp);
})
.catch((err: Error) => {
reject(err);
});
});
}
},
plugins: [createPersistedState()] plugins: [createPersistedState()]
}) })

56
web/src/store/modules/athletes.ts

@ -16,30 +16,30 @@ export default class Athletes extends VuexModule {
private athlete = <AthleteInterface>{}; private athlete = <AthleteInterface>{};
private trainer = <UserInterface>{}; private trainer = <UserInterface>{};
private athletes = [<AthleteInterface>{}]; private athletes = [<AthleteInterface>{}];
private err = <Error>{} private err = <Error>{};
get currentAthlete() { get athlete_current() {
return this.athlete; return this.athlete;
} }
get currentTrainer() { get athlete_trainer() {
return this.trainer; return this.trainer;
} }
get currentAthletes() { get athlete_currents() {
return this.athletes; return this.athletes;
} }
get getErrAthlete() { get athlete_err() {
return this.err return this.err;
} }
@Mutation save_trainer(trainer: UserInterface) { @Mutation api_trainer(trainer: UserInterface) {
this.trainer = trainer; this.trainer = trainer;
} }
@Mutation @Mutation
private save_athlete(athlete: AthleteInterface) { private api_athlete(athlete: AthleteInterface) {
this.athlete = athlete; this.athlete = athlete;
} }
@ -49,36 +49,36 @@ export default class Athletes extends VuexModule {
} }
@Mutation @Mutation
private auth_logout() { private athletes_logout() {
this.athlete = <AthleteInterface>{}; this.athlete = <AthleteInterface>{};
this.trainer = <UserInterface>{} this.trainer = <UserInterface>{};
this.athletes = [<AthleteInterface>{}]; this.athletes = [<AthleteInterface>{}];
} }
@Mutation @Mutation
private update_error(err: Error) { private update_err(err: Error) {
this.err = err this.err = err;
} }
@Action @Action
private getAthletes() { private athlete_getAll() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
axios({ axios({
method: 'GET', method: 'GET',
url: '/api/athletes' url: '/api/athletes'
}) })
.then((resp: AxiosResponse) => { .then((resp: AxiosResponse) => {
this.context.commit('api_athletes', resp.data) this.context.commit('api_athletes', resp.data);
resolve(resp) resolve(resp);
}) })
.catch((err: Error) => { .catch((err: Error) => {
reject(err) reject(err);
}) });
}) });
} }
@Action @Action
private updateAthlete(athlete: AthleteInterface) { private athlete_update(athlete: AthleteInterface) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
axios({ axios({
method: 'PUT', method: 'PUT',
@ -86,22 +86,22 @@ export default class Athletes extends VuexModule {
data: {...athlete} data: {...athlete}
}) })
.then((resp: AxiosResponse) => { .then((resp: AxiosResponse) => {
this.context.commit('save_athlete', resp.data) this.context.commit('api_athlete', resp.data);
resolve(resp) resolve(resp);
}) })
.catch((err: Error) => { .catch((err: Error) => {
reject(err) reject(err);
}) });
}) });
} }
@Action @Action
private saveTrainer(trainer: UserInterface) { private athlete_saveLocalTrainer(trainer: UserInterface) {
this.context.commit('save_trainer', trainer) this.context.commit('api_trainer', trainer);
} }
@Action @Action
private saveAthlete(athlete: AthleteInterface) { private athlete_saveLocal(athlete: AthleteInterface) {
this.context.commit('save_athlete', athlete) this.context.commit('api_athlete', athlete);
} }
} }

79
web/src/store/modules/backend.ts

@ -1,15 +1,82 @@
import {Module, Mutation, VuexModule} from 'vuex-module-decorators' import {Action, Module, Mutation, VuexModule} from 'vuex-module-decorators'
import axios, {AxiosResponse} from "axios";
export interface AthleteData {
measurement: Date,
pointName: string,
}
@Module @Module
export default class Backend extends VuexModule { export default class Backend extends VuexModule {
private serverStatus = false private serverStatus = false;
private liveAthData: AthleteData[] = [];
get server_status() {
return this.serverStatus;
}
get server_liveData() {
return this.liveAthData;
}
get currentServerStatus() { @Mutation
return this.serverStatus private socket_connection(status: boolean) {
this.serverStatus = status;
}
@Mutation
private server_queueData(data: AthleteData) {
this.liveAthData.push(data);
} }
@Mutation @Mutation
private serverConnected(status: boolean) { private server_dequeueData() {
this.serverStatus = status this.liveAthData.shift();
} }
@Mutation
private server_logout() {
this.liveAthData = []
}
@Action
private server_saveLiveData(data: AthleteData) {
console.log(this.liveAthData);
this.context.commit('server_queueData', data);
if (this.liveAthData.length > 15)
this.context.commit('server_dequeueData');
} //Too "expensive" of an action? To be refactored.
@Action
private server_getAll() {
return new Promise((resolve, reject) => {
axios({
method: 'GET',
url: `/api/data/`
})
.then((resp: AxiosResponse) => {
resolve(resp)
})
.catch((err: Error) => {
reject(err)
});
});
}
@Action
private server_getOne(id: string) {
return new Promise((resolve, reject) => {
axios({
method: 'GET',
url: `/api/data/${id}`
})
.then((resp: AxiosResponse) => {
resolve(resp)
})
.catch((err: Error) => {
reject(err)
});
});
}
} }

88
web/src/store/modules/user.ts

@ -17,16 +17,16 @@ export default class User extends VuexModule {
private userStatus = false; private userStatus = false;
private err = <Error>{}; private err = <Error>{};
get currentUser() { get user_current() {
return this.user; return this.user;
} }
get isLoggedIn() { get user_loggedIn() {
return this.userStatus; return this.userStatus;
} }
get getErrUser() { get user_err() {
return this.err return this.err;
} }
@Mutation @Mutation
@ -38,7 +38,7 @@ export default class User extends VuexModule {
@Mutation @Mutation
private auth_error(err: Error) { private auth_error(err: Error) {
this.userStatus = false; this.userStatus = false;
this.err = err this.err = err;
} }
@Mutation @Mutation
@ -48,17 +48,17 @@ export default class User extends VuexModule {
} }
@Mutation @Mutation
private update_error(err: Error) { private update_err(err: Error) {
this.err = err this.err = err;
} }
@Mutation @Mutation
private update_user(user: UserInterface) { private update_user(user: UserInterface) {
this.user = user this.user = user;
} }
@Action @Action
private login(user: UserInterface) { private user_login(user: UserInterface) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
axios({ axios({
method: 'POST', method: 'POST',
@ -66,18 +66,18 @@ export default class User extends VuexModule {
data: qs.stringify({...user}) data: qs.stringify({...user})
}) })
.then((resp: AxiosResponse) => { .then((resp: AxiosResponse) => {
this.context.commit('auth_success', resp.data.user) this.context.commit('auth_success', resp.data.user);
resolve(resp) resolve(resp);
}) })
.catch((err: Error) => { .catch((err: Error) => {
this.context.commit('auth_error', err) this.context.commit('auth_error', err);
reject(err) reject(err);
}) });
}) });
} }
@Action @Action
private logout() { private user_logout() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
axios({ axios({
method: 'POST', method: 'POST',
@ -86,16 +86,16 @@ export default class User extends VuexModule {
.then((resp: AxiosResponse) => { .then((resp: AxiosResponse) => {
this.context.commit('auth_logout'); this.context.commit('auth_logout');
this.context.commit('athlete_logout'); this.context.commit('athlete_logout');
resolve(resp) resolve(resp);
}) })
.catch((err: Error) => { .catch((err: Error) => {
reject(err) reject(err);
}) });
}) });
} }
@Action @Action
private getCurrentUser() { private user_currentSession() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
axios({ axios({
method: 'GET', method: 'GET',
@ -103,49 +103,49 @@ export default class User extends VuexModule {
}) })
.then((resp: AxiosResponse) => { .then((resp: AxiosResponse) => {
this.context.commit('auth_success', resp.data); this.context.commit('auth_success', resp.data);
resolve(resp) resolve(resp);
}) })
.catch((err: Error) => { .catch((err: Error) => {
this.context.commit('auth_error') this.context.commit('auth_error')
reject(err) reject(err);
}) });
}) });
} }
@Action @Action
private specificUser(id: string) { private user_update(user: UserInterface) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
axios({ axios({
method: 'GET', method: 'PUT',
url: `/api/user/${id}` url: `/api/user/${user._id}`,
data: {...user}
}) })
.then((resp: AxiosResponse) => { .then((resp: AxiosResponse) => {
resolve(resp) this.context.commit('update_user', resp.data);
resolve(resp);
}) })
.catch((err: Error) => { .catch((err: Error) => {
reject(err) this.context.commit('update_err', err)
}) reject(err);
}) });
});
} }
@Action @Action
private updateUser(user: UserInterface) { private user_getOne(id: string) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
axios({ axios({
method: 'PUT', method: 'GET',
url: `/api/user/${user._id}`, url: `/api/user/${id}`
data: {...user}
}) })
.then((resp: AxiosResponse) => { .then((resp: AxiosResponse) => {
console.log(resp.data) resolve(resp);
this.context.commit('update_user', resp.data);
resolve(resp)
}) })
.catch((err: Error) => { .catch((err: Error) => {
this.context.commit('update_error', err) reject(err);
reject(err) });
}) });
})
}
} }
}

50
web/src/views/Athlete.vue

@ -10,12 +10,12 @@
</div> </div>
<div class="level-right"> <div class="level-right">
<div class="level-item has-text-centered"> <div class="level-item has-text-centered">
<router-link :to="{ name: 'Table', params: { id: athlete._id }}" @click="saveAthlete(athlete)"> <router-link :to="{ name: 'Table', params: { id: athlete._id }}" @click="athlete_save(athlete)">
<span class="icon is-medium has-background-primary has-text-white mr-1"> <span class="icon is-medium has-background-primary has-text-white mr-1">
<i class="fa fa-lg fa-table"></i> <i class="fa fa-lg fa-table"></i>
</span> </span>
</router-link> </router-link>
<router-link :to="{ name: 'Chart', params: { id: athlete._id }}" @click="saveAthlete(athlete)"> <router-link :to="{ name: 'Chart', params: { id: athlete._id }}" @click="athlete_save(athlete)">
<span class="icon is-medium has-background-primary has-text-white mr-1"> <span class="icon is-medium has-background-primary has-text-white mr-1">
<i class="fa fa-lg fa-chart-area"></i> <i class="fa fa-lg fa-chart-area"></i>
</span> </span>
@ -27,7 +27,7 @@
</div> </div>
<div class="tile is-ancestor"> <div class="tile is-ancestor">
<div class="tile is-6 is-vertical is-parent"> <div class="tile is-6 is-vertical is-parent">
<form @submit="update"> <form @submit="athlete_update">
<div class="tile is-child box"> <div class="tile is-child box">
<p class="title">Personal Details</p> <p class="title">Personal Details</p>
<div class="field"> <div class="field">
@ -87,7 +87,7 @@
</div> </div>
<div class="field"> <div class="field">
<p class="control"> <p class="control">
<button class="button is-medium is-rounded is-primary" @click="update('adopt')">Adopt</button> <button class="button is-medium is-rounded is-primary" @click="athlete_update('adopt')">Adopt</button>
</p> </p>
</div> </div>
</div> </div>
@ -117,31 +117,32 @@ import {AthleteInterface} from "@/store/modules/athletes";
import {UserInterface} from "@/store/modules/user"; import {UserInterface} from "@/store/modules/user";
export default class Athlete extends Vue { export default class Athlete extends Vue {
private athlete = <AthleteInterface>{} private athlete = <AthleteInterface>{};
private trainer = <UserInterface>{} private trainer = <UserInterface>{};
private trainerLogin = ''; private trainerLogin = '';
private msgError = '' private msgError = '';
private msgSuccess = '' private msgSuccess = '';
private clientID = '' private clientID = '';
mounted() { mounted() {
this.athlete = this.$store.getters.currentAthlete this.athlete = this.$store.getters.athlete_current;
if (this.athlete._trainer && (this.athlete._trainer != this.$store.getters.currentUser._id)) { if (this.athlete._trainer && (this.athlete._trainer != this.$store.getters.user_current._id)) {
this.$store.dispatch('specificUser', this.athlete._trainer) this.$store.dispatch('user_getOne', this.athlete._trainer)
.then((res: any) => this.trainer === res.data) .then((res: any) => this.trainer === res.data)
.catch((err: any) => this.msgError = err.response.data.errors.message || err.message || 'Something went wrong!') .catch((err: any) => this.msgError = err.response.data.errors.message || err.message ||
} else if (this.athlete._trainer === this.$store.getters.currentUser._id) { 'Something went wrong!');
this.trainer = this.$store.getters.currentUser } else if (this.athlete._trainer === this.$store.getters.user_current._id) {
this.trainer = this.$store.getters.user_current;
} }
if (this.trainer) { if (this.trainer) {
this.trainerLogin = new Date(this.trainer.lastLogin).toLocaleString() this.trainerLogin = new Date(this.trainer.lastLogin).toLocaleString();
this.$store.dispatch('saveTrainer', this.trainer) this.$store.dispatch('athlete_saveLocalTrainer', this.trainer);
} }
} }
private update(action: string) { private athlete_update(action: string) {
if (action === 'adopt' && this.clientID === '') { if (action === 'adopt' && this.clientID === '') {
this.msgError = 'Please give a valid athlete ID!'; this.msgError = 'Please give a valid athlete ID!';
return; return;
@ -152,16 +153,19 @@ export default class Athlete extends Vue {
return; return;
} }
const user = {_trainer: this.$store.getters.currentUser._id} if (action === 'adopt') {
Object.assign(this.athlete, user) Object.assign(this.athlete, {_trainer: this.$store.getters.user_current._id});
} else {
Object.assign(this.athlete, {_trainer: ''});
}
this.$store.dispatch('updateAthlete', this.athlete) this.$store.dispatch('athlete_update', this.athlete)
.then((res: any) => { .then((res: any) => {
this.msgSuccess = 'Athlete updated' this.msgSuccess = 'Athlete updated'
this.athlete = res.data; this.athlete = res.data;
}) })
.catch(() => this.msgError = this.$store.getters.getErrAthlete.response.data.errors.message || .catch(() => this.msgError = this.$store.getters.athlete_err.response.data.errors.message ||
'Something went wrong!') 'Something went wrong!');
} }
} }
</script> </script>

80
web/src/views/Athletes.vue

@ -4,29 +4,26 @@
<div class="notification is-link is-light"> <div class="notification is-link is-light">
Your adopted athletes are displayed on this table. Choose an athlete and view his details, data. Your adopted athletes are displayed on this table. Choose an athlete and view his details, data.
</div> </div>
<div class="section"> <div class="section">
<div class="table-container"> <div class="table-container">
<table <table class="table is-striped is-large is-hoverable is-fullwidth has-text-centered">
class="table
is-striped
is-large
is-hoverable
is-fullwidth
has-text-centered">
<thead> <thead>
<tr> <tr>
<th><span class="icon mr-1"><i class="fa fa-plug"></i></span> <th>
Athlete status <span class="icon mr-1"><i class="fa fa-plug"></i></span>Athlete status
</th> </th>
<th><span class="icon mr-1"><i class="fas fa-running"></i></span> <th>
Name <span class="icon mr-1"><i class="fas fa-running"></i></span>Name
</th> </th>
<th><span class="icon mr-1"><i class="fas fa-id-badge"></i></span> <th>
ID <span class="icon mr-1"><i class="fas fa-id-badge"></i></span>ID
</th> </th>
<th>Actions</th> <th>Actions</th>
</tr> </tr>
</thead> </thead>
<tr v-for="(athlete, index) in myAthletes" :key="index"> <tr v-for="(athlete, index) in myAthletes" :key="index">
<td v-if="athlete.name" class="is-family-monospace"> <td v-if="athlete.name" class="is-family-monospace">
<span v-if="athlete.socketID">Online</span> <span v-if="athlete.socketID">Online</span>
@ -39,47 +36,48 @@
<span>{{ athlete.id }}</span> <span>{{ athlete.id }}</span>
</td> </td>
<td v-if="athlete.name"> <td v-if="athlete.name">
<router-link :to="{ name: 'Table', params: { id: athlete._id }}" @click="saveAthlete(athlete)"> <router-link :to="{ name: 'Table', params: { id: athlete._id }}" @click="athlete_save(athlete)">
<span class="icon is-medium has-background-primary has-text-white mr-1"> <span class="icon is-medium has-background-primary has-text-white mr-1">
<i class="fa fa-lg fa-table"></i> <i class="fa fa-lg fa-table"></i>
</span> </span>
</router-link> </router-link>
<router-link :to="{ name: 'Chart', params: { id: athlete._id }}" @click="saveAthlete(athlete)"> <router-link :to="{ name: 'Chart', params: { id: athlete._id }}" @click="athlete_save(athlete)">
<span class="icon is-medium has-background-primary has-text-white mr-1"> <span class="icon is-medium has-background-primary has-text-white mr-1">
<i class="fa fa-lg fa-chart-area"></i> <i class="fa fa-lg fa-chart-area"></i>
</span> </span>
</router-link> </router-link>
<router-link :to="{ name: 'Athlete', params: { id: athlete._id }}" @click="saveAthlete(athlete)"> <router-link :to="{ name: 'Athlete', params: { id: athlete._id }}" @click="athlete_save(athlete)">
<span class="icon is-medium has-background-warning has-text-white mr-1"> <span class="icon is-medium has-background-warning has-text-white mr-1">
<i class="fa fa-lg fa-user-edit"></i> <i class="fa fa-lg fa-user-edit"></i>
</span> </span>
</router-link> </router-link>
<a @click="removeMyAthlete(athlete, index)"> <a @click="athlete_delete(athlete, index)">
<span class="icon is-medium has-background-danger has-text-white mr-1"> <span class="icon is-medium has-background-danger has-text-white mr-1">
<i class="fa fa-lg fa-user-times"></i> <i class="fa fa-lg fa-user-times"></i>
</span> </span>
</a> </a>
</td> </td>
</tr> </tr>
</table> </table>
</div> </div>
</div> </div>
<div class="section is-medium"> <div class="section is-medium">
<div class="container"> <div class="container">
<h3 class="title is-4">Search all athletes</h3> <h3 class="title is-4">Search all athletes</h3>
<p class="subtitle">All athletes are displayed on this table.</p> <p class="subtitle">All athletes are displayed on this table.</p>
<div class="control"> <div class="control">
<label>
<input class="input is-focused" placeholder="Search Athletes" type="text"> <input class="input is-focused" placeholder="Search Athletes" type="text">
</label>
</div> </div>
</div> </div>
<div class="table-container"> <div class="table-container">
<table <table
class="table class="table is-striped is-large is-hoverable is-fullwidth has-text-centered">
is-striped
is-large
is-hoverable
is-fullwidth
has-text-centered">
<thead> <thead>
<tr> <tr>
<th><span class="icon mr-1"><i class="fa fa-plug"></i></span> <th><span class="icon mr-1"><i class="fa fa-plug"></i></span>
@ -92,6 +90,7 @@
<th>Actions</th> <th>Actions</th>
</tr> </tr>
</thead> </thead>
<tr v-for="(athlete, index) in athletes" :key="index"> <tr v-for="(athlete, index) in athletes" :key="index">
<td class="is-family-monospace"> <td class="is-family-monospace">
<span v-if="athlete.socketID">Online</span> <span v-if="athlete.socketID">Online</span>
@ -107,23 +106,24 @@
<span class="icon mr-1"><i class="fa fa-times"></i></span> <span class="icon mr-1"><i class="fa fa-times"></i></span>
</td> </td>
<td> <td>
<router-link :to="{ name: 'Table', params: { id: athlete._id }}" @click="saveAthlete(athlete)"> <router-link :to="{ name: 'Table', params: { id: athlete._id }}" @click="athlete_save(athlete)">
<span class="icon is-medium has-background-primary has-text-white mr-1"> <span class="icon is-medium has-background-primary has-text-white mr-1">
<i class="fa fa-lg fa-table"></i> <i class="fa fa-lg fa-table"></i>
</span> </span>
</router-link> </router-link>
<router-link :to="{ name: 'Chart', params: { id: athlete._id }}" @click="saveAthlete(athlete)"> <router-link :to="{ name: 'Chart', params: { id: athlete._id }}" @click="athlete_save(athlete)">
<span class="icon is-medium has-background-primary has-text-white mr-1"> <span class="icon is-medium has-background-primary has-text-white mr-1">
<i class="fa fa-lg fa-chart-area"></i> <i class="fa fa-lg fa-chart-area"></i>
</span> </span>
</router-link> </router-link>
<router-link :to="{ name: 'Athlete', params: { id: athlete._id }}" @click="saveAthlete(athlete)"> <router-link :to="{ name: 'Athlete', params: { id: athlete._id }}" @click="athlete_save(athlete)">
<span class="icon is-medium has-background-warning has-text-white mr-1"> <span class="icon is-medium has-background-warning has-text-white mr-1">
<i class="fa fa-lg fa-user-edit"></i> <i class="fa fa-lg fa-user-edit"></i>
</span> </span>
</router-link> </router-link>
</td> </td>
</tr> </tr>
</table> </table>
</div> </div>
</div> </div>
@ -135,32 +135,32 @@ import {AthleteInterface} from "@/store/modules/athletes";
import {UserInterface} from "@/store/modules/user"; import {UserInterface} from "@/store/modules/user";
export default class Athletes extends Vue { export default class Athletes extends Vue {
private athletes = [<AthleteInterface>{}] private athletes = [<AthleteInterface>{}];
private myAthletes = [<AthleteInterface>{}] private myAthletes = [<AthleteInterface>{}];
private user = <UserInterface>{} private user = <UserInterface>{};
private msg = '' private msg = '';
mounted() { mounted() {
this.$store.dispatch('getAthletes') this.$store.dispatch('athlete_getAll')
.then((res: any) => { .then((res: any) => {
this.athletes = res.data; this.athletes = res.data;
this.user = this.$store.getters.currentUser this.user = this.$store.getters.user_current
for (const athlete of this.athletes) { for (const athlete of this.athletes) {
if (athlete._trainer === this.user._id) if (athlete._trainer === this.user._id)
this.myAthletes.push(athlete) this.myAthletes.push(athlete);
} }
}) })
.catch((err: any) => this.msg = err.response.data.errors.message || err.message || 'Something went wrong!') .catch((err: any) => this.msg = err.response.data.errors.message || err.message || 'Something went wrong!');
} }
private saveAthlete(athlete: AthleteInterface) { private athlete_save(athlete: AthleteInterface) {
this.$store.dispatch('saveAthlete', athlete) this.$store.dispatch('athlete_saveLocal', athlete);
} }
private removeMyAthlete(athlete: AthleteInterface, index: number) { private athlete_delete(athlete: AthleteInterface, index: number) {
athlete._trainer = undefined athlete._trainer = undefined;
this.$store.dispatch('updateAthlete', athlete) this.$store.dispatch('athlete_update', athlete)
.then(() => this.myAthletes.splice(index, 1)) .then(() => this.myAthletes.splice(index, 1));
} }
} }

2
web/src/views/Chart.vue

@ -11,7 +11,7 @@ export default class Chart extends Vue {
private athlete = <AthleteInterface>{} private athlete = <AthleteInterface>{}
mounted() { mounted() {
this.athlete = this.$store.getters.currentAthlete this.athlete = this.$store.getters.athlete_current
} }
} }
</script> </script>

18
web/src/views/Dashboard.vue

@ -13,6 +13,7 @@ import {io} from 'socket.io-client'
import Navbar from '@/components/Navbar.vue' import Navbar from '@/components/Navbar.vue'
import Sidebar from '@/components/Sidebar.vue' import Sidebar from '@/components/Sidebar.vue'
import Footer from '@/components/Footer.vue' import Footer from '@/components/Footer.vue'
import {AthleteData} from "@/store/modules/backend";
@Options({ @Options({
components: { components: {
@ -26,24 +27,29 @@ export default class Dashboard extends Vue {
private socket!: any; private socket!: any;
created() { created() {
this.io() this.io();
}
beforeUnmount() {
this.socket.close()
} }
private io() { private io() {
this.socket = io('/') this.socket = io('/');
this.socket.on('connect', () => { this.socket.on('connect', () => {
this.$store.commit("serverConnected", true); this.$store.commit("socket_connection", true);
}); });
this.socket.on('disconnect', (reason: string) => { this.socket.on('disconnect', (reason: string) => {
this.$store.commit("serverConnected", false); this.$store.commit("socket_connection", false);
if (reason === 'io server disconnect') this.socket.connect(); if (reason === 'io server disconnect') this.socket.connect();
}); });
this.socket.on('console', (data: {}) => { this.socket.on('console', (data: AthleteData) => {
}) this.$store.dispatch('server_saveLiveData', data);
});
} }
} }
</script> </script>

6
web/src/views/DashboardHome.vue

@ -25,7 +25,7 @@
<div class="tile is-parent is-vertical"> <div class="tile is-parent is-vertical">
<article class="tile is-child box"> <article class="tile is-child box">
<p class="title">System status</p> <p class="title">System status</p>
<p v-if="this.$store.getters.currentServerStatus" class="subtitle">All systems operational</p> <p v-if="this.$store.getters.server_status" class="subtitle">All systems operational</p>
<p v-else class="subtitle">Something does not seem right</p> <p v-else class="subtitle">Something does not seem right</p>
</article> </article>
<article class="tile is-child box"> <article class="tile is-child box">
@ -82,8 +82,8 @@ export default class DashboardHome extends Vue {
private date: string = ''; private date: string = '';
created() { created() {
this.user = this.$store.getters.currentUser this.user = this.$store.getters.user_current;
this.date = new Date(this.user.lastLogin).toLocaleString() this.date = new Date(this.user.lastLogin).toLocaleString();
} }
} }

21
web/src/views/Login.vue

@ -4,7 +4,7 @@
<div class="columns"> <div class="columns">
<div class="column is-4 is-offset-4"> <div class="column is-4 is-offset-4">
<h1 class="is-size-1">Login</h1> <h1 class="is-size-1">Login</h1>
<form @submit.prevent="login"> <form @submit.prevent="user_login">
<div class="field"> <div class="field">
<p class="control has-icons-left has-icons-right"> <p class="control has-icons-left has-icons-right">
<input v-model="username" class="input" placeholder="Username" type="text"> <input v-model="username" class="input" placeholder="Username" type="text">
@ -56,25 +56,22 @@ export default class Login extends Vue {
private password = ''; private password = '';
mounted() { mounted() {
this.getCurrentUser(); this.currentSession();
} }
private getCurrentUser() { private currentSession() {
this.$store.dispatch('getCurrentUser') this.$store.dispatch('user_currentSession')
.then((res: any) => this.$router.push({name: 'Dashboard', params: {username: res.data.username}})) .then((res: any) => this.$router.push({name: 'Dashboard', params: {username: res.data.username}}))
.catch(() => { .catch(() => {
this.$router.push('/login') });
})
} }
private login() { private user_login() {
let user = {username: this.username, password: this.password} this.$store.dispatch('user_login', {username: this.username, password: this.password})
this.$store.dispatch('login', user)
.then(() => this.$router.push({name: 'Dashboard', params: {username: this.username}})) .then(() => this.$router.push({name: 'Dashboard', params: {username: this.username}}))
.catch(() => { .catch(() => {
this.msg = this.$store.getters.getErrUser.response.data.errors.message || 'Something went wrong!' this.msg = this.$store.getters.user_err.response.data.errors.message || 'Something went wrong!'
}) });
} }
} }
</script> </script>

20
web/src/views/Profile.vue

@ -1,6 +1,6 @@
<template> <template>
<h1 class="title is-2">/profile</h1> <h1 class="title is-2">/profile</h1>
<form @submit.prevent="update"> <form @submit.prevent="user_update">
<div class="tile is-ancestor"> <div class="tile is-ancestor">
<div class="tile is-4 is-vertical is-parent"> <div class="tile is-4 is-vertical is-parent">
<div class="tile is-child box"> <div class="tile is-child box">
@ -94,22 +94,22 @@ export default class Profile extends Vue {
private msgError = ''; private msgError = '';
mounted() { mounted() {
this.user = this.$store.getters.currentUser this.user = this.$store.getters.user_current;
this.date = new Date(this.user.registered).toLocaleString() this.date = new Date(this.user.registered).toLocaleString();
} }
private update() { private user_update() {
if (this.newPassword != this.repeatNewPassword) { if (this.newPassword != this.repeatNewPassword) {
this.msgError = 'Passwords do not match!' this.msgError = 'Passwords do not match!';
return return;
} }
Object.assign(this.user, {password: this.currentPassword, newPassword: this.newPassword}) Object.assign(this.user, {password: this.currentPassword, newPassword: this.newPassword});
this.$store.dispatch('updateUser', this.user) this.$store.dispatch('user_update', this.user)
.then(() => this.msgSuccess = 'User updated!') .then(() => this.msgSuccess = 'User updated!')
.catch(() => this.msgError = this.$store.getters.getErrUser.response.data.errors.message || .catch(() => this.msgError = this.$store.getters.user_err.response.data.errors.message ||
'Something went wrong!') 'Something went wrong!');
} }
} }

32
web/src/views/Table.vue

@ -1,17 +1,45 @@
<template> <template>
<h1 class="title is-2">/athletes/{{ athlete.name }}/table</h1> <h1 class="title is-2">/athletes/{{ athlete.name }}/table</h1>
<div class="table-container">
<table class="table is-narrow is-striped">
<thead>
<tr>
<th v-for="(value, key) in mData[0]">
{{ key }}
</th>
</tr>
</thead>
<tbody>
<tr v-for="(data, key) in mData" :key="key">
<td v-for="(value, key) in data">
{{ value }}
</td>
</tr>
</tbody>
</table>
</div>
</template> </template>
<script lang="ts"> <script lang="ts">
import {Vue} from 'vue-class-component'; import {Vue} from 'vue-class-component';
import {AthleteInterface} from "@/store/modules/athletes"; import {AthleteInterface} from "@/store/modules/athletes";
import {AthleteData} from "@/store/modules/backend";
export default class Table extends Vue { export default class Table extends Vue {
private athlete = <AthleteInterface>{} private athlete = <AthleteInterface>{};
private mData = [<AthleteData>{}];
mounted() { mounted() {
this.athlete = this.$store.getters.currentAthlete this.athlete = this.$store.getters.athlete_current;
this.mData = this.$store.getters.server_liveData;
}
athlete_storedData() {
this.$store.dispatch('server_getOne', this.athlete._id)
.then((res: any) => console.log(res));
} }
} }
</script> </script>

Loading…
Cancel
Save