Skip to content

Commit

Permalink
feat: scaffold exercise history with chart (#180)
Browse files Browse the repository at this point in the history
  • Loading branch information
wajeht authored Aug 19, 2022
1 parent 89e4686 commit 3db3349
Show file tree
Hide file tree
Showing 13 changed files with 467 additions and 89 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"release:alpha": "npm run release -- --prerelease alpha",
"rmds": "find . -name '.DS_Store' -delete",
"prepare": "husky install",
"commit": "cz"
"commit": "git add -A && cz"
},
"bin": {
"gains": "./src/bin/gains.js"
Expand Down
20 changes: 19 additions & 1 deletion src/apps/api/v1/exercises/exercises.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,24 @@ import * as ExercisesQueries from './exercises.queries.js';
import * as ExerciseCategoriesQueries from '../exercise-categories/exercise-categories.queries.js';
import { omit } from 'lodash-es';

/**
* It gets the exercise history for a given exercise id
* @param req - The request object.
* @param res - The response object.
* @returns The exercise history for a specific exercise.
*/
export async function getExerciseHistory(req, res) {
const exercise_id = req.params.exercise_id;
const exercise = await ExercisesQueries.getExerciseHistoryByExerciseId(exercise_id);

return res.status(StatusCodes.OK).json({
status: 'success',
request_url: req.originalUrl,
message: 'The resource was returned successfully!',
data: exercise,
});
}

/**
* It gets an exercise by its id
* @param req - The request object.
Expand All @@ -18,7 +36,7 @@ export async function getExercise(req, res) {

const exercise = await ExercisesQueries.getExerciseById(eid);

if (!exercise.length) throw new CustomError.BadRequestError(`There are no exercise available for exercise id ${eid}!`); // prettier-ignore
// if (!exercise.length) throw new CustomError.BadRequestError(`There are no exercise available for exercise id ${eid}!`); // prettier-ignore

return res.status(StatusCodes.OK).json({
status: 'success',
Expand Down
37 changes: 37 additions & 0 deletions src/apps/api/v1/exercises/exercises.queries.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,43 @@ export function getExerciseById(id) {
return db.select('*').from('exercises').where({ id }).andWhere({ deleted: false });
}

/**
* Get all the sets for a given exercise, ordered by the date they were created.
* @param id - the id of the exercise you want to get the history for
* @returns An array of objects
*/
export async function getExerciseHistoryByExerciseId(id) {
const { rows } = await db.raw(
`
select
s.reps,
s.weight,
s.rpe as "rpe",
s.notes as "notes",
s.created_at as "created_at",
e."name" as "exercise_name",
ec."name" as "category_name",
e.id as "exercise_id",
ec.id as "category_id",
s.id as "set_id",
s.session_id as "session_id",
s.log_id as "log_id",
e.user_id as "user_id"
from
exercises e
inner join sets s on s.exercise_id = e.id
inner join exercise_categories ec on ec.id = e.exercise_category_id
where
e.deleted = false
and e.id = ?
order by
s.created_at desc
`,
[id],
);
return rows;
}

/**
* Get all exercises from the database where the user_id matches the uid passed in and where the
* deleted column is false.
Expand Down
12 changes: 12 additions & 0 deletions src/apps/api/v1/exercises/exercises.router.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,18 @@ exercises.get(
catchAsyncErrors(ExercisesController.getExercise),
);

/**
* GET /api/v1/exercises/{exercise_id}/history
* @tags exercises
* @summary get history of a exercises
* @param {number} exercise_id.path.required - the exercise id - application/x-www-form-urlencoded
*/
exercises.get(
'/:exercise_id/history',
validator(ExercisesValidation.getExerciseHistory),
catchAsyncErrors(ExercisesController.getExerciseHistory),
);

/**
* POST /api/v1/exercises
* @tags exercises
Expand Down
27 changes: 26 additions & 1 deletion src/apps/api/v1/exercises/exercises.validation.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ export const getExercise = [
.isNumeric()
.withMessage('exercise id must be an number!')
.bail()
.toInt()
.custom(async (eid) => {
const exercise = await ExercisesQueries.getExerciseById(eid);
if (exercise.length === 0) throw new Error('exercise does not exist!');
return true;
})
.toInt(),
];

Expand Down Expand Up @@ -47,7 +53,8 @@ export const getExercises = [
const user = await ExerciseCategoriesQueries.getExerciseCategoriesById(ecid);
if (user.length === 0) throw new Error('category_id does not exist!');
return true;
}),
})
.toInt(),
];

export const postExercise = [
Expand Down Expand Up @@ -147,3 +154,21 @@ export const patchExerciseNote = [
return true;
}),
];

export const getExerciseHistory = [
param('exercise_id')
.trim()
.notEmpty()
.withMessage('exercise id must not be empty!')
.bail()
.isNumeric()
.withMessage('exercise id must be an number!')
.bail()
.toInt()
.custom(async (exercise_id) => {
const exercise = await ExercisesQueries.getExerciseById(exercise_id);
if (exercise.length === 0) throw new Error('exercise does not exist!');
return true;
})
.toInt(),
];
18 changes: 15 additions & 3 deletions src/apps/ui/App.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
<template>
<component :is="layout"
:class="{ 'dashboard-layout-style': layout === 'DashboardLayout' || layout === 'EmptyDashboardLayout' }" />
<component
:is="layout"
:class="{
'dashboard-layout-style': layout === 'DashboardLayout' || layout === 'EmptyDashboardLayout',
}"
/>
</template>

<script>
Expand All @@ -25,7 +29,7 @@ export default {
if (to.meta.layout === 'DashboardLayout' || to.meta.layout === 'EmptyDashboardLayout') {
document.body.style.backgroundColor = 'black';
} else {
document.body.style.backgroundColor = ''
document.body.style.backgroundColor = '';
}
// set layout by route meta
Expand All @@ -40,6 +44,14 @@ export default {
</script>

<style>
.btn-group-xs > .btn,
.btn-xs {
padding: 0.25rem 0.4rem;
font-size: 0.875rem;
line-height: 0.5;
border-radius: 0.2rem;
}
.dashboard-layout-style {
max-width: 540px;
margin: 0 auto;
Expand Down
81 changes: 48 additions & 33 deletions src/apps/ui/components/dashboard/SessionDetails.vue
Original file line number Diff line number Diff line change
Expand Up @@ -1026,56 +1026,64 @@ function clearAndDismissDeleteALogModal() {
<!-- block -->
<span v-if="currentSessionDetails.block_name">
<i class="bi bi-clipboard2-data-fill me-1"></i>Block:
<span class="fw-light">{{ currentSessionDetails.block_name }}</span>
<router-link
:to="`/dashboard/blocks/${currentSessionDetails.block_id}`"
class="fw-light fst-italic link-dark"
>{{ currentSessionDetails.block_name }}</router-link
>
</span>
</small>
</div>
</div>
</div>
<!-- footer -->
<small class="card-footer text-muted d-flex justify-content-between align-items-center">
<!-- date -->
<!-- left -->
<small>
<font-awesome-icon icon="fa-calendar " class="me-1" /><span class="fw-light">{{
gainsDateDisplay(currentSessionDetails.created_at)
}}</span>
</small>
<!-- right -->
<span class="d-flex justify-content-between align-items-center gap-2">
<!-- incomplete or progress -->
<small
v-if="!currentSessionDetails.end_date"
class="fst-italic d-flex align-items-center"
>
<!-- danger -->
<!-- prettier-ignore -->
<div class="card-footer">
<span class="d-flex justify-content-between text-muted">
<!-- left -->
<span class="d-flex justify-content-between align-items-center gap-2">
<!-- date -->
<small>
<i class="bi bi-calendar-check me-1"></i
>{{ dayjs(currentSessionDetails.created_at).format('YYYY/MM/DD') }}
</small>
</span>
<!-- right -->
<span class="d-flex justify-content-between align-items-center gap-2">
<!-- incomplete or progress -->
<span
v-if="!currentSessionDetails.end_date"
class="fst-italic d-flex align-items-center"
>
<!-- danger -->
<!-- prettier-ignore -->
<small
v-if="currentSessionDetails.end_date === null && dayjs(currentSessionDetails.start_date).format('YYYY/MM/DD') === today"
class="text-warning">
<font-awesome-icon icon="fa-refresh" class="me-1" /> in progress
</span>
</small>
<!-- danger -->
<!-- prettier-ignore -->
<span
<!-- danger -->
<!-- prettier-ignore -->
<small
v-if="currentSessionDetails.end_date === null && dayjs(currentSessionDetails.start_date).format('YYYY/MM/DD') < today"
class="text-danger">
<i class="bi bi-exclamation-triangle-fill text-danger"></i> incomplete
</span>
</small>
</span>
<!-- videos view -->
<router-link
class="fw-light link-secondary text-decoration-none"
:to="`/dashboard/videos/${currentSessionDetails.id}`"
>
<small> <i class="bi bi-play-circle-fill"></i> Video view </small>
</router-link>
<!-- videos view -->
<small>
<router-link
class="link-secondary text-decoration-none"
:to="`/dashboard/videos/${currentSessionDetails.id}`"
><i class="bi bi-play-circle-fill me-1"></i>Video view
</router-link>
</small>
</span>
</span>
</small>
</div>
</div>
<!-- exercise logs -->
Expand Down Expand Up @@ -1383,10 +1391,17 @@ function clearAndDismissDeleteALogModal() {
<!-- right -->
<span class="d-flex justify-content-between gap-2">
<!-- chart -->
<button class="btn btn-sm btn-outline-dark" type="button" disabled>
<i class="bi bi-bar-chart"></i>
</button>
<button class="btn btn-sm btn-outline-dark" type="button" disabled>
<!-- history -->
<button
@click="router.push(`/dashboard/exercises/${log.exercise_id}`)"
class="btn btn-sm btn-outline-dark"
type="button"
>
<i class="bi bi-journal-text"></i>
</button>
</span>
Expand Down
49 changes: 27 additions & 22 deletions src/apps/ui/components/dashboard/VideoDetails.vue
Original file line number Diff line number Diff line change
Expand Up @@ -294,38 +294,43 @@ async function postAComment() {

<!-- footer -->
<div class="card-footer">
<small class="d-flex justify-content-between text-muted">
<span class="d-flex justify-content-between text-muted">
<!-- left -->
<span class="d-flex gap-3">
<!-- block -->
<span v-if="currentSessionDetails.block_name">
<i class="bi bi-clipboard2-data me-1"></i>Block:
<span class="fw-light">{{ currentSessionDetails.block_name }}</span>
</span>

<span class="d-flex align-items-center gap-2">
<!-- date -->
<span><i class="bi bi-calendar-check me-1"></i> 2020-01-01</span>
<small
><i class="bi bi-calendar-check me-1"></i
>{{ dayjs(currentSessionDetails.created_at).format('YYYY/MM/DD') }}</small
>

<!-- block -->
<small v-if="currentSessionDetails.block_name">
<router-link
:to="`/dashboard/blocks/${currentSessionDetails.block_id}`"
class="link-secondary text-decoration-none"
>
<i class="bi bi-journal-text me-1"></i>{{ currentSessionDetails.block_name }}
</router-link>
</small>
</span>

<!-- right -->
<div class="d-flex gap-2">
<div class="d-flex align-items-center gap-2">
<!-- session -->
<router-link
v-if="userStore.user.id === currentSessionDetails.user_id"
class="link-secondary text-decoration-none"
:to="`/dashboard/sessions/${currentSessionDetails.id}`"
><i class="bi bi-journal-text me-1"> </i>
<span>
<small>
<router-link
v-if="userStore.user.id === currentSessionDetails.user_id"
class="link-secondary text-decoration-none"
:to="`/dashboard/sessions/${currentSessionDetails.id}`"
><i class="bi bi-journal-text"></i>
{{ currentSessionDetails.id }}
</span>
</router-link>
</router-link>
</small>

<!-- comment -->
<span
><i class="bi bi-chat me-1"></i><span>{{ comments.length || 0 }}</span></span
>
<small><i class="bi bi-chat me-1"></i>{{ comments.length || 0 }}</small>
</div>
</small>
</span>
</div>
</div>

Expand Down
2 changes: 1 addition & 1 deletion src/apps/ui/components/shared/Signup.vue
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
and our
<a
href="#"
class="btn btn-sm p-0 m-0"
class="btn btn-xs p-0 m-0"
style="text-decoration: underline"
:class="{ disabled: loading === true }"
@click="$router.push('/privacy')"
Expand Down
20 changes: 20 additions & 0 deletions src/apps/ui/pages/dashboard/Block.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<script setup>
import Backheader from '../../components/dashboard/headers/Backheader.vue';
</script>

<template>
<!-- header -->
<Backheader />

<div class="container px-3 animate__animated animate__fadeIn animate__faster">
<div class="my-3 d-flex flex-column gap-3">
<div class="card">
<div class="card-body">
<h5 class="card-title">Block</h5>
</div>
</div>
</div>
</div>
</template>

<style scoped></style>
Loading

0 comments on commit 3db3349

Please sign in to comment.