From e996a7643aa56bb3edf6aeb68192f1d054d2126f Mon Sep 17 00:00:00 2001 From: Debi312 Date: Mon, 12 Aug 2024 10:36:37 +0200 Subject: [PATCH] Add getRandomWorkout logic in api and app with test; add WorkoutDetails view; modify Workout data model in README #178 --- .../api/handlers/getRandomWorkoutHandler.js | 32 ++++++ .../project/api/handlers/index.js | 4 +- staff/debora-garcia/project/api/index.js | 1 + .../project/api/logic/getRandomWorkout.js | 34 +++++++ .../api/logic/getRandomWorkout.test.js | 18 ++++ .../debora-garcia/project/api/logic/index.js | 2 + .../project/api/test/get-randomWorkout.sh | 1 + staff/debora-garcia/project/app/src/App.jsx | 29 +++--- .../app/src/components/Button/index.jsx | 2 +- staff/debora-garcia/project/app/src/index.css | 13 ++- .../project/app/src/logic/getRandomWorkout.js | 30 ++++++ .../project/app/src/logic/index.js | 2 + .../project/app/src/views/Achievements.jsx | 70 +------------ .../project/app/src/views/Amrap.jsx | 33 +++++++ .../project/app/src/views/Benchmark.jsx | 32 ++++++ .../project/app/src/views/Emom.jsx | 38 ++++++++ .../project/app/src/views/Feed.jsx | 65 +------------ .../project/app/src/views/ForTime.jsx | 34 +++++++ .../project/app/src/views/Home.jsx | 86 +++++++++++++++- .../project/app/src/views/Login.jsx | 20 ++-- .../project/app/src/views/Register.jsx | 29 +++--- .../project/app/src/views/WorkoutDetails.css | 8 ++ .../project/app/src/views/WorkoutDetails.jsx | 50 ++++++++++ .../project/app/src/views/Workouts.jsx | 97 +++++-------------- .../app/src/views/components/Footer/index.jsx | 27 ++---- .../app/src/views/components/Header/index.jsx | 28 +++++- .../components/Workout/Movement/index.css | 0 .../components/Workout/Movement/index.jsx | 0 .../src/views/components/Workout/index.css | 0 .../src/views/components/Workout/index.jsx | 3 - staff/debora-garcia/project/com/validate.js | 7 +- staff/debora-garcia/project/doc/README.md | 6 +- 32 files changed, 523 insertions(+), 278 deletions(-) create mode 100644 staff/debora-garcia/project/api/handlers/getRandomWorkoutHandler.js create mode 100644 staff/debora-garcia/project/api/logic/getRandomWorkout.js create mode 100644 staff/debora-garcia/project/api/logic/getRandomWorkout.test.js create mode 100755 staff/debora-garcia/project/api/test/get-randomWorkout.sh create mode 100644 staff/debora-garcia/project/app/src/logic/getRandomWorkout.js create mode 100644 staff/debora-garcia/project/app/src/views/Amrap.jsx create mode 100644 staff/debora-garcia/project/app/src/views/Benchmark.jsx create mode 100644 staff/debora-garcia/project/app/src/views/Emom.jsx create mode 100644 staff/debora-garcia/project/app/src/views/ForTime.jsx create mode 100644 staff/debora-garcia/project/app/src/views/WorkoutDetails.css create mode 100644 staff/debora-garcia/project/app/src/views/WorkoutDetails.jsx delete mode 100644 staff/debora-garcia/project/app/src/views/components/Workout/Movement/index.css delete mode 100644 staff/debora-garcia/project/app/src/views/components/Workout/Movement/index.jsx delete mode 100644 staff/debora-garcia/project/app/src/views/components/Workout/index.css delete mode 100644 staff/debora-garcia/project/app/src/views/components/Workout/index.jsx diff --git a/staff/debora-garcia/project/api/handlers/getRandomWorkoutHandler.js b/staff/debora-garcia/project/api/handlers/getRandomWorkoutHandler.js new file mode 100644 index 000000000..bfe90a05a --- /dev/null +++ b/staff/debora-garcia/project/api/handlers/getRandomWorkoutHandler.js @@ -0,0 +1,32 @@ +import "dotenv/config" +import logic from "../logic/index.js" +import jwt from "../utils/jsonwebtoken-promised.js" +import { CredentialsError } from "com/errors.js" + +const { JWT_SECRET } = process.env +const getRandomWorkoutHandler = (req, res, next) => { + try { + const token = req.headers.authorization.slice(7) + + jwt.verify(token, JWT_SECRET) + .then(payload => { + const { sub: userId } = payload + const { workoutType } = req.params + + try { + logic.getRandomWorkout(userId, workoutType) + .then(randomWorkout => res.json(randomWorkout)) + .catch(error => next(error)) + } catch (error) { + next(error) + } + + }) + .catch(error => next(new CredentialsError(error.message))) + + } catch (error) { + next(error) + } +} + +export default getRandomWorkoutHandler \ No newline at end of file diff --git a/staff/debora-garcia/project/api/handlers/index.js b/staff/debora-garcia/project/api/handlers/index.js index 1a1398bcd..9cfb51903 100644 --- a/staff/debora-garcia/project/api/handlers/index.js +++ b/staff/debora-garcia/project/api/handlers/index.js @@ -1,5 +1,6 @@ import authenticateUserHandler from "./authenticateUserHandler.js"; import errorHandler from "./errorHandler.js"; +import getRandomWorkoutHandler from "./getRandomWorkoutHandler.js"; import getUsernameHandler from "./getUsernameHandler.js"; import registerUserHandler from "./registerUserHandler.js"; @@ -8,7 +9,8 @@ const routeHandler = { errorHandler, registerUserHandler, authenticateUserHandler, - getUsernameHandler + getUsernameHandler, + getRandomWorkoutHandler } export default routeHandler \ No newline at end of file diff --git a/staff/debora-garcia/project/api/index.js b/staff/debora-garcia/project/api/index.js index 086e6ca3b..1c735a2d3 100644 --- a/staff/debora-garcia/project/api/index.js +++ b/staff/debora-garcia/project/api/index.js @@ -24,6 +24,7 @@ mongoose.connect(MONGODB_URL) api.post("/users", jsonBodyParser, routeHandler.registerUserHandler) api.post("/users/auth", jsonBodyParser, routeHandler.authenticateUserHandler) api.get("/users/:targetUserId", routeHandler.getUsernameHandler) + api.get("/workouts/:workoutType", routeHandler.getRandomWorkoutHandler) api.use(errorHandler) api.listen(PORT, () => console.log(`API running on PORT ${PORT}`)) diff --git a/staff/debora-garcia/project/api/logic/getRandomWorkout.js b/staff/debora-garcia/project/api/logic/getRandomWorkout.js new file mode 100644 index 000000000..99e8533f4 --- /dev/null +++ b/staff/debora-garcia/project/api/logic/getRandomWorkout.js @@ -0,0 +1,34 @@ +import { User, Workout } from "../data/index.js" +import { SystemError, NotFoundError } from "com/errors.js" +import validate from "com/validate.js" + +const getRandomWorkout = (userId, workoutType) => { + validate.id(userId, "userId") + validate.type(workoutType, "workoutType") + + return User.findById(userId).lean() + .catch(error => { throw new SystemError(error.message) }) + .then(user => { + if (!user) throw new NotFoundError("user not found") + + return Workout.find({ workoutType }).select("-__v").populate("movements").lean() + .catch(error => { throw new SystemError(error.message) }) + .then(workouts => { + if (!workouts) throw new NotFoundError("workouts not found") + + const randomNumber = Math.floor(Math.random() * workouts.length) + + const randomWorkout = workouts[randomNumber] + + if (!randomWorkout) throw new NotFoundError("workout not found") + + randomWorkout.id = randomWorkout._id.toString() + + delete randomWorkout._id + + return randomWorkout + }) + + }) +} +export default getRandomWorkout diff --git a/staff/debora-garcia/project/api/logic/getRandomWorkout.test.js b/staff/debora-garcia/project/api/logic/getRandomWorkout.test.js new file mode 100644 index 000000000..8a7b27715 --- /dev/null +++ b/staff/debora-garcia/project/api/logic/getRandomWorkout.test.js @@ -0,0 +1,18 @@ +import "dotenv/config" +import mongoose from "mongoose" + +import getRandomWorkout from "./getRandomWorkout.js" +const { MONGODB_URL } = process.env + +mongoose.connect(MONGODB_URL) + .then(() => { + try { + getRandomWorkout("66b0b8ff337c2b614a26583b", "emom") + .then(randomWorkout => console.log(randomWorkout)) + .catch(error => console.error(error)) + + } catch (error) { + console.error(error) + } + }) + .catch(error => console.error(error)) diff --git a/staff/debora-garcia/project/api/logic/index.js b/staff/debora-garcia/project/api/logic/index.js index ffb745143..88957cce1 100644 --- a/staff/debora-garcia/project/api/logic/index.js +++ b/staff/debora-garcia/project/api/logic/index.js @@ -2,6 +2,7 @@ import registerUser from "./registerUser.js" import authenticateUser from "./authenticateUser.js" import getUsername from "./getUsername.js" import insertWorkout from "./insertWorkout.js" +import getRandomWorkout from "./getRandomWorkout.js" @@ -10,6 +11,7 @@ const logic = { authenticateUser, getUsername, insertWorkout, + getRandomWorkout } export default logic \ No newline at end of file diff --git a/staff/debora-garcia/project/api/test/get-randomWorkout.sh b/staff/debora-garcia/project/api/test/get-randomWorkout.sh new file mode 100755 index 000000000..ccb0867e0 --- /dev/null +++ b/staff/debora-garcia/project/api/test/get-randomWorkout.sh @@ -0,0 +1 @@ +curl http://localhost:8080/workouts/emom -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI2NmFiZTA1NjcxM2E4YmU5MmY4ZTU4NDQiLCJpYXQiOjE3MjI3OTUwMjAsImV4cCI6MTcyMzM5OTgyMH0.9JIikHMaqlttsnSqRe_YCT_1tYl9cEDfo3o6DFIePO8" -v \ No newline at end of file diff --git a/staff/debora-garcia/project/app/src/App.jsx b/staff/debora-garcia/project/app/src/App.jsx index 40781664d..463d7f393 100644 --- a/staff/debora-garcia/project/app/src/App.jsx +++ b/staff/debora-garcia/project/app/src/App.jsx @@ -1,4 +1,4 @@ -import { Routes, Route, useNavigate, Navigate } from "react-router-dom" +import { Routes, Route, Navigate } from "react-router-dom" import logic from "./logic"; @@ -7,28 +7,27 @@ import Register from "./views/Register"; import Workouts from "./views/Workouts"; import Achievements from "./views/Achievements"; import Feed from "./views/Feed"; +import Amrap from "./views/Amrap"; +import Emom from "./views/Emom"; +import ForTime from "./views/ForTime"; +import Benchmark from "./views/Benchmark"; +import Home from "./views/Home"; +//TODO hacer una pagina de home export default function App() { console.log("App -> render") - const navigate = useNavigate() - const handleGoToLogin = () => navigate("/login") - const handleGoToRegister = () => navigate("/register") - const handleGoToFeed = () => navigate("/feed") - const handleGoToWorkouts = () => navigate("/workouts") - const handleGoToAchievements = () => navigate("/achievements") return - : } /> + } /> - : } /> - - : } /> - - : } /> - - : } /> + } /> + } /> + } +const RenderRegister = () => (logic.isUserLoggedIn() ? : ) +const RenderLogin = () => (logic.isUserLoggedIn() ? : ) +const RenderHome = () => (logic.isUserLoggedIn() ? : ) diff --git a/staff/debora-garcia/project/app/src/components/Button/index.jsx b/staff/debora-garcia/project/app/src/components/Button/index.jsx index 70e55b70f..47925354b 100644 --- a/staff/debora-garcia/project/app/src/components/Button/index.jsx +++ b/staff/debora-garcia/project/app/src/components/Button/index.jsx @@ -1,6 +1,6 @@ import "./index.css" export default function Button({ type, className, onClick, children }) { - return + return } \ No newline at end of file diff --git a/staff/debora-garcia/project/app/src/index.css b/staff/debora-garcia/project/app/src/index.css index 3540b6286..6a1c69f6e 100644 --- a/staff/debora-garcia/project/app/src/index.css +++ b/staff/debora-garcia/project/app/src/index.css @@ -15,14 +15,13 @@ } body { - background-color: var(--second-color); - margin: 0; + @apply flex min-h-screen w-full flex-col bg-[--second-color] justify-center; } - -form { - @apply flex flex-col justify-center min-h-[100vh]; +.Main { + @apply flex w-full flex-grow flex-col items-center justify-center; } + .registerForm { @apply flex flex-col items-center; } @@ -38,3 +37,7 @@ form { .button-container Button:hover { @apply bg-[#65524d]; } + +main { + @apply flex flex-col justify-center items-center gap-4 +} diff --git a/staff/debora-garcia/project/app/src/logic/getRandomWorkout.js b/staff/debora-garcia/project/app/src/logic/getRandomWorkout.js new file mode 100644 index 000000000..dd572149e --- /dev/null +++ b/staff/debora-garcia/project/app/src/logic/getRandomWorkout.js @@ -0,0 +1,30 @@ +import errors, { SystemError } from "com/errors" +import validate from "com/validate" + +const getRandomWorkout = (workoutType) => { + validate.type(workoutType, "workoutType") + return fetch(`${import.meta.env.VITE_API_URL}/workouts/${workoutType}`, { + method: "GET", + headers: { + Authorization: `Bearer ${sessionStorage.token}` + } + }) + .catch(() => { throw new SystemError("server error") }) + .then(response => { + if (response.status === 200) { + return response.json() + .catch(() => { throw new SystemError("server error") }) + .then(workoutRandom => workoutRandom) + } + return response.json() + .catch(() => { throw new SystemError("server error") }) + .then(body => { + const { error, message } = body + const constructor = errors[error] + throw new constructor(message) + }) + }) +} + + +export default getRandomWorkout \ No newline at end of file diff --git a/staff/debora-garcia/project/app/src/logic/index.js b/staff/debora-garcia/project/app/src/logic/index.js index c23133f8c..aa187be0b 100644 --- a/staff/debora-garcia/project/app/src/logic/index.js +++ b/staff/debora-garcia/project/app/src/logic/index.js @@ -3,6 +3,7 @@ import isUserLoggedIn from "./isUserLoggedIn"; import loginUser from "./loginUser"; import logoutUser from "./logoutUser"; import registerUser from "./registerUser"; +import getRandomWorkout from "./getRandomWorkout"; const logic = { registerUser, @@ -10,6 +11,7 @@ const logic = { getUsername, logoutUser, isUserLoggedIn, + getRandomWorkout, } diff --git a/staff/debora-garcia/project/app/src/views/Achievements.jsx b/staff/debora-garcia/project/app/src/views/Achievements.jsx index e695eca3e..858ab5ccc 100644 --- a/staff/debora-garcia/project/app/src/views/Achievements.jsx +++ b/staff/debora-garcia/project/app/src/views/Achievements.jsx @@ -2,74 +2,12 @@ import { useNavigate, Link } from "react-router-dom" import { useState, useEffect } from "react" import logic from "../logic" -import Footer from "./components/Footer" -import Header from "./components/Header" -import Heading from "../components/Heading" import Button from "../components/Button" -import GoBackButton from "../components/GoBackButton" -export default function Achievements({ onUserLoggedOut }) { +export default function Achievements() { console.log("Achievements ->render") - - const [username, setUsername] = useState("") - const navigate = useNavigate() - const [message, setMessage] = useState(null) - - useEffect(() => { - console.log("Home -> useEffect") - try { - logic.getUsername() - .then((username) => { - console.log("Home -> setUsername") - - setUsername(username) - }) - .catch(error => { - console.error(error) - - setMessage(error.message) - }) - } catch (error) { - console.error(error) - - alert(error.message) - } - }, []) - - const handleGoToFeedClick = () => { - navigate("/feed") - } - - const handleGoToWorkoutClick = () => { - navigate("/workouts") - } - - const handleGoToAchievementClick = () => { - navigate("/achievements") - } - const handleLogout = () => { - logic.logoutUser() - //navigate("/login") - onUserLoggedOut() - - } - - const handlePrintInitialLetter = (username) => { - return username.charAt(0).toUpperCase() - } - - return
-
- ACHIVEVEMENTS -
-
- {handlePrintInitialLetter(username)} -
-
- -
- -