build.html 33 KB

123
  1. <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <meta name="theme-color" media="(prefers-color-scheme: dark)" content="#1a1a1a"> <meta name="description" content="Minimalistic application for logging, tracking, monitoring and improving your workouts"> <title>Workout Tracker</title> <style>#registerPage{flex-direction:column}#registerPage .link{margin-top:35px}#loginPage{flex-direction:column}#loginPage .link{margin-top:35px}#homePage{flex-direction:column;position:relative}#homePage h1{text-decoration:underline}#homeNewWorkout{position:absolute;top:15px;right:15px}#installPwa{position:absolute;top:65px;right:15px}#workoutList{display:flex;flex-direction:column;align-items:center;width:100%}#workoutList button{margin:15px 0;padding:15px 0;width:100%;max-width:750px}#homeLogout{position:absolute;bottom:15px;left:0;width:100%;text-align:center}#workoutMenuPage{flex-direction:column;justify-content:flex-start;align-items:center;position:relative}#workoutMenuTitle{text-decoration:underline}.workoutMenuButtons{width:100%;max-width:550px;margin-top:35px}#workoutMenuPage button{width:100%;padding:15px 0;margin:15px 0}#resumeWorkoutContainer{flex-direction:column;justify-content:space-around;align-items:center;position:absolute;top:0;left:0;height:100%;width:100%;background:var(--dark);padding:25px}#resumeWorkoutContainer h2{line-height:35px;text-align:center}#resumeWorkoutContainer button{font-size:18px;max-width:550px}#deleteWorkoutModal{flex-direction:column;justify-content:space-around;position:absolute;top:0;left:0;height:calc(100vh - 60px);width:100vw;z-index:5;background:var(--dark);padding:15px;text-align:center}#newWorkoutPage{flex-direction:column;justify-content:flex-start;position:relative;padding-top:95px;overflow-y:auto}#newWorkoutBack{position:absolute;top:15px;right:15px}#newWorkoutPage label{display:flex;flex-direction:column;font-size:22px}#newWorkoutPage input{font-size:22px;color:var(--gray);padding:5px}.newWorkoutInputs{width:100%;max-width:550px}#newWorkoutName{margin-bottom:35px}#newWorkoutFinish{margin-top:35px;width:100%;max-width:550px}#sessionPage{flex-direction:column;justify-content:flex-start;padding-bottom:25px}#sessionButtonBox{display:flex;flex-direction:column;position:absolute;top:15px;right:15px}#sessionExercisesBtn{position:absolute;top:60px;left:15px}#sessionExercisesList{flex-direction:column;justify-content:center;position:fixed;top:0;left:0;height:100vh;width:100vw;background:var(--dark);overflow-y:auto;z-index:3}#closeExerciseList{background:linear-gradient(to right,var(--accent),var(--primary));border:none;position:absolute;top:15px;right:15px;font-size:22px;border-radius:50%;height:35px;width:35px;cursor:pointer;color:var(--dark)}#sessionExercisesList .exerciseListButton{align-self:center;background:linear-gradient(to right,var(--accent),var(--primary),var(--accent));background-clip:text;color:transparent;border:none;font-size:25px;margin:10px 0;cursor:pointer}#sessionNotesBtn{margin-bottom:5px}#sessionNotesText{display:flex;flex-direction:column;position:absolute;top:25%;left:2%;height:35%;min-height:275px;width:95%;max-width:750px;padding:25px 10px;box-shadow:0 0 5px var(--text);background:var(--gray);z-index:2}#sessionNotesText textarea{height:100%;width:100%;font-size:18px;margin-bottom:15px;color:var(--gray);padding:5px}#noSessionText{color:#fff;font-size:18px}#sessionPage h1{text-align:center;text-decoration:underline;margin-top:15px}.weightSet{padding:10px 5px;border:1px solid var(--accent);border-radius:25px;margin:15px 0;position:relative}.weightSetDelete{background:linear-gradient(to right,var(--accent),var(--primary));border:none;position:absolute;top:5px;right:5px;font-size:22px;border-radius:50%;height:35px;width:35px;cursor:pointer;color:var(--dark)}.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)}#nextSessionBtn,#finishSessionBtn{width:100%;max-width:550px;padding:15px 0;margin-top:25px}@media screen and (min-width: 750px){#sessionNotesText{left:calc(50% - 375px)}}#editWorkoutPage{flex-direction:column;position:relative}#editWorkoutPage h1{margin-top:35px}#editWorkoutAddExercise{position:absolute;top:5px;right:5px}#editWorkoutExercises{display:flex;flex-direction:column;align-items:center;width:100%}.editWorkoutExercise{display:flex;justify-content:space-between;align-items:center;padding:0 5px;height:75px;width:100%;max-width:550px;border-radius:5px;border:2px solid white;margin:15px 0}.workoutMove{display:flex;flex-direction:column;flex-basis:40px;flex-grow:0}.workoutMove button{background:linear-gradient(to right,var(--accent),var(--primary),var(--accent));cursor:pointer;border:none;background-clip:text;color:transparent;font-size:40px;line-height:35px}.editWorkoutExercise p{font-size:25px;flex-basis:40px;flex-grow:1;text-align:center}.editWorkoutDelete{background:linear-gradient(to right,var(--accent),var(--primary));border:none;font-size:22px;border-radius:50%;height:35px;width:35px;flex-basis:35px;flex-grow:0;cursor:pointer;color:var(--dark)}#newExerciseInput{font-size:22px;color:var(--gray);padding-left:5px}#newExerciseContainer{width:100%;max-width:550px;margin-bottom:25px}#newExerciseSubmit{border:none;background:linear-gradient(to right,var(--accent),var(--primary));background-clip:text;color:transparent;font-size:40px;font-weight:700;margin-left:15px}#editWorkoutBack,#editWorkoutSubmit{width:100%;max-width:550px;padding:15px 0;margin:15px 0}#sessionHistoryPage{flex-direction:column}#sessionHistoryPage h1{text-align:center;text-decoration:underline}#sessionHistoryClose{background:linear-gradient(to right,var(--accent),var(--primary));border:none;position:absolute;top:15px;right:15px;font-size:22px;border-radius:50%;height:35px;width:35px;cursor:pointer;color:var(--dark)}#sessionHistoryItems{display:flex;flex-direction:column;align-items:center;width:100%}#sessionHistoryItems>button{margin:5px 0;width:100%;max-width:750px;padding:15px 0}:root{--primary: #d7263d;--accent: #f46036;--dark: #1a1a1a;--gray: #2e2e2e;--text: #f2f2f2;--success: #4caf50;--warning: #ffc107}*{margin:0;padding:0;box-sizing:border-box;color:var(--text)}body{background:var(--dark)}.page{display:flex;justify-content:center;align-items:center;min-height:calc(100vh - 65px);width:100%;padding:25px}.logo{margin-left:10px}#notifier{display:flex;justify-content:center;align-items:center;position:fixed;bottom:15px;left:15px;font-size:22px;padding:25px;width:calc(100% - 30px);text-align:center;z-index:100}#notifier.error{background:var(--warning);color:var(--gray)}#notifier.success{background:var(--success)}.standardForm{display:flex;flex-direction:column;background:var(--gray);padding:35px;width:100%;max-width:550px}.standardForm h1{font-size:35px;text-align:center}.standardForm label{display:flex;flex-direction:column;font-size:22px;margin:10px 0}.standardForm input{font-size:22px;color:var(--gray)}.standardForm button{font-size:26px;background:var(--accent);margin-top:35px;padding:10px 0;cursor:pointer}.link{background:none;border:none;font-size:22px;cursor:pointer;text-decoration:underline}.button{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 transparent;padding:5px 25px;font-size:22px;cursor:pointer;position:relative;-webkit-tap-highlight-color:transparent}.dangerButton{background:linear-gradient(to bottom right,var(--accent),var(--primary),var(--accent));border-radius:15px;border:none;padding:5px 25px;font-size:22px;cursor:pointer;position:relative}.dangerText{color:var(--primary)}
  2. </style> <link rel="icon" href="/logo.svg" type="image/svg+xml"> <link rel="manifest" href="/manifest.json"> </head> <body> <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> <div id="registerPage" class="page" style="display:none"> <form id="registerForm" class="standardForm"> <h1>Create Account</h1> <label>Name <input id="registerName" type="text" placeholder="Name" required> </label> <label>Email <input id="registerEmail" type="email" placeholder="Email" required> </label> <label>Password <input id="registerPass" type="password" placeholder="Password" required> </label> <label>Confirm Password <input id="registerConfirmPass" type="password" placeholder="Confirm Password" required> </label> <button>Create</button> </form> <button id="registerToLogin" class="link">Log In</button> </div> <div id="loginPage" class="page" style="display:none"> <form id="loginForm" class="standardForm"> <h1>Log In</h1> <label>Email <input id="loginEmail" type="email" placeholder="Email" required> </label> <label>Password <input id="loginPass" type="password" placeholder="Password" required> </label> <button>Log In</button> </form> <button id="loginToRegister" class="link">Register</button> </div> <div id="homePage" class="page" style="display:none"> <button id="homeNewWorkout" class="button">+ Workout</button> <button id="installPwa" class="button">Install App</button> <h1>My Workouts</h1> <div id="workoutList"></div> <button id="homeLogout" class="link">Log Out</button> </div> <div id="newWorkoutPage" class="page" style="display:none"> <button id="newWorkoutBack" class="button">Cancel</button> <div id="newWorkoutInputs"> <label>Name of Workout: <input id="newWorkoutName" type="text" placeholder="Name"> </label> </div> <button id="newWorkoutFinish" class="button">Create Workout</button> </div> <div id="workoutMenuPage" , class="page" style="display:none"> <h1 id="workoutMenuTitle"></h1> <div id="workoutMenuButtons"></div> <div id="resumeWorkoutContainer" style="display:none"> <h2>You have a previously unfinished session for this workout. What would you like to to?</h2> <button id="resumeWorkoutCancel" class="button">Cancel</button> </div> <div id="deleteWorkoutModal" style="display:none"> <h1>Are you sure that you want to delete this workout?</h1> <h2>All workout sessions associated with the workout will also be deleted</h2> <h2 class="dangerText">THIS CANNOT BE UNDONE</h2> <button id="confirmDeleteWorkoutBtn" class="button">Delete Workout</button> <button id="cancelDeleteWorkoutBtn" class="button">Cancel</button> </div> </div> <div id="sessionPage" class="page" style="display:none"> <h1 id="sessionExerciseName"></h1> <p id="previousSession"></p> <div id="sessionButtonBox"> <button id="sessionNotesBtn" class="button">Notes</button> <button id="sessionAddSet" class="button">Add Set</button> </div> <button id="sessionExercisesBtn" class="button">Exercises</button> <div id="sessionExercisesList" style="display:none"> <button id="closeExerciseList">X</button> </div> <div id="sessionNotesText" style="display:none"> <textarea id="sessionTextArea"></textarea> <button id="sessionNotesDone" class="button">Done</button> </div> <div id="sessionSets"></div> <button id="nextSessionBtn" class="button">Next Exercise</button> <button id="finishSessionBtn" class="button">Finish Workout</button> <template id="weightSet"> <div class="weightSet"> <button class="weightSetDelete">X</button> <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> <div id="editWorkoutPage" class="page" style="display:none"> <button id="editWorkoutAddExercise" aria-label="Add Exercise" class="button">+ Exercise</button> <h1></h1> <div id="editWorkoutExercises"></div> <div id="newExerciseContainer" style="display:none"> <input id="newExerciseInput" type="text" placeholder="New Exercise"> <button id="newExerciseSubmit">✓</button> </div> <button id="editWorkoutSubmit" class="button">Finish</button> <button id="editWorkoutBack" class="button">Cancel</button> <template id="editWorkoutExercise"> <div class="editWorkoutExercise"> <div class="workoutMove"> <button class="workoutMoveUp" aria-label="Move up">▲</button> <button class="workoutMoveDown" aria-label="Move down">▼</button> </div> <p></p> <button class="editWorkoutDelete" aria-label="Delete">X</button> </div> </template> </div> <div id="sessionHistoryPage" class="page" style="display:none"> <button id="sessionHistoryClose" aria-label="Close">X</button> <h1 id="sessionHistoryTitle"></h1> <div id="sessionHistoryItems"></div> </div> <script>(()=>{var h={rendered:!1,render:function(){this.rendered||(this.buttons(),this.createSubmit(),this.rendered=!0)},buttons:function(){document.getElementById("registerToLogin").addEventListener("click",()=>{changePage("login")})},createSubmit:function(){document.getElementById("registerForm").addEventListener("submit",e=>{e.preventDefault(),fetch("/user",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:document.getElementById("registerName").value,email:document.getElementById("registerEmail").value,pass:document.getElementById("registerPass").value,confirmPass:document.getElementById("registerConfirmPass").value})}).then(t=>t.json()).then(t=>{t.error?notify("error",t.error.message):changePage("login")}).catch(t=>{notify("error","Something went wrong, try refreshing the page")})})}};var m={rendered:!1,render:function(){document.getElementById("loginEmail").focus(),this.rendered||(this.buttons(),this.createSubmit(),this.rendered=!0)},buttons:function(){document.getElementById("loginToRegister").addEventListener("click",()=>{changePage("register")})},createSubmit:function(){document.getElementById("loginForm").addEventListener("submit",e=>{e.preventDefault(),fetch("/user/login",{method:"put",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:document.getElementById("loginEmail").value,pass:document.getElementById("loginPass").value})}).then(t=>t.json()).then(t=>{t.error?notify("error",t.error.message):(localStorage.setItem("loggedIn","true"),changePage("home",t))}).catch(t=>{console.log(t),notify("error","Something went wrong, try refreshing the page")})})},checkUser:function(){fetch("/user",{method:"GET",headers:{"Content-Type":"application/json"}}).then(e=>e.json()).then(e=>{e.error||changePage("home",e)}).catch(e=>{})}};var g={rendered:!1,workoutList:document.getElementById("workoutList"),render:function(e){this.rendered||(this.getWorkouts(),this.buttons(),this.rendered=!0),e&&this.handleUpdate(e)},buttons:function(){document.getElementById("homeLogout").addEventListener("click",()=>{fetch("/user/logout").then(e=>e.json()).then(e=>{e.error?notify("error",e.error.message):(localStorage.removeItem("loggedIn"),changePage("login"))}).catch(e=>{notify("error","Something went wrong, try refreshing the page")})}),document.getElementById("homeNewWorkout").addEventListener("click",()=>{changePage("newWorkout")})},getWorkouts:function(){fetch("/workout",{method:"get",headers:{"Content-Type":"application/json"}}).then(e=>e.json()).then(e=>{e.error?notify("error",e.error.message):this.renderWorkouts(e)}).catch(e=>{notify("error","ERROR: Unable to retrieve workouts")})},renderWorkouts:function(e){for(;this.workoutList.children.length>0;)this.workoutList.removeChild(this.workoutList.firstChild);for(let t=0;t<e.length;t++)this.workoutList.appendChild(this.createWorkoutElem(e[t]))},handleUpdate:function(e){switch(e.type){case"new":this.workoutList.appendChild(this.createWorkoutElem(e.workout));break;case"remove":this.removeWorkout(e.workout);break;case"replace":this.replaceWorkout(e.workout);break}},createWorkoutElem:function(e){let t=document.createElement("button");return t.workoutId=e.id,t.classList.add("button"),t.textContent=e.name,t.addEventListener("click",()=>{changePage("workoutMenu",e)}),t},removeWorkout:function(e){let t=this.workoutList.children;for(let n=0;n<t.length;n++)if(t[n].workoutId===e){this.workoutList.removeChild(t[n]);break}},replaceWorkout:function(e){let t=this.workoutList.children;for(let n=0;n<t.length;n++)if(t[n].workoutId===e.id){t[n].replaceWith(this.createWorkoutElem(e));break}}};var f={render:function(e){document.getElementById("workoutMenuTitle").textContent=e.name,this.buttons(e)},buttons:function(e){let t=document.getElementById("workoutMenuButtons");for(;t.children.length>0;)t.removeChild(t.firstChild);let n=document.createElement("button");n.classList.add("button"),n.textContent="Start Workout",n.addEventListener("click",()=>{if(localStorage.getItem(e.id)===null)changePage("session",e);else{let u=document.getElementById("resumeWorkoutContainer");u.style.display="flex",this.addResumeButtons(u,e)}}),t.appendChild(n);let s=document.createElement("button");s.classList.add("button"),s.textContent="Workout History",s.addEventListener("click",()=>{changePage("sessionHistory",e)}),t.appendChild(s);let o=document.createElement("button");o.classList.add("button"),o.textContent="Edit Workout",o.addEventListener("click",()=>{changePage("editWorkout",e)}),t.appendChild(o);let i=document.createElement("button");i.classList.add("button"),i.textContent="Delete Workout",i.addEventListener("click",()=>{this.showDeleteModal(e)}),t.appendChild(i);let r=document.createElement("button");r.classList.add("button"),r.textContent="Back",r.addEventListener("click",()=>{changePage("home")}),t.appendChild(r)},addResumeButtons:function(e,t){let n=e.querySelectorAll("button");for(let c=0;c<n.length;c++)n[c].parentElement.removeChild(n[c]);let s=document.createElement("button");s.classList.add("button"),s.textContent="Save Previous and Start New",s.addEventListener("click",()=>{this.finish(t)}),e.appendChild(s);let o=document.createElement("button");o.classList.add("button"),o.textContent="Discard Previous and Start New",o.addEventListener("click",()=>{this.discard(t)}),e.appendChild(o);let i=document.createElement("button");i.classList.add("button"),i.textContent="Resume Previous Workout",i.addEventListener("click",()=>{this.resume(t)}),e.appendChild(i);let r=document.createElement("button");r.classList.add("button"),r.textContent="Cancel",r.addEventListener("click",this.cancel),e.appendChild(r)},finish:function(e){let t=JSON.parse(localStorage.getItem(e.id));t.end=new Date,fetch("/session",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)}).then(n=>n.json()).then(n=>{n.error?notify("error",n.error.message):notify("success","Workout saved"),localStorage.removeItem(e.id),document.getElementById("resumeWorkoutContainer").style.display="none",changePage("session",e)}).catch(n=>{notify("error","ERROR: unable to start workout")})},discard:function(e){localStorage.removeItem(e.id),document.getElementById("resumeWorkoutContainer").style.display="none",changePage("session",e)},resume:function(e){document.getElementById("resumeWorkoutContainer").style.display="none",changePage("session",e)},cancel:function(){document.getElementById("resumeWorkoutContainer").style.display="none"},showDeleteModal:function(e){let t=document.getElementById("deleteWorkoutModal"),n=t.querySelectorAll("button");for(let i=0;i<n.length;i++)n[i].parentElement.removeChild(n[i]);let s=document.createElement("button");s.classList.add("button"),s.textContent="Cancel",s.addEventListener("click",()=>{t.style.display="none"}),t.appendChild(s);let o=document.createElement("button");o.classList.add("dangerButton"),o.textContent="Delete Workout",o.addEventListener("click",()=>{this.delete(e)}),t.appendChild(o),t.style.display="flex"},delete:function(e){fetch(`/workout/${e.id}`,{method:"DELETE",headers:{"Content-Type":"application/json"}}).then(t=>t.json()).then(t=>{t.error?notify("error",t.error.message):changePage("home",{type:"remove",workout:e.id})}).catch(t=>{notify("error","ERROR: unable to delete the workout")}),document.getElementById("resumeWorkoutContainer").style.display="none"}};var y={rendered:!1,exerciseInputs:[],inputsDiv:document.getElementById("newWorkoutInputs"),render:function(){document.getElementById("newWorkoutName").focus(),this.rendered||(this.buttons(),this.addExerciseInput(),this.rendered=!0)},buttons:function(){document.getElementById("newWorkoutBack").addEventListener("click",()=>{changePage("home")}),document.getElementById("newWorkoutFinish").addEventListener("click",this.createWorkout.bind(this))},addExerciseInput:function(){let e=document.createElement("label");this.inputsDiv.appendChild(e);let t=document.createElement("p");t.textContent=`Exercise # ${this.exerciseInputs.length+1}`,e.appendChild(t);let n=document.createElement("input");n.type="text",n.placeholder="Exercise Name",n.addEventListener("keyup",this.checkInputs.bind(this)),e.appendChild(n),this.exerciseInputs.push(n)},checkInputs:function(){let e=!1;for(let t=0;t<this.exerciseInputs.length;t++)this.exerciseInputs[t].value===""&&(e=!0);e||this.addExerciseInput()},createWorkout:function(){let e=document.getElementById("newWorkoutName").value,t=[];for(let n=0;n<this.exerciseInputs.length;n++)this.exerciseInputs[n].value!==""&&t.push({name:this.exerciseInputs[n].value,type:"weights"});if(t.length===0){notify("error","Workout must contain at least one exercise");return}fetch("/workout",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:document.getElementById("newWorkoutName").value,exercises:t})}).then(n=>n.json()).then(n=>{n.error?notify("error",n.error.message):(notify("success","New workout created"),changePage("home",{type:"new",workout:n}))}).catch(n=>{notify("error","ERROR: unable to create workout")})}};var p={rendered:!1,workout:null,pastSessions:null,exerciseIndex:0,currentSession:null,render:async function(e){this.workout=e,this.pastSessions=await this.getPastSessions(e.id);let t=localStorage.getItem(e.id);t?(this.currentSession=JSON.parse(t),this.exerciseIndex=this.currentSession.exerciseIndex):this.currentSession=this.createNewSession(e),this.buttons(),this.changeExercise(0)},getPastSessions:async function(e){let t=await fetch(`/session/${e}`,{method:"GET",headers:{"Content-Type":"application/json"}});return t.error?(notify("error","ERROR: Unable to retrieve past workouts"),[]):await t.json()},buttons:function(){let e=document.getElementById("nextSessionBtn");e.style.display="block",this.rendered||(e.addEventListener("click",()=>{this.currentSession.exercises[this.exerciseIndex].done=!0,this.changeExercise(this.exerciseIndex+1)}),document.getElementById("finishSessionBtn").addEventListener("click",()=>{this.finish()}),document.getElementById("sessionAddSet").addEventListener("click",()=>{this.addSet()}),document.getElementById("sessionNotesBtn").addEventListener("click",this.displayNotes.bind(this)),document.getElementById("sessionNotesDone").addEventListener("click",this.closeNote.bind(this)),document.getElementById("sessionExercisesBtn").addEventListener("click",this.displayExerciseList.bind(this)),document.getElementById("closeExerciseList").addEventListener("click",()=>{document.getElementById("sessionExercisesList").style.display="none"}),this.rendered=!0)},displayExerciseList:function(){let e=document.getElementById("sessionExercisesList");e.style.display="flex";let t=e.querySelectorAll(".exerciseListButton");for(let n=0;n<t.length;n++)t[n].parentElement.removeChild(t[n]);for(let n=0;n<this.workout.exercises.length;n++){let s=document.createElement("button");s.classList.add("exerciseListButton"),this.exerciseIndex===n?s.textContent=`*${this.workout.exercises[n].name}`:s.textContent=this.workout.exercises[n].name,s.addEventListener("click",()=>{this.changeExercise(n),e.style.display="none"}),this.currentSession.exercises[n]?.done&&(s.style.color="white"),e.appendChild(s)}},displayNotes:function(){let e=document.getElementById("sessionNotesText");e.style.display="flex";let t=e.querySelector("textarea");t.value=this.workout.exercises[this.exerciseIndex].notes||""},closeNote:function(){let e=this.workout.exercises.find(n=>n._id===this.currentSession.exercises[this.exerciseIndex].exerciseId),t=document.getElementById("sessionTextArea").value;e.notes!==t&&fetch(`/workout/${this.workout.id}/note`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({exercise:this.currentSession.exercises[this.exerciseIndex].exerciseId,note:t})}).then(n=>n.json()).then(n=>{n.error&&notify("error",n.error.message),e.notes=t}).catch(n=>{notify("error","ERROR: unable to save note")}),document.getElementById("sessionNotesText").style.display="none"},addSet:function(){let e=this.currentSession.exercises[this.exerciseIndex],t=document.getElementById("weightSet").content.children[0],n=document.getElementById("sessionSets");switch(e.type){case"weights":let s={weight:0,reps:0},o=n.children.length+1;e.sets.push(s),n.appendChild(this.createWeightSetElement(t,s,o));break}},createNewSession:function(e){return session={workout:e.id,start:new Date,notes:"",exercises:Array(this.workout.exercises.length).fill(null),exerciseIndex:this.exerciseIndex},localStorage.setItem(e.id,JSON.stringify(session)),session},changeExercise:function(e){this.exerciseIndex=e,localStorage.setItem(this.workout.id,JSON.stringify(this.currentSession));let t=document.getElementById("nextSessionBtn");this.exerciseIndex===this.workout.exercises.length-1?t.style.display="none":t.style.display="block";let n=null;if(this.currentSession.exercises[this.exerciseIndex])n=this.currentSession.exercises[this.exerciseIndex];else{let o=this.workout.exercises[this.exerciseIndex];n={exerciseId:o._id,name:o.name,type:o.type,notes:"",sets:this.getPastSets(o._id),done:!1},this.currentSession.exercises[this.exerciseIndex]=n}document.getElementById("sessionExerciseName").textContent=n.name;let s=document.getElementById("sessionSets");for(;s.children.length>0;)s.removeChild(s.firstChild);switch(n.type){case"weights":this.displayWeightSets(n.sets,s)}},displayWeightSets:function(e,t){let n=document.getElementById("weightSet").content.children[0];for(let s=0;s<e.length;s++)t.appendChild(this.createWeightSetElement(n,e[s],s+1))},createWeightSetElement:function(e,t,n){let s=e.cloneNode(!0);s.querySelector("h3").textContent=`Set #${n}`,s.querySelector(".weightSetDelete").addEventListener("click",c=>{this.deleteSet(n,c.target.parentElement)});let i=s.querySelector(".weightSetWeight");t.weight>0&&(i.value=t.weight),i.addEventListener("input",()=>{t.weight=i.value});let r=s.querySelector(".weightSetReps");return t.reps!==0&&(r.value=t.reps),r.addEventListener("input",()=>{t.reps=r.value}),s},deleteSet:function(e,t){this.currentSession.exercises[this.exerciseIndex].sets.splice(e-1,1);let n=t.parentElement;n.removeChild(t);for(let s=0;s<n.children.length;s++)n.children[s].querySelector("h3").textContent=`Set #${s+1}`},getPastSets:function(e){let t=document.getElementById("previousSession");for(let n=0;n<this.pastSessions.length;n++)for(let s=0;s<this.pastSessions[n].exercises.length;s++)if(this.pastSessions[n].exercises[s].exerciseId===e)return t.textContent="*Data autofilled from previous workout",this.pastSessions[n].exercises[s].sets;return t.textContent="*No previous workout data",[{weight:0,reps:0},{weight:0,reps:0},{weight:0,reps:0}]},finish:function(){this.currentSession.end=new Date,fetch("/session",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(this.currentSession)}).then(e=>e.json()).then(e=>{e.error?notify("error",e.error.message):(notify("success","Workout completed and saved"),localStorage.removeItem(this.currentSession.workout),this.workout=null,this.exerciseIndex=0,this.pastSessions=null,this.currentSession=null,changePage("home"))}).catch(e=>{notify("error","ERROR: unable to save workout to database")})}};var E={rendered:!1,workout:null,render:function(e){this.workout=e,document.querySelector("#editWorkoutPage h1").textContent=e.name,this.displayExercises(e.exercises),this.rendered||(this.buttons(),this.rendered=!0)},buttons:function(){document.getElementById("editWorkoutBack").addEventListener("click",()=>{changePage("home")}),document.getElementById("editWorkoutAddExercise").addEventListener("click",()=>{let e=document.getElementById("newExerciseContainer");e.style.display="flex",e.querySelector("input").focus()}),document.getElementById("newExerciseSubmit").addEventListener("click",this.addExercise.bind(this)),document.getElementById("editWorkoutSubmit").addEventListener("click",this.submitWorkout.bind(this))},displayExercises:function(e){let t=document.getElementById("editWorkoutExercises"),n=document.getElementById("editWorkoutExercise").content.children[0];for(;t.children.length>0;)t.removeChild(t.firstChild);for(let s=0;s<e.length;s++){let o=n.cloneNode(!0);o.setAttribute("data-id",e[s]._id),o.querySelector("p").textContent=e[s].name,o.querySelector(".editWorkoutDelete").addEventListener("click",()=>{t.removeChild(o)}),o.querySelector(".workoutMoveUp").addEventListener("click",i=>{this.moveExercise(i.target.parentElement.parentElement,!0)}),o.querySelector(".workoutMoveDown").addEventListener("click",i=>{this.moveExercise(i.target.parentElement.parentElement,!1)}),t.appendChild(o)}},moveExercise:function(e,t){let n=t?e.previousElementSibling:e.nextElementSibling;t?e.parentElement.insertBefore(e,n):e.parentElement.insertBefore(n,e)},addExercise:function(){let e=document.getElementById("editWorkoutExercises"),t=document.getElementById("editWorkoutExercise").content.children[0],n=document.getElementById("newExerciseInput");if(n.value===""){notify("error","Exercise must have a name");return}let s=t.cloneNode(!0);s.querySelector("p").textContent=n.value,s.querySelector(".editWorkoutDelete").addEventListener("click",()=>{e.removeChild(s)}),s.querySelector(".workoutMoveUp").addEventListener("click",o=>{this.moveExercise(o.target.parentElement.parentElement,!0)}),s.querySelector(".workoutMoveDown").addEventListener("click",o=>{this.moveExercise(o.target.parentElement.parentElement,!0)}),e.appendChild(s),n.value="",document.getElementById("newExerciseContainer").style.display="none"},submitWorkout:function(){let e=document.getElementById("editWorkoutExercises"),t=[];for(let n=0;n<e.children.length;n++){let s=e.children[n],o=s.getAttribute("data-id");o?t.push({id:o}):t.push({new:s.querySelector("p").textContent,type:"weights"})}fetch(`/workout/${this.workout.id}`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({existingExercises:t})}).then(n=>n.json()).then(n=>{n.error?notify("error",n.error.message):(notify("success","Workout updated"),changePage("home",{type:"replace",workout:n}))}).catch(n=>{notify("error","ERROR: unable to save workout")})}};var x={rendered:!1,render:function(e){this.rendered||(this.buttons(e),this.rendered=!0),document.getElementById("sessionHistoryTitle").textContent=e.name,this.populateSessions(e)},buttons:function(e){document.getElementById("sessionHistoryClose").addEventListener("click",()=>{changePage("workoutMenu",e)})},populateSessions:function(e){fetch(`/session/${e.id}/all`,{method:"GET",headers:{"Content-Type":"application/json"}}).then(t=>t.json()).then(t=>{t.error?notify("error",t.error.message):this.showSessions(t)}).catch(t=>{console.log(t),notify("error","ERROR: unable to load your data")})},showSessions:function(e){let t=document.getElementById("sessionHistoryItems");for(;t.children.length>0;)t.removeChild(t.firstChild);for(let s=0;s<e.length;s++)t.appendChild(this.createSessionButton(e[s]));let n=document.createElement("button");n.classList.add("button"),n.addEventListern},createSessionButton:function(e){let t=document.createElement("button");return t.classList.add("button"),t.textContent=this.dateFormat(new Date(e.start)),t.addEventListener("click",()=>{console.log(`Button pressed for ${e.id}`)}),t},dateFormat:function(e){return e.toLocaleDateString("en-us",{year:"numeric",month:"long",day:"numeric"})}};var d=document.getElementById("notifier"),k=document.querySelectorAll(".page");window.notify=(e,t)=>{d.className="",d.classList.add(e),d.textContent=t,d.style.display="flex",setTimeout(()=>{d.style.display="none"},7500)};window.changePage=(e,t)=>{for(let n=0;n<k.length;n++)k[n].style.display="none";switch(document.getElementById(`${e}Page`).style.display="flex",e){case"login":m.render();break;case"register":h.render();break;case"home":g.render(t);break;case"newWorkout":y.render();case"session":p.render(t);break;case"workoutMenu":f.render(t);break;case"editWorkout":E.render(t);break;case"sessionHistory":x.render(t);break}};localStorage.getItem("loggedIn")==="true"?changePage("home"):changePage("login");"serviceWorker"in navigator&&window.addEventListener("load",()=>{navigator.serviceWorker.register("/serviceWorker.js").then(e=>null).catch(e=>null)});var a,l=document.getElementById("installPwa"),I=()=>window.matchMedia("(display-mode: standalone)").matches||window.navigator.standalone===!0;I()&&(l.style.display="none");window.addEventListener("beforeinstallprompt",e=>{e.preventDefault(),a=e});l.addEventListener("click",async()=>{if(a){a.prompt();let{outcome:e}=await a.userChoice;a=null,e==="accepted"&&(l.style.display="none")}});})();
  3. </script> </body> </html>