Răsfoiți Sursa

Adding functionality to the sessions page.

Lee Morgan 1 an în urmă
părinte
comite
ef0ca38560

+ 11 - 3
controllers/session.js

@@ -1,6 +1,10 @@
 import Session from "../models/Session.js";
 import Workout from "../models/Workout.js";
 
+import mongoose from "mongoose";
+
+const ObjectId = mongoose.Types.ObjectId;
+
 const createRoute = async (req, res, next)=>{
     try{
         const session = createSession(req.body);
@@ -11,10 +15,14 @@ const createRoute = async (req, res, next)=>{
 
 const getRoute = async (req, res, next)=>{
     try{
-        const [workout, sessions] = Promise.all(
+        const [workout, sessions] = await Promise.all([
             Workout.findOne({_id: req.params.workoutId}),
-            Session.find({workout: req.params.workoutId}).limit(5)
-        );
+            Session.aggregate([
+                {$match: {workout: new ObjectId(req.params.workoutId)}},
+                {$sort: {start: -1}},
+                {$limit: 5}
+            ])
+        ]);
         confirmWorkoutOwnership(workout, res.locals.user);
         res.json(sessions.map(s => responseSession(s)));
     }catch(e){next(e)}

+ 1 - 1
controllers/workout.js

@@ -11,7 +11,7 @@ const createRoute = async (req, res, next)=>{
 const getRoute = async (req, res, next)=>{
     try{
         const workouts = await Workout.find({user: res.locals.user._id});
-        res.json(workouts);
+        res.json(workouts.map(w => responseWorkout(w)));
     }catch(e){next(e)}
 }
 

+ 1 - 1
routes/session.js

@@ -7,5 +7,5 @@ import {userAuth} from "../auth.js";
 
 export default (app)=>{
     app.post("/session", userAuth, createRoute);
-    app.get("/session/:workoutId", userAuth, createRoute);
+    app.get("/session/:workoutId", userAuth, getRoute);
 }

+ 52 - 0
views/css/session.css

@@ -0,0 +1,52 @@
+#sessionPage{
+    flex-direction: column;
+    justify-content: flex-start;
+    padding-top: 75px;
+    overflow-y: auto;
+}
+
+#previousSession{
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+    height: 10%;
+    width: 100%;
+    border: 1px solid var(--primary);
+    border-radius: 25px;
+    margin-bottom: 15px;
+}
+
+#noSessionText{
+    color: white;
+    font-size: 18px;
+}
+
+#sessionPage h1{
+    text-align: center;
+    text-decoration: underline;
+    margin-bottom: 15px;
+}
+
+.weightSet{
+    padding: 10px 5px;
+    border: 1px solid var(--accent);
+    border-radius: 25px;
+    margin: 15px 0;
+}
+
+.weightSet h3{
+    margin-bottom: 15px;
+}
+
+.weightSet label{
+    display: flex;
+    flex-direction: column;
+    margin-bottom: 10px;
+}
+
+.weightSet input{
+    font-size: 22px;
+    padding: 5px;
+    color: var(--gray);
+}

+ 5 - 2
views/index.css

@@ -2,6 +2,7 @@
 @import "./css/login.css";
 @import "./css/home.css";
 @import "./css/newWorkout.css";
+@import "./css/session.css";
 
 :root{
     --primary: #d7263d;
@@ -103,12 +104,14 @@
 }
 
 .button{
-    background: none;
+    background: linear-gradient(var(--dark), var(--dark)) padding-box,
+                linear-gradient(to right, var(--accent), var(--primary), var(--accent)) border-box;
     border-radius: 15px;
-    border: 2px solid var(--accent);
+    border: 2px solid transparent;
     padding: 5px 25px;
     font-size: 22px;
     cursor: pointer;
+    position: relative;
 }
 
 .button:active{

+ 30 - 3
views/index.html

@@ -8,8 +8,15 @@
     <link rel="icon" href="/logo.svg" type="image/svg+xml">
 </head>
 <body>
-    <svg class="logo" width="90" height="60" viewBox="10 20 80 50">
-      <path d="M10,40 Q25,20 50,30 Q75,40 90,30 Q75,50 50,60 Q25,70 10,60 Q25,50 10,40" fill="#D7263D">
+    <svg class="logo" width="90" height="60" viewBox="10 20 80 50" xmlns="http://www.w3.org/2000/svg">
+      <defs>
+        <linearGradient id="logoGradient" x1="0%" y1="0%" x2="100%" y2="0%">
+        <stop offset="0%" stop-color="#e57600" />
+          <stop offset="10%" stop-color="#f46036" />
+          <stop offset="100%" stop-color="#d7263d" />
+        </linearGradient>
+      </defs>
+      <path d="M10,40 Q25,20 50,30 Q75,40 90,30 Q75,50 50,60 Q25,70 10,60 Q25,50 10,40" fill="url(#logoGradient)" />
     </svg>
 
     <p id="notifier" style="display:none"></p>
@@ -114,7 +121,27 @@
         <button id="newWorkoutFinish" class="button">Create Workout</button>
     </div>
 
-    <div id="sessionPage" class="page"></div>
+    <div id="sessionPage" class="page">
+        <div id="previousSession"></div>
+
+        <h1 id="sessionExerciseName"></h3>
+
+        <div id="sessionSets"></div>
+
+        <button id="nextSessionBtn" class="button">Next</button>
+
+        <template id="weightSet">
+            <div class="weightSet">
+                <h3></h3>
+                <label>Weight
+                    <input class="weightSetWeight" type="number" step="1">
+                </label>
+                <label>Reps
+                    <input class="weightSetReps" type="number" step="1">
+                </label>
+            </div>
+        </template>
+    </div>
 
     <script src="/index.js"></script>
 </body>

+ 87 - 3
views/js/pages/session.js

@@ -1,5 +1,89 @@
-export default {
-    render: function(workout){
-        console.log("rendering");
+export default{
+    workout: null,
+    pastSessions: null,
+    exerciseIndex: 0,
+    currentSession: null,
+
+    render: async function(workout){
+        this.workout = workout;
+        this.pastSessions = await this.getPastSessions(workout.id);
+        this.createNewSession(workout);
+        this.changeExercise(0);
+    },
+
+    getPastSessions: async function(id){
+        const sessions = await fetch(`/session/${id}`, {
+            method: "GET",
+            headers: {
+                "Content-Type": "application/json"
+            }
+        });
+
+        if(sessions.error){
+            notify("error", "ERROR: Unable to retrieve past workouts");
+            return [];
+        }
+
+        return await sessions.json();
+    },
+
+    createNewSession: function(workout){
+        this.currentSession = {
+            workout: workout.id,
+            start: new Date(),
+            notes: "",
+            exercises: []
+        };
+
+        localStorage.setItem(workout.id, JSON.stringify(this.currentSession));
+    },
+
+    changeExercise: function(num){
+        this.exerciseIndex += num;
+        let exercise = null;
+        if(this.currentSession[this.exerciseIndex]){
+            exercise = currentSession[this.exerciseIndex];
+        }else{
+            const workoutExercise = this.workout.exercises[this.exerciseIndex];
+            exercise = {
+                exerciseId: workoutExercise._id,
+                name: workoutExercise.name,
+                type: workoutExercise.type,
+                notes: "",
+                sets: this.getPastSets(workoutExercise._id)
+            }
+            this.currentSession.exercises.push(exercise);
+        }
+
+        document.getElementById("sessionExerciseName").textContent = exercise.name;
+
+        switch(exercise.type){
+            case "weights": this.displayWeightSets(exercise);
+        }
+    },
+
+    displayWeightSets: function(exercise){
+        const container = document.getElementById("sessionSets");
+        const weightTemplate = document.getElementById("weightSet").content.children[0];
+
+        for(let i = 0; i < exercise.sets.length; i++){
+            const set = weightTemplate.cloneNode(true);
+            set.querySelector("h3").textContent = `Set #${i+1}`;
+            set.querySelector(".weightSetWeight").value = exercise.sets[i].weight;
+            set.querySelector(".weightSetReps").value = exercise.sets[i].reps;
+            container.appendChild(set);
+        }
+    },
+
+    getPastSets: function(id){
+        for(let i = 0; i < this.pastSessions.length; i++){
+            for(let j = 0; j < this.pastSessions[i].exercises.length; j++){
+                if(this.pastSessions[i].exercises[j].exerciseId === id){
+                    return this.pastSessions[i].exercises[j].sets;
+                }
+            }
+        }
+
+        return [{weight: 0, reps: 0}, {weight: 0, reps: 0}, {weight: 0, reps: 0}];
     }
 }

+ 89 - 0
views/js/pages/session2.js

@@ -0,0 +1,89 @@
+export default {
+    workout: null,
+    exerciseIndex: 0,
+    pastSessions: null,
+    previousExercise: null,
+
+    render: async function(workout){
+        this.workout = workout;
+        this.pastSessions = await this.getPastSessions(workout.id);
+        this.switchExercise(0);
+    },
+
+    getPastSessions: async function(id){
+        const sessions = await fetch(`/session/${id}`, {
+            method: "GET",
+            headers: {
+                "Content-Type": "application/json"
+            }
+        });
+
+        if(sessions.error){
+            notify("error", "ERROR: Unable to retrieve past workouts");
+            return [];
+        }
+
+        return await sessions.json();
+    },
+
+    switchExercise: function(num){
+        this.exerciseIndex += num;
+        this.previousExercise = this.findPreviousExercise();
+        this.renderPreviousSessionData();
+        this.renderExercise();
+    },
+
+    findPreviousExercise: function(){
+        for(let i = 0; i < this.pastSessions.length; i++){
+            for(let j = 0; j < this.pastSessions[i].exercises.length; j++){
+                const exercise = this.pastSessions[i].exercises[j];
+                if(exercise.exerciseId === this.workout.exercises[this.exerciseIndex]){
+                    return exercise;
+                }
+            }
+        }
+        return null;
+    },
+
+    renderExercise: function(){
+        const container = document.getElementById("sessionSets");
+        const weightTemplate = document.getElementById("weightSet").content.children[0];
+        let setCount = 0;
+
+        const title = document.createElement("h1");
+        title.textContent = this.workout.exercises[this.exerciseIndex].name;
+        container.appendChild(title);
+
+        if(this.previousExercise){
+            setCount = this.previousExercise.sets.length;
+        }else{
+            setCount = 3;
+        }
+        for(let i = 0; i < setCount; i++){
+            const weightSet = weightTemplate.cloneNode(true);
+            weightSet.querySelector("h3").textContent = `Set #${i+1}`;
+            if(this.previousExercise){
+                weightSet.querySelector(".weightSetWeight").value = this.previousExercise.sets[i].weight;
+            }
+            weightSet.querySelector(".weightSetWeight").addEventListener("change", this.update.bind(this));
+            container.appendChild(weightSet);
+        }
+    },
+
+    renderPreviousSessionData: function(){
+        const container = document.getElementById("previousSession");
+
+        if(!this.previousExercise){
+            const p = document.createElement("p");
+            p.id = "noSessionText";
+            p.textContent = "No previous workout data to display";
+            container.appendChild(p);
+        }else{
+            console.log("not implemented");
+        }
+    },
+
+    update: function(){
+        console.log("something");
+    }
+}

+ 9 - 2
views/logo.svg

@@ -1,3 +1,10 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="90" height="60" viewBox="10 20 80 50">
-  <path d="M10,40 Q25,20 50,30 Q75,40 90,30 Q75,50 50,60 Q25,70 10,60 Q25,50 10,40" fill="#D7263D"/>
+<svg class="logo" width="90" height="60" viewBox="10 20 80 50" xmlns="http://www.w3.org/2000/svg">
+  <defs>
+    <linearGradient id="logoGradient" x1="0%" y1="0%" x2="100%" y2="0%">
+    <stop offset="0%" stop-color="#e57600" />
+      <stop offset="25%" stop-color="#f46036" />
+      <stop offset="100%" stop-color="#d7263d" />
+    </linearGradient>
+  </defs>
+  <path d="M10,40 Q25,20 50,30 Q75,40 90,30 Q75,50 50,60 Q25,70 10,60 Q25,50 10,40" fill="url(#logoGradient)" />
 </svg>