Haris Razis
4 years ago
9 changed files with 345 additions and 16 deletions
@ -0,0 +1,90 @@ |
|||||
|
import {Action, Module, Mutation, VuexModule} from 'vuex-module-decorators' |
||||
|
import axios, {AxiosResponse} from "axios"; |
||||
|
import qs from 'qs'; |
||||
|
|
||||
|
import {UserInterface} from "@/store/modules/user"; |
||||
|
|
||||
|
export interface AthleteInterface { |
||||
|
_id: string, |
||||
|
id: string, |
||||
|
socketID: string, |
||||
|
name: string, |
||||
|
_trainer: UserInterface |
||||
|
} |
||||
|
|
||||
|
@Module |
||||
|
export default class Athletes extends VuexModule { |
||||
|
private athlete = <AthleteInterface>{}; |
||||
|
private trainer = <UserInterface>{}; |
||||
|
private athletes = [<AthleteInterface>{}]; |
||||
|
|
||||
|
get currentAthlete() { |
||||
|
return this.athlete; |
||||
|
} |
||||
|
|
||||
|
get currentTrainer() { |
||||
|
return this.trainer; |
||||
|
} |
||||
|
|
||||
|
get currentAthletes() { |
||||
|
return this.athletes; |
||||
|
} |
||||
|
|
||||
|
@Mutation |
||||
|
private save_athlete(athlete: AthleteInterface) { |
||||
|
this.athlete = athlete; |
||||
|
} |
||||
|
|
||||
|
@Mutation save_trainer(trainer: UserInterface) { |
||||
|
this.trainer = trainer; |
||||
|
} |
||||
|
|
||||
|
@Mutation |
||||
|
private api_athletes(athletes: [AthleteInterface]) { |
||||
|
this.athletes = athletes; |
||||
|
} |
||||
|
|
||||
|
@Action |
||||
|
private getAthletes() { |
||||
|
return new Promise((resolve, reject) => { |
||||
|
axios({ |
||||
|
method: 'GET', |
||||
|
url: '/api/athletes' |
||||
|
}) |
||||
|
.then((resp: AxiosResponse) => { |
||||
|
this.context.commit('api_athletes', resp.data) |
||||
|
resolve(resp) |
||||
|
}) |
||||
|
.catch((err: Error) => { |
||||
|
reject(err) |
||||
|
}) |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
@Action |
||||
|
private updateAthlete(athlete: AthleteInterface) { |
||||
|
return new Promise((resolve, reject) => { |
||||
|
axios({ |
||||
|
method: 'PUT', |
||||
|
url: `/api/athletes/${athlete._id}`, |
||||
|
data: qs.stringify({...athlete}) |
||||
|
}) |
||||
|
.then((resp: AxiosResponse) => { |
||||
|
this.context.commit('save_athlete', resp.data) |
||||
|
}) |
||||
|
.catch((err: Error) => { |
||||
|
reject(err) |
||||
|
}) |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
@Action |
||||
|
private saveTrainer(trainer: UserInterface) { |
||||
|
this.context.commit('save_trainer', trainer) |
||||
|
} |
||||
|
|
||||
|
@Action |
||||
|
private saveAthlete(athlete: AthleteInterface) { |
||||
|
this.context.commit('save_athlete', athlete) |
||||
|
} |
||||
|
} |
@ -0,0 +1,125 @@ |
|||||
|
<template> |
||||
|
<h1 class="title is-2">Athletes/{{ athlete.name }}</h1> |
||||
|
<div class="tile is-ancestor"> |
||||
|
<div class="tile is-6 is-vertical is-parent"> |
||||
|
<form @submit="update"> |
||||
|
<div class="tile is-child box"> |
||||
|
<p class="title">Personal Details</p> |
||||
|
<div class="field"> |
||||
|
<label class="label">Name</label> |
||||
|
<div class="control"> |
||||
|
<input class="input" type="text" v-model="athlete.name"> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="field"> |
||||
|
<label class="label">ID</label> |
||||
|
<p>{{ athlete.id }}</p> |
||||
|
</div> |
||||
|
<div class="field"> |
||||
|
<label class="label">Client Status</label> |
||||
|
<p v-if="athlete.socketID">Online</p> |
||||
|
<p v-else>Offline</p> |
||||
|
</div> |
||||
|
<div class="notification is-danger has-text-centered mt-5" v-if="msgError"> |
||||
|
<b>{{ msgError }}</b> |
||||
|
</div> |
||||
|
<div class="notification is-success has-text-centered mt-5" v-else-if="msgSuccess"> |
||||
|
<b>{{ msgSuccess }}</b> |
||||
|
</div> |
||||
|
<div class="notification is-info is-light mt-5" v-else> |
||||
|
<ul> |
||||
|
<li>Client name is randomly generated on device connection. Change to athlete's name, so to be easily |
||||
|
identified. |
||||
|
</li> |
||||
|
<li>The ID is the mac of the client. It is persistent in the database and cannot change.</li> |
||||
|
<li>If the client has established a socket connection with the server he is considered online. In any |
||||
|
other case he is considered offline. |
||||
|
</li> |
||||
|
</ul> |
||||
|
</div> |
||||
|
<div class="field"> |
||||
|
<p class="control"> |
||||
|
<button class="button is-primary is-rounded" type="submit"> |
||||
|
Update |
||||
|
</button> |
||||
|
</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
</form> |
||||
|
</div> |
||||
|
<div class="tile is-parent"> |
||||
|
<div class="tile is-child box"> |
||||
|
<p class="title">Trainer Status</p> |
||||
|
<div class="notification is-warning is-light mt-5" v-if="!athlete._trainer"> |
||||
|
<ul> |
||||
|
<p>It seems that this athlete has no trainer attached to him!</p> |
||||
|
<p>By adopting an athlete you can edit his personal details and view his performance stats.</p> |
||||
|
</ul> |
||||
|
<button class="button is-large is-rounded is-primary is-light" @click="update">update</button> |
||||
|
</div> |
||||
|
<div v-else> |
||||
|
<div class="field"> |
||||
|
<label class="label">Username</label> |
||||
|
<p>{{ trainer.username }}</p> |
||||
|
</div> |
||||
|
<div class="field"> |
||||
|
<label class="label">Email</label> |
||||
|
<p v-if="trainer.email">{{ trainer.email }}</p> |
||||
|
<p v-else>-</p> |
||||
|
</div> |
||||
|
<div class="field"> |
||||
|
<label class="label">Last login</label> |
||||
|
<p>{{ trainerLogin }}</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script lang="ts"> |
||||
|
import {Vue} from "vue-class-component"; |
||||
|
import {AthleteInterface} from "@/store/modules/athletes"; |
||||
|
import {UserInterface} from "@/store/modules/user"; |
||||
|
|
||||
|
export default class Athlete extends Vue { |
||||
|
private athlete = <AthleteInterface>{} |
||||
|
private trainer = <UserInterface>{} |
||||
|
private trainerLogin = ''; |
||||
|
private msgError = '' |
||||
|
private msgSuccess = '' |
||||
|
|
||||
|
mounted() { |
||||
|
this.athlete = this.$store.getters.currentAthlete |
||||
|
|
||||
|
if (this.athlete._trainer && (this.athlete._trainer != this.$store.getters.currentUser._id)) { |
||||
|
this.$store.dispatch('specificUser', this.athlete._trainer) |
||||
|
.then((res: any) => this.trainer === res.data) |
||||
|
.catch((err: any) => this.msgError = err.response.data.errors.message || err.message || 'Something went wrong!') |
||||
|
} else if (this.athlete._trainer === this.$store.getters.currentUser._id) { |
||||
|
this.trainer = this.$store.getters.currentUser |
||||
|
} |
||||
|
|
||||
|
if (this.trainer) { |
||||
|
this.trainerLogin = new Date(this.trainer.lastLogin).toLocaleString() |
||||
|
this.$store.dispatch('saveTrainer', this.trainer) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private update() { |
||||
|
const user = {_trainer: this.$store.getters.currentUser._id} |
||||
|
Object.assign(this.athlete, user) |
||||
|
this.$store.dispatch('updateAthlete', this.athlete) |
||||
|
.then((res: any) => { |
||||
|
console.log('updated') |
||||
|
this.msgSuccess = 'Athlete updated' |
||||
|
this.athlete = res.data; |
||||
|
}) |
||||
|
.catch((err: any) => this.msgError = err.response.data.errors.message || err.message || 'Something went wrong!') |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
|
||||
|
</style> |
@ -0,0 +1,75 @@ |
|||||
|
<template> |
||||
|
<h1 class="title is-2">Athletes</h1> |
||||
|
<div class="tile"> |
||||
|
<table |
||||
|
class="table |
||||
|
is-striped |
||||
|
is-large |
||||
|
is-hoverable |
||||
|
is-fullwidth |
||||
|
has-text-left" |
||||
|
> |
||||
|
<thead> |
||||
|
<tr> |
||||
|
<th>Athlete id</th> |
||||
|
<th>Name</th> |
||||
|
<th>Trainer</th> |
||||
|
<th>Actions</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tr v-for="(athlete, index) in athletes" :key="index"> |
||||
|
<td class="is-family-monospace"> |
||||
|
<span class="icon-text"> |
||||
|
<span class="icon mr-1"><i class="fa fa-id-card"></i></span> |
||||
|
<span>{{ athlete.id }}</span> |
||||
|
</span> |
||||
|
</td> |
||||
|
<td> |
||||
|
<span class="icon-text"> |
||||
|
<span class="icon mr-1"><i class="fa fa-signature"></i></span> |
||||
|
<span>{{ athlete.name }}</span> |
||||
|
</span> |
||||
|
</td> |
||||
|
<td v-if="athlete._trainer"> |
||||
|
<span class="icon mr-1"><i class="fa fa-check"></i></span> |
||||
|
</td> |
||||
|
<td v-else> |
||||
|
<span class="icon mr-1"><i class="fa fa-times"></i></span> |
||||
|
</td> |
||||
|
<td> |
||||
|
<router-link :to="{ name: 'Athlete', params: { id: athlete._id }}" @click="saveAthlete(athlete)"> |
||||
|
<span class="icon has-text-primary-dark"> |
||||
|
<i class="fa fa-2x fa-user-edit"></i> |
||||
|
</span> |
||||
|
</router-link> |
||||
|
</td> |
||||
|
</tr> |
||||
|
</table> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script lang="ts"> |
||||
|
import {Vue} from "vue-class-component"; |
||||
|
import {AthleteInterface} from "@/store/modules/athletes"; |
||||
|
import {UserInterface} from "@/store/modules/user"; |
||||
|
|
||||
|
export default class Athletes extends Vue { |
||||
|
private athletes = [<AthleteInterface>{}] |
||||
|
private msg = '' |
||||
|
|
||||
|
mounted() { |
||||
|
this.$store.dispatch('getAthletes') |
||||
|
.then((res: any) => this.athletes = res.data) |
||||
|
.catch((err: any) => this.msg = err.response.data.errors.message || err.message || 'Something went wrong!') |
||||
|
} |
||||
|
|
||||
|
private saveAthlete(athlete: AthleteInterface) { |
||||
|
this.$store.dispatch('saveAthlete', athlete) |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
|
||||
|
</style> |
Loading…
Reference in new issue