From a8c73cc34d13c97c22c5580228c6f04999b6f4d7 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Sat, 25 Jan 2025 19:44:44 -0500 Subject: [PATCH 01/19] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b2588bc51..206c3941c 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ My groupmembers are: -- XXXX -- XXXX -- XXXX +- Ryan Maazous +- Thomas Marshall +- Jonah Minkoff - XXXX From 217ff27f3be939e95696101b364ad4b78ed90d6a Mon Sep 17 00:00:00 2001 From: Sebastian Date: Sat, 25 Jan 2025 19:48:07 -0500 Subject: [PATCH 02/19] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 206c3941c..701f30c6c 100644 --- a/README.md +++ b/README.md @@ -6,3 +6,4 @@ My groupmembers are: ------------------ Fill in some information about your project under this ------------------ +Our group has decided to work on the Mental Health Support App. From 3a1e4d2f250fec5b45040a5bac8a1f7538f1773a Mon Sep 17 00:00:00 2001 From: Sebastian Date: Sat, 25 Jan 2025 19:48:45 -0500 Subject: [PATCH 03/19] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 701f30c6c..98692b65e 100644 --- a/README.md +++ b/README.md @@ -6,4 +6,4 @@ My groupmembers are: ------------------ Fill in some information about your project under this ------------------ -Our group has decided to work on the Mental Health Support App. +## Our group has decided to work on the Mental Health Support App. From f1db75cf279e593fae2167fe37b8a76f2eceaf81 Mon Sep 17 00:00:00 2001 From: Jonah Minkoff <80793189+JGMink@users.noreply.github.com> Date: Tue, 28 Jan 2025 10:53:55 -0500 Subject: [PATCH 04/19] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 98692b65e..0fdbbc8c4 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ -My groupmembers are: +The groupmembers are: - Ryan Maazous - Thomas Marshall - Jonah Minkoff -- XXXX +- Brady Miller +- Sebastian Alcibar ------------------ Fill in some information about your project under this ------------------ From d81a1d1970d53bca74d52fcecfb1767dcad7f92b Mon Sep 17 00:00:00 2001 From: tlm273623 Date: Sat, 22 Mar 2025 23:36:02 -0400 Subject: [PATCH 05/19] Sprint 1 Commit --- Sprint 1/AI Fitness Project/.gitignore | 4 + Sprint 1/AI Fitness Project/app.py | 87 +++++++++++++++++++ Sprint 1/AI Fitness Project/backend/db.py | 3 + Sprint 1/AI Fitness Project/backend/forms.py | 30 +++++++ Sprint 1/AI Fitness Project/backend/tables.py | 10 +++ Sprint 1/AI Fitness Project/requirements.txt | 51 +++++++++++ .../AI Fitness Project/templates/about.html | 12 +++ .../templates/fitness-log.html | 12 +++ .../AI Fitness Project/templates/index.html | 12 +++ .../AI Fitness Project/templates/login.html | 20 +++++ .../templates/main-chat.html | 12 +++ .../AI Fitness Project/templates/navbar.html | 86 ++++++++++++++++++ .../templates/register.html | 30 +++++++ 13 files changed, 369 insertions(+) create mode 100644 Sprint 1/AI Fitness Project/.gitignore create mode 100644 Sprint 1/AI Fitness Project/app.py create mode 100644 Sprint 1/AI Fitness Project/backend/db.py create mode 100644 Sprint 1/AI Fitness Project/backend/forms.py create mode 100644 Sprint 1/AI Fitness Project/backend/tables.py create mode 100644 Sprint 1/AI Fitness Project/requirements.txt create mode 100644 Sprint 1/AI Fitness Project/templates/about.html create mode 100644 Sprint 1/AI Fitness Project/templates/fitness-log.html create mode 100644 Sprint 1/AI Fitness Project/templates/index.html create mode 100644 Sprint 1/AI Fitness Project/templates/login.html create mode 100644 Sprint 1/AI Fitness Project/templates/main-chat.html create mode 100644 Sprint 1/AI Fitness Project/templates/navbar.html create mode 100644 Sprint 1/AI Fitness Project/templates/register.html diff --git a/Sprint 1/AI Fitness Project/.gitignore b/Sprint 1/AI Fitness Project/.gitignore new file mode 100644 index 000000000..cd6eb6e16 --- /dev/null +++ b/Sprint 1/AI Fitness Project/.gitignore @@ -0,0 +1,4 @@ +.env +database.db +__pycache__/ +venv/ \ No newline at end of file diff --git a/Sprint 1/AI Fitness Project/app.py b/Sprint 1/AI Fitness Project/app.py new file mode 100644 index 000000000..9380ca32f --- /dev/null +++ b/Sprint 1/AI Fitness Project/app.py @@ -0,0 +1,87 @@ +from flask import Flask, render_template +from dotenv import load_dotenv +import os +from backend.db import db +from backend.tables import User +from flask_login import LoginManager, login_required, login_user, logout_user, current_user +from flask import Flask, render_template, redirect, url_for, flash +from flask_bcrypt import Bcrypt +from backend.forms import RegisterForm, LoginForm + +app = Flask(__name__) +load_dotenv() +bcrypt = Bcrypt(app) + +# Handles our SQLite database +app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.db' +app.config['SECRET_KEY'] = os.getenv('FLASK_SECRET_KEY') +db.init_app(app) + +# Handles login verification +login_manager = LoginManager() +login_manager.init_app(app) +login_manager.login_view = "login" +@login_manager.user_loader +def load_user(user_id): + return User.query.get(int(user_id)) + + +# Renders home page +@app.route('/', methods=['GET', 'POST']) +@login_required +def home(): + return render_template('index.html', first_name=current_user.first_name) + + +# Renders fitness log page +@app.route('/fitness-log') +def fitness_log(): + return render_template('fitness-log.html') + +# Renders about page +@app.route('/about') +def about(): + return render_template('about.html') + +# Renders main AI chat page +@app.route('/main-chat') +def main_chat(): + return render_template('main-chat.html') + +# Renders login page +@app.route('/login', methods=['GET', 'POST']) +def login(): + form = LoginForm() + if form.validate_on_submit(): + user = User.query.filter_by(username=form.username.data).first() + if user: + if bcrypt.check_password_hash(user.password, form.password.data): + login_user(user) + return redirect(url_for('home')) + return render_template('login.html', form=form) + +# Handles logout functionality +@app.route('/logout', methods=['GET', 'POST']) +@login_required +def logout(): + logout_user() + return redirect(url_for('login')) + +# Renders register page +@app.route('/register', methods=['GET', 'POST']) +def register(): + form = RegisterForm() + + if form.validate_on_submit(): + hashed_password = bcrypt.generate_password_hash(form.password.data) + new_user = User(username=form.username.data, password=hashed_password, first_name=form.first_name.data, last_name=form.last_name.data) + db.session.add(new_user) + db.session.commit() + return redirect(url_for('login')) + + return render_template('register.html', form=form) + + + +if __name__ == "__main__": + app.run(debug=True) diff --git a/Sprint 1/AI Fitness Project/backend/db.py b/Sprint 1/AI Fitness Project/backend/db.py new file mode 100644 index 000000000..97a5faf13 --- /dev/null +++ b/Sprint 1/AI Fitness Project/backend/db.py @@ -0,0 +1,3 @@ +from flask_sqlalchemy import SQLAlchemy + +db = SQLAlchemy() \ No newline at end of file diff --git a/Sprint 1/AI Fitness Project/backend/forms.py b/Sprint 1/AI Fitness Project/backend/forms.py new file mode 100644 index 000000000..cb54e6eee --- /dev/null +++ b/Sprint 1/AI Fitness Project/backend/forms.py @@ -0,0 +1,30 @@ +from flask_wtf import FlaskForm +from wtforms import StringField, PasswordField, SubmitField +from wtforms.validators import InputRequired, Length, ValidationError +from backend.tables import User + +# Sets up the form on the register page +class RegisterForm(FlaskForm): + username = StringField(validators=[InputRequired(), Length(min=4, max=20)], render_kw={"placeholder": "Username"}) + password = PasswordField(validators=[InputRequired(), Length(min=4, max=20)], render_kw={"placeholder": "Password"}) + first_name = StringField(validators=[InputRequired(), Length(min=1)], render_kw={"placeholder": "First Name"}) + last_name = StringField(validators=[InputRequired(), Length(min=1)], render_kw={"placeholder": "Last Name"}) + + submit = SubmitField("Register") + + def validate_username(self, username): + existing_user = User.query.filter_by( + username=username.data).first() + if existing_user: + raise ValidationError( + "That username already exists." + ) + + +# Sets up form on login page +class LoginForm(FlaskForm): + username = StringField(validators=[InputRequired(), Length(min=4, max=20)], render_kw={"placeholder": "Username"}) + + password = PasswordField(validators=[InputRequired(), Length(min=4, max=20)], render_kw={"placeholder": "Password"}) + + submit = SubmitField("Login") \ No newline at end of file diff --git a/Sprint 1/AI Fitness Project/backend/tables.py b/Sprint 1/AI Fitness Project/backend/tables.py new file mode 100644 index 000000000..c2dd3229c --- /dev/null +++ b/Sprint 1/AI Fitness Project/backend/tables.py @@ -0,0 +1,10 @@ +from backend.db import db +from flask_login import UserMixin + +# Creates our Sqlite table that holds user login/register info. +class User(db.Model, UserMixin): + id = db.Column(db.Integer, primary_key=True) + username = db.Column(db.String(20), nullable=False, unique=True) + password = db.Column(db.String(80), nullable=False) + first_name = db.Column(db.String(20), nullable=False) + last_name = db.Column(db.String(20), nullable=False) \ No newline at end of file diff --git a/Sprint 1/AI Fitness Project/requirements.txt b/Sprint 1/AI Fitness Project/requirements.txt new file mode 100644 index 000000000..2b694b2f8 --- /dev/null +++ b/Sprint 1/AI Fitness Project/requirements.txt @@ -0,0 +1,51 @@ +asttokens==3.0.0 +bcrypt==4.3.0 +blinker==1.9.0 +click==8.1.8 +colorama==0.4.6 +comm==0.2.2 +debugpy==1.8.13 +decorator==5.2.1 +dnspython==2.7.0 +email_validator==2.2.0 +executing==2.2.0 +Flask==3.1.0 +Flask-Bcrypt==1.0.1 +Flask-Login==0.6.3 +Flask-MySQLdb==2.0.0 +Flask-SQLAlchemy==3.1.1 +Flask-WTF==1.2.2 +greenlet==3.1.1 +idna==3.10 +ipykernel==6.29.5 +ipython==9.0.2 +ipython_pygments_lexers==1.1.1 +itsdangerous==2.2.0 +jedi==0.19.2 +Jinja2==3.1.6 +jupyter_client==8.6.3 +jupyter_core==5.7.2 +MarkupSafe==3.0.2 +matplotlib-inline==0.1.7 +mysqlclient==2.2.7 +nest-asyncio==1.6.0 +packaging==24.2 +parso==0.8.4 +platformdirs==4.3.7 +prompt_toolkit==3.0.50 +psutil==7.0.0 +pure_eval==0.2.3 +Pygments==2.19.1 +python-dateutil==2.9.0.post0 +python-dotenv==1.0.1 +pywin32==310 +pyzmq==26.3.0 +six==1.17.0 +SQLAlchemy==2.0.39 +stack-data==0.6.3 +tornado==6.4.2 +traitlets==5.14.3 +typing_extensions==4.12.2 +wcwidth==0.2.13 +Werkzeug==3.1.3 +WTForms==3.2.1 diff --git a/Sprint 1/AI Fitness Project/templates/about.html b/Sprint 1/AI Fitness Project/templates/about.html new file mode 100644 index 000000000..6f6039ed1 --- /dev/null +++ b/Sprint 1/AI Fitness Project/templates/about.html @@ -0,0 +1,12 @@ + + + + + + About + + + {% include 'navbar.html' %} +

About Page

+ + \ No newline at end of file diff --git a/Sprint 1/AI Fitness Project/templates/fitness-log.html b/Sprint 1/AI Fitness Project/templates/fitness-log.html new file mode 100644 index 000000000..011871ec3 --- /dev/null +++ b/Sprint 1/AI Fitness Project/templates/fitness-log.html @@ -0,0 +1,12 @@ + + + + + + Fitness Log + + + {% include 'navbar.html' %} +

Fitness Log

+ + \ No newline at end of file diff --git a/Sprint 1/AI Fitness Project/templates/index.html b/Sprint 1/AI Fitness Project/templates/index.html new file mode 100644 index 000000000..157f0a217 --- /dev/null +++ b/Sprint 1/AI Fitness Project/templates/index.html @@ -0,0 +1,12 @@ + + + + + + Home + + + {% include 'navbar.html' %} +

Welcome, {{ first_name|capitalize }}!

+ + \ No newline at end of file diff --git a/Sprint 1/AI Fitness Project/templates/login.html b/Sprint 1/AI Fitness Project/templates/login.html new file mode 100644 index 000000000..78225206a --- /dev/null +++ b/Sprint 1/AI Fitness Project/templates/login.html @@ -0,0 +1,20 @@ + + + + + + Login Page + + +

Login

+ +
+ {{ form.hidden_tag() }} + {{ form.username }} + {{ form.password }} + {{ form.submit }} +
+ + Don't have an account? Register + + \ No newline at end of file diff --git a/Sprint 1/AI Fitness Project/templates/main-chat.html b/Sprint 1/AI Fitness Project/templates/main-chat.html new file mode 100644 index 000000000..a2b68bd6d --- /dev/null +++ b/Sprint 1/AI Fitness Project/templates/main-chat.html @@ -0,0 +1,12 @@ + + + + + + Main Chat + + + {% include 'navbar.html' %} +

Main AI Chat Page

+ + \ No newline at end of file diff --git a/Sprint 1/AI Fitness Project/templates/navbar.html b/Sprint 1/AI Fitness Project/templates/navbar.html new file mode 100644 index 000000000..222b83484 --- /dev/null +++ b/Sprint 1/AI Fitness Project/templates/navbar.html @@ -0,0 +1,86 @@ + + + + + + Navigation Bar + + + + + + diff --git a/Sprint 1/AI Fitness Project/templates/register.html b/Sprint 1/AI Fitness Project/templates/register.html new file mode 100644 index 000000000..a24e1f4f2 --- /dev/null +++ b/Sprint 1/AI Fitness Project/templates/register.html @@ -0,0 +1,30 @@ + + + + + + Register Page + + +

Register

+ +
+ {{ form.hidden_tag() }} + +
+ {{ form.username }} + {{ form.password }} +
+ +
+ {{ form.first_name }} + {{ form.last_name }} +
+ + + {{ form.submit }} +
+ + Already have an account? Log In + + \ No newline at end of file From aeba003ab56cc68f2648a5dc7cc47709230047df Mon Sep 17 00:00:00 2001 From: JGMink Date: Sun, 23 Mar 2025 19:05:23 -0400 Subject: [PATCH 06/19] dev-container setup Added files necessary to create docker image --- .devcontainer/Dockerfile | 22 ++++++++++++++++++++++ .devcontainer/devcontainer.json | 10 ++++++++++ 2 files changed, 32 insertions(+) create mode 100644 .devcontainer/Dockerfile create mode 100644 .devcontainer/devcontainer.json diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 000000000..2141062fd --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,22 @@ +# Use a Python 3.10 base image (Debian-based) +FROM python:3.10-bullseye + +# Set the working directory inside the container +WORKDIR /app + +# Install Node.js and npm (latest LTS) from NodeSource +RUN apt-get update && apt-get install -y curl && \ + curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - && \ + apt-get install -y nodejs + +# Install additional dependencies (if needed) +RUN apt-get install -y git + +# Copy the application files into the container +COPY . . + +# Expose necessary ports (adjust if needed) +EXPOSE 5000 3000 + +# Set the default command (adjust based on your project setup) +CMD ["bash"] diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000..3f7427c42 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,10 @@ +{ + "name": "AI Fitness Dev Container", + "build": { + "dockerfile": "Dockerfile" + }, + "workspaceFolder": "/workspace", + "mounts": ["source=${localWorkspaceFolder},target=/workspace,type=bind"], + "remoteUser": "vscode" + } + \ No newline at end of file From 716c06806b659559fe228f3f8c4874fdd082585d Mon Sep 17 00:00:00 2001 From: JGMink Date: Sun, 23 Mar 2025 19:24:39 -0400 Subject: [PATCH 07/19] Update Dockerfile Dockerfile now runs in accordance with sprint1 project structure --- .devcontainer/Dockerfile | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 2141062fd..faaa61744 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,22 +1,17 @@ -# Use a Python 3.10 base image (Debian-based) -FROM python:3.10-bullseye +FROM python:3.10-slim -# Set the working directory inside the container -WORKDIR /app +# Set the working directory to the 'backend' folder where app.py and requirements.txt are located +WORKDIR /app/backend -# Install Node.js and npm (latest LTS) from NodeSource -RUN apt-get update && apt-get install -y curl && \ - curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - && \ - apt-get install -y nodejs +# Install Python dependencies from requirements.txt +COPY Sprint\ 1/AI\ Fitness\ Project/backend/requirements.txt ./ +RUN pip install --no-cache-dir -r requirements.txt -# Install additional dependencies (if needed) -RUN apt-get install -y git +# Copy the rest of the backend code +COPY Sprint\ 1/AI\ Fitness\ Project/backend/ ./ -# Copy the application files into the container -COPY . . +# Expose port 5000 (common port for Flask apps) +EXPOSE 5000 -# Expose necessary ports (adjust if needed) -EXPOSE 5000 3000 - -# Set the default command (adjust based on your project setup) -CMD ["bash"] +# Command to run the app +CMD ["python", "app.py"] From 4c63a812fdd0ef95503e126916800027c44200b7 Mon Sep 17 00:00:00 2001 From: JGMink Date: Tue, 25 Mar 2025 15:41:01 -0400 Subject: [PATCH 08/19] Adapted Files for Mac Implementation - Improved Docker files in hopes of later readaptation - Altered app.py to render the tables on run and specify local run port - Added Requirements for mac specific as requirements_mac.txt and specific windows requirements page through rename --- .devcontainer/Dockerfile | 37 ++++++++++---- Sprint 1/AI Fitness Project/app.py | 4 +- .../AI Fitness Project/requirements_mac.txt | 51 +++++++++++++++++++ ...uirements.txt => requirements_windows.txt} | 0 4 files changed, 82 insertions(+), 10 deletions(-) create mode 100644 Sprint 1/AI Fitness Project/requirements_mac.txt rename Sprint 1/AI Fitness Project/{requirements.txt => requirements_windows.txt} (100%) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index faaa61744..a4b6a55f5 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,17 +1,36 @@ +# Use the official Python 3.10 slim image FROM python:3.10-slim -# Set the working directory to the 'backend' folder where app.py and requirements.txt are located -WORKDIR /app/backend +# Set the working directory inside the container +WORKDIR /app + +# Install system dependencies including build tools and MariaDB development files +RUN apt-get update && \ + apt-get install -y \ + build-essential \ + pkg-config \ + python3-dev \ + libmariadb-dev-compat \ + libmariadb-dev \ + && rm -rf /var/lib/apt/lists/* + +# Upgrade pip (optional but recommended) +RUN pip install --upgrade pip + +# Copy the requirements.txt file from the correct relative path into the container +COPY Sprint_1/AI_Fitness_Project/requirements.txt /app/requirements.txt # Install Python dependencies from requirements.txt -COPY Sprint\ 1/AI\ Fitness\ Project/backend/requirements.txt ./ -RUN pip install --no-cache-dir -r requirements.txt +RUN pip install --no-cache-dir -r /app/requirements.txt + +# Copy the rest of your application code into the container +COPY Sprint_1/AI_Fitness_Project /app -# Copy the rest of the backend code -COPY Sprint\ 1/AI\ Fitness\ Project/backend/ ./ +# Set environment variables (using the recommended syntax) +ENV PYTHONUNBUFFERED=1 -# Expose port 5000 (common port for Flask apps) +# Expose the port your app uses (adjust if needed) EXPOSE 5000 -# Command to run the app -CMD ["python", "app.py"] +# Run the application +CMD ["python", "/app/app.py"] diff --git a/Sprint 1/AI Fitness Project/app.py b/Sprint 1/AI Fitness Project/app.py index 9380ca32f..7308e4e25 100644 --- a/Sprint 1/AI Fitness Project/app.py +++ b/Sprint 1/AI Fitness Project/app.py @@ -84,4 +84,6 @@ def register(): if __name__ == "__main__": - app.run(debug=True) + with app.app_context(): + db.create_all() + app.run(debug=True, host="0.0.0.0", port=5000) diff --git a/Sprint 1/AI Fitness Project/requirements_mac.txt b/Sprint 1/AI Fitness Project/requirements_mac.txt new file mode 100644 index 000000000..0c9419795 --- /dev/null +++ b/Sprint 1/AI Fitness Project/requirements_mac.txt @@ -0,0 +1,51 @@ +asttokens==3.0.0 +bcrypt==4.3.0 +blinker==1.9.0 +click==8.1.8 +colorama==0.4.6 +comm==0.2.2 +debugpy==1.8.13 +decorator==5.2.1 +dnspython==2.7.0 +email_validator==2.2.0 +executing==2.2.0 +Flask==3.1.0 +Flask-Bcrypt==1.0.1 +Flask-Login==0.6.3 +Flask-MySQLdb==2.0.0 +Flask-SQLAlchemy==3.1.1 +Flask-WTF==1.2.2 +greenlet==3.1.1 +idna==3.10 +ipykernel==6.29.5 +ipython==8.10.0 +ipython_pygments_lexers==1.1.1 +itsdangerous==2.2.0 +jedi==0.19.2 +Jinja2==3.1.6 +jupyter_client==8.6.3 +jupyter_core==5.7.2 +MarkupSafe==3.0.2 +matplotlib-inline==0.1.7 +PyMySQL==1.0.2 #mysqlclient==2.2.7 +nest-asyncio==1.6.0 +packaging==24.2 +parso==0.8.4 +platformdirs==4.3.7 +prompt_toolkit==3.0.50 +psutil==7.0.0 +pure_eval==0.2.3 +Pygments==2.19.1 +python-dateutil==2.9.0.post0 +python-dotenv==1.0.1 +pywin32==310; sys_platform == "win32" +pyzmq==26.3.0 +six==1.17.0 +SQLAlchemy==2.0.39 +stack-data==0.6.3 +tornado==6.4.2 +traitlets==5.14.3 +typing_extensions==4.12.2 +wcwidth==0.2.13 +Werkzeug==3.1.3 +WTForms==3.2.1 diff --git a/Sprint 1/AI Fitness Project/requirements.txt b/Sprint 1/AI Fitness Project/requirements_windows.txt similarity index 100% rename from Sprint 1/AI Fitness Project/requirements.txt rename to Sprint 1/AI Fitness Project/requirements_windows.txt From 6d5dd212eb52c0f633e9d6498968cb19571ec26b Mon Sep 17 00:00:00 2001 From: Jonah Minkoff <80793189+JGMink@users.noreply.github.com> Date: Tue, 25 Mar 2025 17:06:17 -0400 Subject: [PATCH 09/19] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0fdbbc8c4..4993f3e8d 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ The groupmembers are: +- Sebastian Alcibar - Ryan Maazous - Thomas Marshall - Jonah Minkoff - Brady Miller -- Sebastian Alcibar ------------------ Fill in some information about your project under this ------------------ From 5ece06a07092c5a918a531db76d2b450e52fe179 Mon Sep 17 00:00:00 2001 From: tlm273623 Date: Tue, 25 Mar 2025 18:50:09 -0400 Subject: [PATCH 10/19] Sprint 1 Update - Added functionality to fitness log. - Created survey form. - Display workout goals on main page. - Created separate folders for js scripts and css files. --- Sprint 1/AI Fitness Project/app.py | 46 +++++++--- Sprint 1/AI Fitness Project/backend/forms.py | 46 +++++++++- Sprint 1/AI Fitness Project/backend/tables.py | 8 +- .../static/scripts/fitness-log.js | 9 ++ .../static/styles/fitness-log.css | 26 ++++++ .../static/styles/navbar.css | 65 +++++++++++++ .../templates/fitness-log.html | 64 ++++++++++++- .../AI Fitness Project/templates/index.html | 15 ++- .../AI Fitness Project/templates/navbar.html | 92 ++++--------------- .../AI Fitness Project/templates/survey.html | 23 +++++ 10 files changed, 301 insertions(+), 93 deletions(-) create mode 100644 Sprint 1/AI Fitness Project/static/scripts/fitness-log.js create mode 100644 Sprint 1/AI Fitness Project/static/styles/fitness-log.css create mode 100644 Sprint 1/AI Fitness Project/static/styles/navbar.css create mode 100644 Sprint 1/AI Fitness Project/templates/survey.html diff --git a/Sprint 1/AI Fitness Project/app.py b/Sprint 1/AI Fitness Project/app.py index 7308e4e25..c04a6417d 100644 --- a/Sprint 1/AI Fitness Project/app.py +++ b/Sprint 1/AI Fitness Project/app.py @@ -1,20 +1,20 @@ -from flask import Flask, render_template -from dotenv import load_dotenv +from flask import Flask, render_template, session import os from backend.db import db from backend.tables import User from flask_login import LoginManager, login_required, login_user, logout_user, current_user from flask import Flask, render_template, redirect, url_for, flash from flask_bcrypt import Bcrypt -from backend.forms import RegisterForm, LoginForm +from backend.forms import RegisterForm, LoginForm, SurveyForm, FitnessLogWorkoutForm, FitnessLogCardioForm +from backend.tables import User +import secrets app = Flask(__name__) -load_dotenv() bcrypt = Bcrypt(app) # Handles our SQLite database app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.db' -app.config['SECRET_KEY'] = os.getenv('FLASK_SECRET_KEY') +app.config['SECRET_KEY'] = secrets.token_hex(16) db.init_app(app) # Handles login verification @@ -30,13 +30,21 @@ def load_user(user_id): @app.route('/', methods=['GET', 'POST']) @login_required def home(): - return render_template('index.html', first_name=current_user.first_name) + fitness_goals= current_user.fitness_goals + + if fitness_goals: + fitness_goals_list = fitness_goals.split(",") + else: + fitness_goals_list = None + return render_template('index.html', first_name=current_user.first_name, fitness_goals=fitness_goals_list) # Renders fitness log page -@app.route('/fitness-log') +@app.route('/fitness-log', methods=['GET', 'POST']) def fitness_log(): - return render_template('fitness-log.html') + workout_form = FitnessLogWorkoutForm() + cardio_form = FitnessLogCardioForm() + return render_template('fitness-log.html', workout_form=workout_form, cardio_form=cardio_form) # Renders about page @app.route('/about') @@ -72,18 +80,32 @@ def logout(): def register(): form = RegisterForm() + if form.validate_on_submit(): hashed_password = bcrypt.generate_password_hash(form.password.data) new_user = User(username=form.username.data, password=hashed_password, first_name=form.first_name.data, last_name=form.last_name.data) db.session.add(new_user) db.session.commit() - return redirect(url_for('login')) + login_user(new_user) + return redirect(url_for('survey')) return render_template('register.html', form=form) +@app.route('/survey', methods=['GET', 'POST']) +def survey(): + form = SurveyForm() + + if form.validate_on_submit(): + selected_goals = ",".join(form.fitness_goals.data) + current_user.fitness_goals = selected_goals + db.session.commit() + return redirect(url_for('home')) + + return render_template('survey.html', form=form) + +with app.app_context(): + db.create_all() - if __name__ == "__main__": - with app.app_context(): - db.create_all() + app.run(debug=True, host="0.0.0.0", port=5000) diff --git a/Sprint 1/AI Fitness Project/backend/forms.py b/Sprint 1/AI Fitness Project/backend/forms.py index cb54e6eee..eb6fe2c2f 100644 --- a/Sprint 1/AI Fitness Project/backend/forms.py +++ b/Sprint 1/AI Fitness Project/backend/forms.py @@ -1,6 +1,6 @@ from flask_wtf import FlaskForm -from wtforms import StringField, PasswordField, SubmitField -from wtforms.validators import InputRequired, Length, ValidationError +from wtforms import StringField, PasswordField, SubmitField, SelectMultipleField, widgets, IntegerField, FieldList, FormField, DecimalField +from wtforms.validators import InputRequired, Length, ValidationError, DataRequired, NumberRange from backend.tables import User # Sets up the form on the register page @@ -27,4 +27,44 @@ class LoginForm(FlaskForm): password = PasswordField(validators=[InputRequired(), Length(min=4, max=20)], render_kw={"placeholder": "Password"}) - submit = SubmitField("Login") \ No newline at end of file + submit = SubmitField("Login") + + +class SurveyForm(FlaskForm): + fitness_goals = SelectMultipleField( + "What are your fitness goals?", + choices=[ + ("Build Muscle", "Build Muscle"), + ("Lose Weight", "Lose Weight"), + ("Increase Strength", "Increase Strength"), + ("Improve Cardio", "Improve Cardio") + ], + option_widget=widgets.CheckboxInput(), + widget=widgets.ListWidget(prefix_label=False) + ) + + submit = SubmitField("Submit") + + +class FitnessLogWorkoutForm(FlaskForm): + legs_reps = IntegerField('Total Reps', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")]) + legs_sets = IntegerField('Total Sets', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")]) + + chest_reps = IntegerField('Total Reps', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")]) + chest_sets = IntegerField('Total Sets', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")]) + + back_reps = IntegerField('Total Reps', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")]) + back_sets = IntegerField('Total Sets', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")]) + + bicep_reps = IntegerField('Total Reps', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")]) + bicep_sets = IntegerField('Total Sets', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")]) + + tricep_reps = IntegerField('Total Reps', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")]) + tricep_sets = IntegerField('Total Sets', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")]) + + submit = SubmitField("Submit") + +class FitnessLogCardioForm(FlaskForm): + miles = DecimalField('Total Miles', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")]) + + submit = SubmitField("Submit") \ No newline at end of file diff --git a/Sprint 1/AI Fitness Project/backend/tables.py b/Sprint 1/AI Fitness Project/backend/tables.py index c2dd3229c..c8de3faa1 100644 --- a/Sprint 1/AI Fitness Project/backend/tables.py +++ b/Sprint 1/AI Fitness Project/backend/tables.py @@ -7,4 +7,10 @@ class User(db.Model, UserMixin): username = db.Column(db.String(20), nullable=False, unique=True) password = db.Column(db.String(80), nullable=False) first_name = db.Column(db.String(20), nullable=False) - last_name = db.Column(db.String(20), nullable=False) \ No newline at end of file + last_name = db.Column(db.String(20), nullable=False) + fitness_goals = db.Column(db.String(255), nullable=True) + +class FitnessLogWorkout(db.Model): + id = db.Column(db.Integer, primary_key=True) + + diff --git a/Sprint 1/AI Fitness Project/static/scripts/fitness-log.js b/Sprint 1/AI Fitness Project/static/scripts/fitness-log.js new file mode 100644 index 000000000..1b949e0dd --- /dev/null +++ b/Sprint 1/AI Fitness Project/static/scripts/fitness-log.js @@ -0,0 +1,9 @@ +function toggleWorkoutForm() { + const form = document.getElementById('workout-form'); + form.style.display = (form.style.display === 'none' || form.style.display === '') ? 'block' : 'none'; +} + +function toggleCardioForm() { + const form = document.getElementById('cardio-form'); + form.style.display = (form.style.display === 'none' || form.style.display === '') ? 'block' : 'none'; +} \ No newline at end of file diff --git a/Sprint 1/AI Fitness Project/static/styles/fitness-log.css b/Sprint 1/AI Fitness Project/static/styles/fitness-log.css new file mode 100644 index 000000000..6621768a8 --- /dev/null +++ b/Sprint 1/AI Fitness Project/static/styles/fitness-log.css @@ -0,0 +1,26 @@ +.forms-wrapper { + display: flex; + gap: 20px; + justify-content: space-between; +} + +.workout-form, .cardio-form { + width: 48%; + padding-left: 10px; +} + +#workout-form, #cardio-form { + display: none; +} + +button { + margin-bottom: 15px; +} + +label { + margin-left: 10px; +} + +#submit-button { + padding-top: 20px; +} diff --git a/Sprint 1/AI Fitness Project/static/styles/navbar.css b/Sprint 1/AI Fitness Project/static/styles/navbar.css new file mode 100644 index 000000000..22a5a8cbf --- /dev/null +++ b/Sprint 1/AI Fitness Project/static/styles/navbar.css @@ -0,0 +1,65 @@ +html, body{ + margin: 0; + padding: 0; +} +#navbar { + * { + text-decoration: none; + padding: 0; + margin: 0; + box-sizing: border-box; + } + .navbar { + background: gray; + font-family: calibri; + padding: 10px 20px; + } + .navdiv { + display: flex; + align-items: center; + justify-content: space-between; + } + .logo a { + color: white; + font-size: 21px; + font-weight: bold; + } + ul { + display: flex; + list-style: none; + padding: 0; + } + li { + margin-right: 38px; + } + li a { + color: white; + font-size: 25px; + font-weight: bold; + } + li a:hover{ + color: lightgray; + } + .buttons { + display: flex; + gap: 10px; + } + button { + background-color: black; + border: none; + border-radius: 10px; + padding: 10px; + width: 90px; + cursor: pointer; + } + button a { + color: white; + font-weight: bold; + font-size: 15px; + display: block; + text-align: center; + } + button a:hover{ + color:lightgray; + } +} diff --git a/Sprint 1/AI Fitness Project/templates/fitness-log.html b/Sprint 1/AI Fitness Project/templates/fitness-log.html index 011871ec3..696126f5e 100644 --- a/Sprint 1/AI Fitness Project/templates/fitness-log.html +++ b/Sprint 1/AI Fitness Project/templates/fitness-log.html @@ -4,9 +4,71 @@ Fitness Log + {% include 'navbar.html' %}

Fitness Log

+ +
+
+ + +
+ {{ workout_form.hidden_tag() }} +
+

Legs

+ + {{ workout_form.legs_reps }} + + {{ workout_form.legs_sets }} +
+
+

Back

+ + {{ workout_form.back_reps }} + + {{ workout_form.back_sets }} +
+
+

Chest

+ + {{ workout_form.chest_reps }} + + {{ workout_form.chest_sets }} +
+
+

Tricep

+ + {{ workout_form.tricep_reps }} + + {{ workout_form.tricep_sets }} +
+
+

Bicep

+ + {{ workout_form.bicep_reps }} + + {{ workout_form.bicep_sets }} +
+
{{ workout_form.submit }}
+
+
+ +
+ + +
+ {{ cardio_form.hidden_tag() }} +
+ + {{ cardio_form.miles }} +
+
{{ cardio_form.submit }}
+
+
+
+ + - \ No newline at end of file + diff --git a/Sprint 1/AI Fitness Project/templates/index.html b/Sprint 1/AI Fitness Project/templates/index.html index 157f0a217..863610483 100644 --- a/Sprint 1/AI Fitness Project/templates/index.html +++ b/Sprint 1/AI Fitness Project/templates/index.html @@ -7,6 +7,19 @@ {% include 'navbar.html' %} -

Welcome, {{ first_name|capitalize }}!

+

Welcome, {{ first_name|capitalize }}!

+

Your Fitness Goals:

+
    + {% if fitness_goals %} + {% for goal in fitness_goals %} + +
  • + {{ goal }} +
  • + {% endfor %} + {% else %} +

    No fitness goals set.

    + {% endif %} +
\ No newline at end of file diff --git a/Sprint 1/AI Fitness Project/templates/navbar.html b/Sprint 1/AI Fitness Project/templates/navbar.html index 222b83484..5e1397826 100644 --- a/Sprint 1/AI Fitness Project/templates/navbar.html +++ b/Sprint 1/AI Fitness Project/templates/navbar.html @@ -4,83 +4,25 @@ Navigation Bar - + - + + + diff --git a/Sprint 1/AI Fitness Project/templates/survey.html b/Sprint 1/AI Fitness Project/templates/survey.html new file mode 100644 index 000000000..763bc7ef9 --- /dev/null +++ b/Sprint 1/AI Fitness Project/templates/survey.html @@ -0,0 +1,23 @@ + + + + + + Document + + +

Fitness Survey: What are your goals?

+ +
+ {{ form.hidden_tag() }} +

{{ form.fitness_goals.label }}

+ {% for subfield in form.fitness_goals %} +
+ {{ subfield }} {{ subfield.label }} +
+ {% endfor %} +
+ {{ form.submit() }} +
+ + \ No newline at end of file From 6fe1bf393d272e5b41b018bf4c82319eafd85956 Mon Sep 17 00:00:00 2001 From: tlm273623 Date: Wed, 26 Mar 2025 21:34:16 -0400 Subject: [PATCH 11/19] Sprint-1 Test Case - Created test cases for login. --- Sprint 1/AI Fitness Project/app.py | 1 + Sprint 1/AI Fitness Project/backend/tables.py | 3 +- Sprint 1/AI Fitness Project/login_test.py | 41 +++++++++++++++++++ 3 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 Sprint 1/AI Fitness Project/login_test.py diff --git a/Sprint 1/AI Fitness Project/app.py b/Sprint 1/AI Fitness Project/app.py index c04a6417d..ee287da0f 100644 --- a/Sprint 1/AI Fitness Project/app.py +++ b/Sprint 1/AI Fitness Project/app.py @@ -9,6 +9,7 @@ from backend.tables import User import secrets + app = Flask(__name__) bcrypt = Bcrypt(app) diff --git a/Sprint 1/AI Fitness Project/backend/tables.py b/Sprint 1/AI Fitness Project/backend/tables.py index c8de3faa1..429ba7f9c 100644 --- a/Sprint 1/AI Fitness Project/backend/tables.py +++ b/Sprint 1/AI Fitness Project/backend/tables.py @@ -10,7 +10,6 @@ class User(db.Model, UserMixin): last_name = db.Column(db.String(20), nullable=False) fitness_goals = db.Column(db.String(255), nullable=True) -class FitnessLogWorkout(db.Model): - id = db.Column(db.Integer, primary_key=True) + diff --git a/Sprint 1/AI Fitness Project/login_test.py b/Sprint 1/AI Fitness Project/login_test.py new file mode 100644 index 000000000..3e25affcc --- /dev/null +++ b/Sprint 1/AI Fitness Project/login_test.py @@ -0,0 +1,41 @@ +import requests +from bs4 import BeautifulSoup + + +base_url = "http://localhost:5000" +login_url = f"{base_url}/login" +home_url = f"{base_url}/home" + +test_username = 'test' +test_password = 'test' + +session = requests.Session() + +login_page = session.get(login_url) + +soup = BeautifulSoup(login_page.text, 'html.parser') + +csrf_token = soup.find('input', {'name': 'csrf_token'})['value'] + +login_data = { + 'csrf_token': csrf_token, + 'username': test_username, + 'password': test_password, + 'submit': 'Login' +} + +login_response = session.post(login_url, data=login_data) + +print("\nLogin Response Status Code:", login_response.status_code) + +if login_response.status_code == 200: + if "Welcome" in login_response.text: + print("Login test passed.") + elif "Invalid username or password" in login_response.text: + print("Login failed. Invalid username or password.") + else: + print("Login failed with status code 200 but no error message found.") +else: + print("Login failed. Status code:", login_response.status_code) + print("Response Content:") + print(login_response.text) From 29945c446cd4c3f7d1dcc410eb5ac065e11bf8de Mon Sep 17 00:00:00 2001 From: tlm273623 Date: Fri, 28 Mar 2025 17:25:05 -0400 Subject: [PATCH 12/19] Sprint-2 - Copying project to sprint 2. --- Sprint 2/AI Fitness Project/.gitignore | 4 + Sprint 2/AI Fitness Project/app.py | 112 ++++++++++++++++++ Sprint 2/AI Fitness Project/backend/db.py | 3 + Sprint 2/AI Fitness Project/backend/forms.py | 70 +++++++++++ Sprint 2/AI Fitness Project/backend/tables.py | 15 +++ Sprint 2/AI Fitness Project/login_test.py | 41 +++++++ .../AI Fitness Project/requirements_mac.txt | 51 ++++++++ .../requirements_windows.txt | 51 ++++++++ .../static/scripts/fitness-log.js | 9 ++ .../static/styles/fitness-log.css | 26 ++++ .../static/styles/navbar.css | 65 ++++++++++ .../AI Fitness Project/templates/about.html | 12 ++ .../templates/fitness-log.html | 74 ++++++++++++ .../AI Fitness Project/templates/index.html | 25 ++++ .../AI Fitness Project/templates/login.html | 20 ++++ .../templates/main-chat.html | 12 ++ .../AI Fitness Project/templates/navbar.html | 28 +++++ .../templates/register.html | 30 +++++ .../AI Fitness Project/templates/survey.html | 23 ++++ 19 files changed, 671 insertions(+) create mode 100644 Sprint 2/AI Fitness Project/.gitignore create mode 100644 Sprint 2/AI Fitness Project/app.py create mode 100644 Sprint 2/AI Fitness Project/backend/db.py create mode 100644 Sprint 2/AI Fitness Project/backend/forms.py create mode 100644 Sprint 2/AI Fitness Project/backend/tables.py create mode 100644 Sprint 2/AI Fitness Project/login_test.py create mode 100644 Sprint 2/AI Fitness Project/requirements_mac.txt create mode 100644 Sprint 2/AI Fitness Project/requirements_windows.txt create mode 100644 Sprint 2/AI Fitness Project/static/scripts/fitness-log.js create mode 100644 Sprint 2/AI Fitness Project/static/styles/fitness-log.css create mode 100644 Sprint 2/AI Fitness Project/static/styles/navbar.css create mode 100644 Sprint 2/AI Fitness Project/templates/about.html create mode 100644 Sprint 2/AI Fitness Project/templates/fitness-log.html create mode 100644 Sprint 2/AI Fitness Project/templates/index.html create mode 100644 Sprint 2/AI Fitness Project/templates/login.html create mode 100644 Sprint 2/AI Fitness Project/templates/main-chat.html create mode 100644 Sprint 2/AI Fitness Project/templates/navbar.html create mode 100644 Sprint 2/AI Fitness Project/templates/register.html create mode 100644 Sprint 2/AI Fitness Project/templates/survey.html diff --git a/Sprint 2/AI Fitness Project/.gitignore b/Sprint 2/AI Fitness Project/.gitignore new file mode 100644 index 000000000..cd6eb6e16 --- /dev/null +++ b/Sprint 2/AI Fitness Project/.gitignore @@ -0,0 +1,4 @@ +.env +database.db +__pycache__/ +venv/ \ No newline at end of file diff --git a/Sprint 2/AI Fitness Project/app.py b/Sprint 2/AI Fitness Project/app.py new file mode 100644 index 000000000..ee287da0f --- /dev/null +++ b/Sprint 2/AI Fitness Project/app.py @@ -0,0 +1,112 @@ +from flask import Flask, render_template, session +import os +from backend.db import db +from backend.tables import User +from flask_login import LoginManager, login_required, login_user, logout_user, current_user +from flask import Flask, render_template, redirect, url_for, flash +from flask_bcrypt import Bcrypt +from backend.forms import RegisterForm, LoginForm, SurveyForm, FitnessLogWorkoutForm, FitnessLogCardioForm +from backend.tables import User +import secrets + + +app = Flask(__name__) +bcrypt = Bcrypt(app) + +# Handles our SQLite database +app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.db' +app.config['SECRET_KEY'] = secrets.token_hex(16) +db.init_app(app) + +# Handles login verification +login_manager = LoginManager() +login_manager.init_app(app) +login_manager.login_view = "login" +@login_manager.user_loader +def load_user(user_id): + return User.query.get(int(user_id)) + + +# Renders home page +@app.route('/', methods=['GET', 'POST']) +@login_required +def home(): + fitness_goals= current_user.fitness_goals + + if fitness_goals: + fitness_goals_list = fitness_goals.split(",") + else: + fitness_goals_list = None + return render_template('index.html', first_name=current_user.first_name, fitness_goals=fitness_goals_list) + + +# Renders fitness log page +@app.route('/fitness-log', methods=['GET', 'POST']) +def fitness_log(): + workout_form = FitnessLogWorkoutForm() + cardio_form = FitnessLogCardioForm() + return render_template('fitness-log.html', workout_form=workout_form, cardio_form=cardio_form) + +# Renders about page +@app.route('/about') +def about(): + return render_template('about.html') + +# Renders main AI chat page +@app.route('/main-chat') +def main_chat(): + return render_template('main-chat.html') + +# Renders login page +@app.route('/login', methods=['GET', 'POST']) +def login(): + form = LoginForm() + if form.validate_on_submit(): + user = User.query.filter_by(username=form.username.data).first() + if user: + if bcrypt.check_password_hash(user.password, form.password.data): + login_user(user) + return redirect(url_for('home')) + return render_template('login.html', form=form) + +# Handles logout functionality +@app.route('/logout', methods=['GET', 'POST']) +@login_required +def logout(): + logout_user() + return redirect(url_for('login')) + +# Renders register page +@app.route('/register', methods=['GET', 'POST']) +def register(): + form = RegisterForm() + + + if form.validate_on_submit(): + hashed_password = bcrypt.generate_password_hash(form.password.data) + new_user = User(username=form.username.data, password=hashed_password, first_name=form.first_name.data, last_name=form.last_name.data) + db.session.add(new_user) + db.session.commit() + login_user(new_user) + return redirect(url_for('survey')) + + return render_template('register.html', form=form) + +@app.route('/survey', methods=['GET', 'POST']) +def survey(): + form = SurveyForm() + + if form.validate_on_submit(): + selected_goals = ",".join(form.fitness_goals.data) + current_user.fitness_goals = selected_goals + db.session.commit() + return redirect(url_for('home')) + + return render_template('survey.html', form=form) + +with app.app_context(): + db.create_all() + +if __name__ == "__main__": + + app.run(debug=True, host="0.0.0.0", port=5000) diff --git a/Sprint 2/AI Fitness Project/backend/db.py b/Sprint 2/AI Fitness Project/backend/db.py new file mode 100644 index 000000000..97a5faf13 --- /dev/null +++ b/Sprint 2/AI Fitness Project/backend/db.py @@ -0,0 +1,3 @@ +from flask_sqlalchemy import SQLAlchemy + +db = SQLAlchemy() \ No newline at end of file diff --git a/Sprint 2/AI Fitness Project/backend/forms.py b/Sprint 2/AI Fitness Project/backend/forms.py new file mode 100644 index 000000000..eb6fe2c2f --- /dev/null +++ b/Sprint 2/AI Fitness Project/backend/forms.py @@ -0,0 +1,70 @@ +from flask_wtf import FlaskForm +from wtforms import StringField, PasswordField, SubmitField, SelectMultipleField, widgets, IntegerField, FieldList, FormField, DecimalField +from wtforms.validators import InputRequired, Length, ValidationError, DataRequired, NumberRange +from backend.tables import User + +# Sets up the form on the register page +class RegisterForm(FlaskForm): + username = StringField(validators=[InputRequired(), Length(min=4, max=20)], render_kw={"placeholder": "Username"}) + password = PasswordField(validators=[InputRequired(), Length(min=4, max=20)], render_kw={"placeholder": "Password"}) + first_name = StringField(validators=[InputRequired(), Length(min=1)], render_kw={"placeholder": "First Name"}) + last_name = StringField(validators=[InputRequired(), Length(min=1)], render_kw={"placeholder": "Last Name"}) + + submit = SubmitField("Register") + + def validate_username(self, username): + existing_user = User.query.filter_by( + username=username.data).first() + if existing_user: + raise ValidationError( + "That username already exists." + ) + + +# Sets up form on login page +class LoginForm(FlaskForm): + username = StringField(validators=[InputRequired(), Length(min=4, max=20)], render_kw={"placeholder": "Username"}) + + password = PasswordField(validators=[InputRequired(), Length(min=4, max=20)], render_kw={"placeholder": "Password"}) + + submit = SubmitField("Login") + + +class SurveyForm(FlaskForm): + fitness_goals = SelectMultipleField( + "What are your fitness goals?", + choices=[ + ("Build Muscle", "Build Muscle"), + ("Lose Weight", "Lose Weight"), + ("Increase Strength", "Increase Strength"), + ("Improve Cardio", "Improve Cardio") + ], + option_widget=widgets.CheckboxInput(), + widget=widgets.ListWidget(prefix_label=False) + ) + + submit = SubmitField("Submit") + + +class FitnessLogWorkoutForm(FlaskForm): + legs_reps = IntegerField('Total Reps', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")]) + legs_sets = IntegerField('Total Sets', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")]) + + chest_reps = IntegerField('Total Reps', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")]) + chest_sets = IntegerField('Total Sets', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")]) + + back_reps = IntegerField('Total Reps', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")]) + back_sets = IntegerField('Total Sets', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")]) + + bicep_reps = IntegerField('Total Reps', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")]) + bicep_sets = IntegerField('Total Sets', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")]) + + tricep_reps = IntegerField('Total Reps', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")]) + tricep_sets = IntegerField('Total Sets', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")]) + + submit = SubmitField("Submit") + +class FitnessLogCardioForm(FlaskForm): + miles = DecimalField('Total Miles', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")]) + + submit = SubmitField("Submit") \ No newline at end of file diff --git a/Sprint 2/AI Fitness Project/backend/tables.py b/Sprint 2/AI Fitness Project/backend/tables.py new file mode 100644 index 000000000..429ba7f9c --- /dev/null +++ b/Sprint 2/AI Fitness Project/backend/tables.py @@ -0,0 +1,15 @@ +from backend.db import db +from flask_login import UserMixin + +# Creates our Sqlite table that holds user login/register info. +class User(db.Model, UserMixin): + id = db.Column(db.Integer, primary_key=True) + username = db.Column(db.String(20), nullable=False, unique=True) + password = db.Column(db.String(80), nullable=False) + first_name = db.Column(db.String(20), nullable=False) + last_name = db.Column(db.String(20), nullable=False) + fitness_goals = db.Column(db.String(255), nullable=True) + + + + diff --git a/Sprint 2/AI Fitness Project/login_test.py b/Sprint 2/AI Fitness Project/login_test.py new file mode 100644 index 000000000..3e25affcc --- /dev/null +++ b/Sprint 2/AI Fitness Project/login_test.py @@ -0,0 +1,41 @@ +import requests +from bs4 import BeautifulSoup + + +base_url = "http://localhost:5000" +login_url = f"{base_url}/login" +home_url = f"{base_url}/home" + +test_username = 'test' +test_password = 'test' + +session = requests.Session() + +login_page = session.get(login_url) + +soup = BeautifulSoup(login_page.text, 'html.parser') + +csrf_token = soup.find('input', {'name': 'csrf_token'})['value'] + +login_data = { + 'csrf_token': csrf_token, + 'username': test_username, + 'password': test_password, + 'submit': 'Login' +} + +login_response = session.post(login_url, data=login_data) + +print("\nLogin Response Status Code:", login_response.status_code) + +if login_response.status_code == 200: + if "Welcome" in login_response.text: + print("Login test passed.") + elif "Invalid username or password" in login_response.text: + print("Login failed. Invalid username or password.") + else: + print("Login failed with status code 200 but no error message found.") +else: + print("Login failed. Status code:", login_response.status_code) + print("Response Content:") + print(login_response.text) diff --git a/Sprint 2/AI Fitness Project/requirements_mac.txt b/Sprint 2/AI Fitness Project/requirements_mac.txt new file mode 100644 index 000000000..0c9419795 --- /dev/null +++ b/Sprint 2/AI Fitness Project/requirements_mac.txt @@ -0,0 +1,51 @@ +asttokens==3.0.0 +bcrypt==4.3.0 +blinker==1.9.0 +click==8.1.8 +colorama==0.4.6 +comm==0.2.2 +debugpy==1.8.13 +decorator==5.2.1 +dnspython==2.7.0 +email_validator==2.2.0 +executing==2.2.0 +Flask==3.1.0 +Flask-Bcrypt==1.0.1 +Flask-Login==0.6.3 +Flask-MySQLdb==2.0.0 +Flask-SQLAlchemy==3.1.1 +Flask-WTF==1.2.2 +greenlet==3.1.1 +idna==3.10 +ipykernel==6.29.5 +ipython==8.10.0 +ipython_pygments_lexers==1.1.1 +itsdangerous==2.2.0 +jedi==0.19.2 +Jinja2==3.1.6 +jupyter_client==8.6.3 +jupyter_core==5.7.2 +MarkupSafe==3.0.2 +matplotlib-inline==0.1.7 +PyMySQL==1.0.2 #mysqlclient==2.2.7 +nest-asyncio==1.6.0 +packaging==24.2 +parso==0.8.4 +platformdirs==4.3.7 +prompt_toolkit==3.0.50 +psutil==7.0.0 +pure_eval==0.2.3 +Pygments==2.19.1 +python-dateutil==2.9.0.post0 +python-dotenv==1.0.1 +pywin32==310; sys_platform == "win32" +pyzmq==26.3.0 +six==1.17.0 +SQLAlchemy==2.0.39 +stack-data==0.6.3 +tornado==6.4.2 +traitlets==5.14.3 +typing_extensions==4.12.2 +wcwidth==0.2.13 +Werkzeug==3.1.3 +WTForms==3.2.1 diff --git a/Sprint 2/AI Fitness Project/requirements_windows.txt b/Sprint 2/AI Fitness Project/requirements_windows.txt new file mode 100644 index 000000000..2b694b2f8 --- /dev/null +++ b/Sprint 2/AI Fitness Project/requirements_windows.txt @@ -0,0 +1,51 @@ +asttokens==3.0.0 +bcrypt==4.3.0 +blinker==1.9.0 +click==8.1.8 +colorama==0.4.6 +comm==0.2.2 +debugpy==1.8.13 +decorator==5.2.1 +dnspython==2.7.0 +email_validator==2.2.0 +executing==2.2.0 +Flask==3.1.0 +Flask-Bcrypt==1.0.1 +Flask-Login==0.6.3 +Flask-MySQLdb==2.0.0 +Flask-SQLAlchemy==3.1.1 +Flask-WTF==1.2.2 +greenlet==3.1.1 +idna==3.10 +ipykernel==6.29.5 +ipython==9.0.2 +ipython_pygments_lexers==1.1.1 +itsdangerous==2.2.0 +jedi==0.19.2 +Jinja2==3.1.6 +jupyter_client==8.6.3 +jupyter_core==5.7.2 +MarkupSafe==3.0.2 +matplotlib-inline==0.1.7 +mysqlclient==2.2.7 +nest-asyncio==1.6.0 +packaging==24.2 +parso==0.8.4 +platformdirs==4.3.7 +prompt_toolkit==3.0.50 +psutil==7.0.0 +pure_eval==0.2.3 +Pygments==2.19.1 +python-dateutil==2.9.0.post0 +python-dotenv==1.0.1 +pywin32==310 +pyzmq==26.3.0 +six==1.17.0 +SQLAlchemy==2.0.39 +stack-data==0.6.3 +tornado==6.4.2 +traitlets==5.14.3 +typing_extensions==4.12.2 +wcwidth==0.2.13 +Werkzeug==3.1.3 +WTForms==3.2.1 diff --git a/Sprint 2/AI Fitness Project/static/scripts/fitness-log.js b/Sprint 2/AI Fitness Project/static/scripts/fitness-log.js new file mode 100644 index 000000000..1b949e0dd --- /dev/null +++ b/Sprint 2/AI Fitness Project/static/scripts/fitness-log.js @@ -0,0 +1,9 @@ +function toggleWorkoutForm() { + const form = document.getElementById('workout-form'); + form.style.display = (form.style.display === 'none' || form.style.display === '') ? 'block' : 'none'; +} + +function toggleCardioForm() { + const form = document.getElementById('cardio-form'); + form.style.display = (form.style.display === 'none' || form.style.display === '') ? 'block' : 'none'; +} \ No newline at end of file diff --git a/Sprint 2/AI Fitness Project/static/styles/fitness-log.css b/Sprint 2/AI Fitness Project/static/styles/fitness-log.css new file mode 100644 index 000000000..6621768a8 --- /dev/null +++ b/Sprint 2/AI Fitness Project/static/styles/fitness-log.css @@ -0,0 +1,26 @@ +.forms-wrapper { + display: flex; + gap: 20px; + justify-content: space-between; +} + +.workout-form, .cardio-form { + width: 48%; + padding-left: 10px; +} + +#workout-form, #cardio-form { + display: none; +} + +button { + margin-bottom: 15px; +} + +label { + margin-left: 10px; +} + +#submit-button { + padding-top: 20px; +} diff --git a/Sprint 2/AI Fitness Project/static/styles/navbar.css b/Sprint 2/AI Fitness Project/static/styles/navbar.css new file mode 100644 index 000000000..22a5a8cbf --- /dev/null +++ b/Sprint 2/AI Fitness Project/static/styles/navbar.css @@ -0,0 +1,65 @@ +html, body{ + margin: 0; + padding: 0; +} +#navbar { + * { + text-decoration: none; + padding: 0; + margin: 0; + box-sizing: border-box; + } + .navbar { + background: gray; + font-family: calibri; + padding: 10px 20px; + } + .navdiv { + display: flex; + align-items: center; + justify-content: space-between; + } + .logo a { + color: white; + font-size: 21px; + font-weight: bold; + } + ul { + display: flex; + list-style: none; + padding: 0; + } + li { + margin-right: 38px; + } + li a { + color: white; + font-size: 25px; + font-weight: bold; + } + li a:hover{ + color: lightgray; + } + .buttons { + display: flex; + gap: 10px; + } + button { + background-color: black; + border: none; + border-radius: 10px; + padding: 10px; + width: 90px; + cursor: pointer; + } + button a { + color: white; + font-weight: bold; + font-size: 15px; + display: block; + text-align: center; + } + button a:hover{ + color:lightgray; + } +} diff --git a/Sprint 2/AI Fitness Project/templates/about.html b/Sprint 2/AI Fitness Project/templates/about.html new file mode 100644 index 000000000..6f6039ed1 --- /dev/null +++ b/Sprint 2/AI Fitness Project/templates/about.html @@ -0,0 +1,12 @@ + + + + + + About + + + {% include 'navbar.html' %} +

About Page

+ + \ No newline at end of file diff --git a/Sprint 2/AI Fitness Project/templates/fitness-log.html b/Sprint 2/AI Fitness Project/templates/fitness-log.html new file mode 100644 index 000000000..696126f5e --- /dev/null +++ b/Sprint 2/AI Fitness Project/templates/fitness-log.html @@ -0,0 +1,74 @@ + + + + + + Fitness Log + + + + {% include 'navbar.html' %} +

Fitness Log

+ +
+
+ + +
+ {{ workout_form.hidden_tag() }} +
+

Legs

+ + {{ workout_form.legs_reps }} + + {{ workout_form.legs_sets }} +
+
+

Back

+ + {{ workout_form.back_reps }} + + {{ workout_form.back_sets }} +
+
+

Chest

+ + {{ workout_form.chest_reps }} + + {{ workout_form.chest_sets }} +
+
+

Tricep

+ + {{ workout_form.tricep_reps }} + + {{ workout_form.tricep_sets }} +
+
+

Bicep

+ + {{ workout_form.bicep_reps }} + + {{ workout_form.bicep_sets }} +
+
{{ workout_form.submit }}
+
+
+ +
+ + +
+ {{ cardio_form.hidden_tag() }} +
+ + {{ cardio_form.miles }} +
+
{{ cardio_form.submit }}
+
+
+
+ + + + diff --git a/Sprint 2/AI Fitness Project/templates/index.html b/Sprint 2/AI Fitness Project/templates/index.html new file mode 100644 index 000000000..863610483 --- /dev/null +++ b/Sprint 2/AI Fitness Project/templates/index.html @@ -0,0 +1,25 @@ + + + + + + Home + + + {% include 'navbar.html' %} +

Welcome, {{ first_name|capitalize }}!

+

Your Fitness Goals:

+
    + {% if fitness_goals %} + {% for goal in fitness_goals %} + +
  • + {{ goal }} +
  • + {% endfor %} + {% else %} +

    No fitness goals set.

    + {% endif %} +
+ + \ No newline at end of file diff --git a/Sprint 2/AI Fitness Project/templates/login.html b/Sprint 2/AI Fitness Project/templates/login.html new file mode 100644 index 000000000..78225206a --- /dev/null +++ b/Sprint 2/AI Fitness Project/templates/login.html @@ -0,0 +1,20 @@ + + + + + + Login Page + + +

Login

+ +
+ {{ form.hidden_tag() }} + {{ form.username }} + {{ form.password }} + {{ form.submit }} +
+ + Don't have an account? Register + + \ No newline at end of file diff --git a/Sprint 2/AI Fitness Project/templates/main-chat.html b/Sprint 2/AI Fitness Project/templates/main-chat.html new file mode 100644 index 000000000..a2b68bd6d --- /dev/null +++ b/Sprint 2/AI Fitness Project/templates/main-chat.html @@ -0,0 +1,12 @@ + + + + + + Main Chat + + + {% include 'navbar.html' %} +

Main AI Chat Page

+ + \ No newline at end of file diff --git a/Sprint 2/AI Fitness Project/templates/navbar.html b/Sprint 2/AI Fitness Project/templates/navbar.html new file mode 100644 index 000000000..5e1397826 --- /dev/null +++ b/Sprint 2/AI Fitness Project/templates/navbar.html @@ -0,0 +1,28 @@ + + + + + + Navigation Bar + + + + + + + diff --git a/Sprint 2/AI Fitness Project/templates/register.html b/Sprint 2/AI Fitness Project/templates/register.html new file mode 100644 index 000000000..a24e1f4f2 --- /dev/null +++ b/Sprint 2/AI Fitness Project/templates/register.html @@ -0,0 +1,30 @@ + + + + + + Register Page + + +

Register

+ +
+ {{ form.hidden_tag() }} + +
+ {{ form.username }} + {{ form.password }} +
+ +
+ {{ form.first_name }} + {{ form.last_name }} +
+ + + {{ form.submit }} +
+ + Already have an account? Log In + + \ No newline at end of file diff --git a/Sprint 2/AI Fitness Project/templates/survey.html b/Sprint 2/AI Fitness Project/templates/survey.html new file mode 100644 index 000000000..763bc7ef9 --- /dev/null +++ b/Sprint 2/AI Fitness Project/templates/survey.html @@ -0,0 +1,23 @@ + + + + + + Document + + +

Fitness Survey: What are your goals?

+ +
+ {{ form.hidden_tag() }} +

{{ form.fitness_goals.label }}

+ {% for subfield in form.fitness_goals %} +
+ {{ subfield }} {{ subfield.label }} +
+ {% endfor %} +
+ {{ form.submit() }} +
+ + \ No newline at end of file From 7976bdb2d81d543572ddd71402d94d11fa156fbe Mon Sep 17 00:00:00 2001 From: tlm273623 Date: Fri, 28 Mar 2025 17:38:47 -0400 Subject: [PATCH 13/19] Test Commit - Testing commits to sprint 2. --- Sprint 2/AI Fitness Project/test.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 Sprint 2/AI Fitness Project/test.txt diff --git a/Sprint 2/AI Fitness Project/test.txt b/Sprint 2/AI Fitness Project/test.txt new file mode 100644 index 000000000..30d74d258 --- /dev/null +++ b/Sprint 2/AI Fitness Project/test.txt @@ -0,0 +1 @@ +test \ No newline at end of file From 0b1c4c07e70aa85a4678ab0f645a98a43c9fc421 Mon Sep 17 00:00:00 2001 From: rayanm231 <160540674+rayanm231@users.noreply.github.com> Date: Wed, 2 Apr 2025 21:28:06 -0400 Subject: [PATCH 14/19] Adding fitness log script and style --- .DS_Store | Bin 8196 -> 8196 bytes Sprint 1/.DS_Store | Bin 0 -> 6148 bytes Sprint 1/AI Fitness Project/.DS_Store | Bin 0 -> 6148 bytes Sprint 1/AI Fitness Project/static/.DS_Store | Bin 0 -> 6148 bytes 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 Sprint 1/.DS_Store create mode 100644 Sprint 1/AI Fitness Project/.DS_Store create mode 100644 Sprint 1/AI Fitness Project/static/.DS_Store diff --git a/.DS_Store b/.DS_Store index 953c41e9449856e3957d771b2c9c256685da8c46..bbd9324c279e69aeaa7fc4e4914f7f0efc8f44dd 100644 GIT binary patch delta 470 zcmZp1XmOa}FDlKzz`)4BAi%)j%izkO$B@gA;+eCta2or>2Hwr=94s95AQhYpK|onY z1{Y*i`N>H+`AI-opk|;P1B2dwFaWX`7^E1A7*ZJu8A=&4!K_>$FOQ*wA%G!=A(0^& z$je~J2eMOutRkSjB@7h|C7wAbX08XBnS^Ah978ZrQyNflInWT01pz=ZA8cGPLoq3a zGs=PthnPKizksN;A*$t!-Kg@6hLf)fG>DiQ80#n)o0-fDN+;2m}ZL6O-{3 n6O#!NwUZ7LfsjraqOuCaCF{nt-6k@@0Z>Vnhy_ACCFwe;s+2SQ z7_R#z{GIVV+Y=oHZ5I$je%15${OtE)f2r-5h{RwNKO$-okq2dL+(z*W;da(JS+JfZ zpwKx|swk&~O8lHS1{?$bIs?3R@6smik)$1(UB8m{sUSrku$~X8+RM~ol&J{)d9&Dr zuAggxb9og$|OgnPY zfAX{=ANTsxY13PK@bKA-;m7P#u0HG8kidSX<&MP*_yXfve4PYEo~isj`g5*(;80Nv zF83*;5VeGM;mNeGpmpq=r*kZSMdU2YZ934qYeiegQEK}~zN4%1iTgk0Tcs1ca~_qN z8Q0Z$n1$JKq3YzuF<}4W-pY*|xf`%!z%lTr8Q}dvLK%IFwL!ggpwL$UU;}O~u=(?V zW28mjVr>vD5Me@rCRErfhA`pqOWV)4SQ|9qB<$rw*e45nLlOGv$S-ww623uKItCmA zml;?z)fS)s&wqdazZ~RhjseHOf5m`kYzNx|Ov#?DbCct!y@&96p3q9ipo|XE}<+3t^~mWP-)r-qD|v$lM+x>DQEZx zet|1r!tcNv+bcC`;Ra$?o@)FYduHr;sqL7E#CSEoOVlAE2g=yEj$)5+KkJShm=^XE zDn?45p2l((#4^~iwhfj6%fSD}0I%I9O)15%58YnByeT|__J1l-Q*TiK>lvLx^yW965jiW3d41S1%!^X8{%V{}B&Kv)|Ec|?$ud?xU z`HG*OOBn|j^=a@T3X4hS__0j#X_SOZkvl7(#Lx6o;gPy@sBYGf0y8^YVFjowr-O=tEJI`RLQM;2c zmk(h^7UqT`)aZ!sDsvK^Mq642ECW>r4)tS)&;KXCzyDXA?2~1{GH|6B5RFs+bc~eD z*}9V)pS3RZEtG}rN{z||g*lE@g^%JcR0;ZAt^hrQrAD+s?1zA&!4{T*f6Blwep}`< literal 0 HcmV?d00001 diff --git a/Sprint 1/AI Fitness Project/static/.DS_Store b/Sprint 1/AI Fitness Project/static/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..130e3f0769ec924bce7641089b32f95fdb6a9cf9 GIT binary patch literal 6148 zcmeHK%}xR_5S{|UA~E5h3CAX0iDD3<@vXZ07 zI@1=zj~+EbI?42#c4l_lFX^-e09Na_cL4GLV4)JGR2I0}m$luW->rW#JHY>q81!bJ6Y~?7F^;esjCN7e=Mh zJ4+-}E9s1tv2xb6b0-E))QtLJt=YSz-kA`-JGPtdxz`yq^6N(;h?-u|>B$7I-NBHn z3omGkK~407b|`Zl<*>3=wvjIkhm}&f$jjBrsK|%az5OEJEmudQthKSZeQ?^i_a6fB zEawdjYm}5VjbnI0V}^rArx*AlxJ3_TrIDcsp1_CBxW0Yy^NRjSex_oVgq^81&2WRu zH?oin=>1^j7IOAx(uM)Uz;7}@^?{=j+8SepvUFf0p8$v{9F~GMT^cBdYqT}S3ekhY zR4SrMW%`N1R634x9cOEd6{>V#`tiZ^pP7E4F!^`XHc8Az&bp3eW{ zpWpw}Nv3BQFbpge11wc{>NQ-FK3nG&M`tZZy+I|RxLBb~!A2j)(x9WbfGP!joD4); UW2_KIP|QU@(qJ0Hz@IYk3F8E$7ytkO literal 0 HcmV?d00001 From f400cb5cc8d25f6e57b8ab8cf3906cfc29531625 Mon Sep 17 00:00:00 2001 From: rayanm231 <160540674+rayanm231@users.noreply.github.com> Date: Wed, 2 Apr 2025 21:29:09 -0400 Subject: [PATCH 15/19] Fitness Calendar --- .../templates/fitness-calendar.html | 132 ++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 Sprint 1/AI Fitness Project/templates/fitness-calendar.html diff --git a/Sprint 1/AI Fitness Project/templates/fitness-calendar.html b/Sprint 1/AI Fitness Project/templates/fitness-calendar.html new file mode 100644 index 000000000..7629a9081 --- /dev/null +++ b/Sprint 1/AI Fitness Project/templates/fitness-calendar.html @@ -0,0 +1,132 @@ + + + FitBod + + + + + +
+
March 2025
+
+
+
Sun
+
Mon
+
Tue
+
Wed
+
Thu
+
Fri
+
Sat
+
+ +
+
+
+
+
+
+
1
+
2
+ +
3
+
4
+
5
+
6
+
7
+
8
+
9
+ +
10
+
11
+
12
+
13
+
14
+
15
+
16
+ +
17
+
18
+
19
+
20
+
21
+
22
+
23
+ +
24
+
25
+
26
+
27
+
28
+
29
+
30
+ +
31
+
+
+ + + From 34bf176d0891adbf03fc8c233bd0c545b79d9564 Mon Sep 17 00:00:00 2001 From: rayanm231 <160540674+rayanm231@users.noreply.github.com> Date: Mon, 7 Apr 2025 03:48:08 -0400 Subject: [PATCH 16/19] Added calendar --- .../static/scripts/calendarScript.js | 87 +++++++++++ .../templates/calendarPage.html | 144 ++++++++++++++++++ .../templates/fitness-log.html | 2 +- 3 files changed, 232 insertions(+), 1 deletion(-) create mode 100644 Sprint 2/AI Fitness Project/static/scripts/calendarScript.js create mode 100644 Sprint 2/AI Fitness Project/templates/calendarPage.html diff --git a/Sprint 2/AI Fitness Project/static/scripts/calendarScript.js b/Sprint 2/AI Fitness Project/static/scripts/calendarScript.js new file mode 100644 index 000000000..43c6718a9 --- /dev/null +++ b/Sprint 2/AI Fitness Project/static/scripts/calendarScript.js @@ -0,0 +1,87 @@ +let display = document.querySelector(".display"); +let previous = document.querySelector(".left"); +let next = document.querySelector(".right"); +let days = document.querySelector(".days"); +let selected = document.querySelector(".selected"); + +let today = new Date(); +let date = new Date(today); +let year = date.getFullYear(); +let month = date.getMonth(); + + +function calendarDisplay() { + days.innerHTML = ''; + + let formattedDate = date.toLocaleString("en-US", { + month: "long", + year: "numeric", + }); + display.innerHTML = formattedDate; + + const firstDay = new Date(year, month, 1); + const firstDayIndex = firstDay.getDay(); + + const lastDay = new Date(year, month + 1, 0); + const numberOfDays = lastDay.getDate(); + + for (let x = 1; x <= firstDayIndex; x++) { + let div = document.createElement("div"); + div.classList.add("days"); + div.innerHTML = ""; + days.appendChild(div); + } + + for (let i = 1; i <= numberOfDays; i++) { + let div = document.createElement("div"); + + div.classList.add("day"); + div.innerHTML = i; + days.appendChild(div); + + let currentDate = new Date(year, month, i); + if ( + currentDate.getFullYear() === new Date().getFullYear() && + currentDate.getMonth() === new Date().getMonth() && + currentDate.getDate() === new Date().getDate() + ) { + div.classList.add("current-date"); + } + } + + displaySelected(); +} + +function displaySelected() { + const dayElements = document.querySelectorAll(".days div"); + dayElements.forEach((day) => { + day.addEventListener("click", (e) => { + const selectedDate = e.target.dataset.date; + selected.innerHTML = `Selected Date : ${selectedDate}`; + window.open("/Sprint 2/AI Fitness Project/templates/fitness-log.html", '_blank') + }); + }); + } + displaySelected(); + +previous.addEventListener("click", () => { + month--; + if (month < 0) { + month = 11; + year--; + } + date.setFullYear(year, month); + calendarDisplay(); +}); + +next.addEventListener("click", () => { + month++; + if (month > 11) { + month = 0; + year++; + } + date.setFullYear(year, month); + calendarDisplay(); +}); + +calendarDisplay(); diff --git a/Sprint 2/AI Fitness Project/templates/calendarPage.html b/Sprint 2/AI Fitness Project/templates/calendarPage.html new file mode 100644 index 000000000..79acbe2e5 --- /dev/null +++ b/Sprint 2/AI Fitness Project/templates/calendarPage.html @@ -0,0 +1,144 @@ + + + + + + Calendar + + + + +
+
+
+
+
+

""

+
+
+
+
+
Su
+
Mo
+
Tu
+
We
+
Th
+
Fr
+
Sa
+
+
+
+
+
+
+

+
+ + + + \ No newline at end of file diff --git a/Sprint 2/AI Fitness Project/templates/fitness-log.html b/Sprint 2/AI Fitness Project/templates/fitness-log.html index 696126f5e..4f75b6939 100644 --- a/Sprint 2/AI Fitness Project/templates/fitness-log.html +++ b/Sprint 2/AI Fitness Project/templates/fitness-log.html @@ -69,6 +69,6 @@

Bicep

- + From a0c05a960864d78dd8b6ef20748530d58bc7e2ec Mon Sep 17 00:00:00 2001 From: tlm273623 Date: Mon, 7 Apr 2025 19:05:52 -0400 Subject: [PATCH 17/19] Sprint-2 Update - Completed cardio and workout logs. - Merged the calendar html file to the fitness-log file. --- Sprint 2/AI Fitness Project/app.py | 12 ++ Sprint 2/AI Fitness Project/backend/forms.py | 24 +-- Sprint 2/AI Fitness Project/backend/tables.py | 2 + .../static/images/arrow.png | Bin 0 -> 24738 bytes .../static/scripts/cardio-log.js | 24 +++ .../static/scripts/fitness-log.js | 92 ++++++++- .../static/scripts/workout-log.js | 21 ++ .../static/styles/cardio-log.css | 56 +++++ .../static/styles/workout-log.css | 56 +++++ .../templates/cardio-log.html | 39 ++++ .../templates/fitness-log.html | 195 ++++++++++++------ .../templates/workout-log.html | 41 ++++ Sprint 2/AI Fitness Project/test.txt | 1 - 13 files changed, 479 insertions(+), 84 deletions(-) create mode 100644 Sprint 2/AI Fitness Project/static/images/arrow.png create mode 100644 Sprint 2/AI Fitness Project/static/scripts/cardio-log.js create mode 100644 Sprint 2/AI Fitness Project/static/scripts/workout-log.js create mode 100644 Sprint 2/AI Fitness Project/static/styles/cardio-log.css create mode 100644 Sprint 2/AI Fitness Project/static/styles/workout-log.css create mode 100644 Sprint 2/AI Fitness Project/templates/cardio-log.html create mode 100644 Sprint 2/AI Fitness Project/templates/workout-log.html delete mode 100644 Sprint 2/AI Fitness Project/test.txt diff --git a/Sprint 2/AI Fitness Project/app.py b/Sprint 2/AI Fitness Project/app.py index ee287da0f..07a53dee3 100644 --- a/Sprint 2/AI Fitness Project/app.py +++ b/Sprint 2/AI Fitness Project/app.py @@ -104,6 +104,18 @@ def survey(): return render_template('survey.html', form=form) +@app.route('/workout-log', methods=['GET', 'POST']) +@login_required +def workout_log(): + form = FitnessLogWorkoutForm() + return render_template('workout-log.html', form=form) + +@app.route('/cardio-log', methods=['GET', 'POST']) +@login_required +def cardio_log(): + form = FitnessLogCardioForm() + return render_template('cardio-log.html', form=form) + with app.app_context(): db.create_all() diff --git a/Sprint 2/AI Fitness Project/backend/forms.py b/Sprint 2/AI Fitness Project/backend/forms.py index eb6fe2c2f..a4ecd8da8 100644 --- a/Sprint 2/AI Fitness Project/backend/forms.py +++ b/Sprint 2/AI Fitness Project/backend/forms.py @@ -1,7 +1,8 @@ from flask_wtf import FlaskForm -from wtforms import StringField, PasswordField, SubmitField, SelectMultipleField, widgets, IntegerField, FieldList, FormField, DecimalField +from wtforms import StringField, PasswordField, SubmitField, SelectMultipleField, widgets, IntegerField, FieldList, FormField, DecimalField, TimeField from wtforms.validators import InputRequired, Length, ValidationError, DataRequired, NumberRange from backend.tables import User +from datetime import time # Sets up the form on the register page class RegisterForm(FlaskForm): @@ -47,24 +48,19 @@ class SurveyForm(FlaskForm): class FitnessLogWorkoutForm(FlaskForm): - legs_reps = IntegerField('Total Reps', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")]) - legs_sets = IntegerField('Total Sets', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")]) + reps_field = IntegerField('Total Reps', default=1, validators=[NumberRange(min=0, message="Value must be 0 or greater")]) + sets_field = IntegerField('Total Sets', default=1, validators=[NumberRange(min=0, message="Value must be 0 or greater")]) - chest_reps = IntegerField('Total Reps', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")]) - chest_sets = IntegerField('Total Sets', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")]) + exercise_input = StringField(validators=[InputRequired(), Length(min=1, max=50)], render_kw={"placeholder": "Exercise Input"}) - back_reps = IntegerField('Total Reps', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")]) - back_sets = IntegerField('Total Sets', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")]) + submit = SubmitField("Submit") - bicep_reps = IntegerField('Total Reps', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")]) - bicep_sets = IntegerField('Total Sets', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")]) +class FitnessLogCardioForm(FlaskForm): + minute_field = IntegerField('Minutes', default=0, validators=[NumberRange(min=0)]) - tricep_reps = IntegerField('Total Reps', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")]) - tricep_sets = IntegerField('Total Sets', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")]) + second_field = IntegerField( 'Seconds', default=0, validators=[NumberRange(min=0, max=59)]) - submit = SubmitField("Submit") + distance_field = DecimalField('Total Miles', default=0, validators=[InputRequired(), NumberRange(min=0, message="Value must be 0 or greater")]) -class FitnessLogCardioForm(FlaskForm): - miles = DecimalField('Total Miles', default=0, validators=[NumberRange(min=0, message="Value must be 0 or greater")]) submit = SubmitField("Submit") \ No newline at end of file diff --git a/Sprint 2/AI Fitness Project/backend/tables.py b/Sprint 2/AI Fitness Project/backend/tables.py index 429ba7f9c..d27e4ce5d 100644 --- a/Sprint 2/AI Fitness Project/backend/tables.py +++ b/Sprint 2/AI Fitness Project/backend/tables.py @@ -13,3 +13,5 @@ class User(db.Model, UserMixin): + + diff --git a/Sprint 2/AI Fitness Project/static/images/arrow.png b/Sprint 2/AI Fitness Project/static/images/arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..99a73c7c59696ca46cc5f5d828f01a2ab2d629cb GIT binary patch literal 24738 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 H$#?$?^F3)t literal 0 HcmV?d00001 diff --git a/Sprint 2/AI Fitness Project/static/scripts/cardio-log.js b/Sprint 2/AI Fitness Project/static/scripts/cardio-log.js new file mode 100644 index 000000000..3e4a3a437 --- /dev/null +++ b/Sprint 2/AI Fitness Project/static/scripts/cardio-log.js @@ -0,0 +1,24 @@ +document.getElementById("add-form-btn").addEventListener("click", function() { + const formContainer = document.getElementById("cardio-form"); + const lastFormChild = document.querySelector(".form-child"); + const submitButton = document.getElementById("submit-button"); + + if (lastFormChild && submitButton) { + const clonedFormChild = lastFormChild.cloneNode(true); + clonedFormChild.querySelectorAll("input").forEach(input => input.value = ""); + + let distance = 0; + + clonedFormChild.querySelector("#distance_field input").value = distance.toFixed(2); + clonedFormChild.querySelector("#minute_field input").value = 0; + clonedFormChild.querySelector("#second_field input").value = 0; + + formContainer.insertBefore(clonedFormChild, submitButton); + + clonedFormChild.querySelector("#delete-field").addEventListener("click", function() { + clonedFormChild.remove(); + }); + } +}); + + diff --git a/Sprint 2/AI Fitness Project/static/scripts/fitness-log.js b/Sprint 2/AI Fitness Project/static/scripts/fitness-log.js index 1b949e0dd..ef8f3e001 100644 --- a/Sprint 2/AI Fitness Project/static/scripts/fitness-log.js +++ b/Sprint 2/AI Fitness Project/static/scripts/fitness-log.js @@ -1,9 +1,87 @@ -function toggleWorkoutForm() { - const form = document.getElementById('workout-form'); - form.style.display = (form.style.display === 'none' || form.style.display === '') ? 'block' : 'none'; +let display = document.querySelector(".display"); +let previous = document.querySelector(".left"); +let next = document.querySelector(".right"); +let days = document.querySelector(".days"); +let selected = document.querySelector(".selected"); + +let today = new Date(); +let date = new Date(today); +let year = date.getFullYear(); +let month = date.getMonth(); + + +function calendarDisplay() { + days.innerHTML = ''; + + let formattedDate = date.toLocaleString("en-US", { + month: "long", + year: "numeric", + }); + display.innerHTML = formattedDate; + + const firstDay = new Date(year, month, 1); + const firstDayIndex = firstDay.getDay(); + + const lastDay = new Date(year, month + 1, 0); + const numberOfDays = lastDay.getDate(); + + for (let x = 1; x <= firstDayIndex; x++) { + let div = document.createElement("div"); + div.classList.add("days"); + div.innerHTML = ""; + days.appendChild(div); + } + + for (let i = 1; i <= numberOfDays; i++) { + let div = document.createElement("div"); + + div.classList.add("day"); + div.innerHTML = i; + days.appendChild(div); + + let currentDate = new Date(year, month, i); + if ( + currentDate.getFullYear() === new Date().getFullYear() && + currentDate.getMonth() === new Date().getMonth() && + currentDate.getDate() === new Date().getDate() + ) { + div.classList.add("current-date"); + } + } + + displaySelected(); } -function toggleCardioForm() { - const form = document.getElementById('cardio-form'); - form.style.display = (form.style.display === 'none' || form.style.display === '') ? 'block' : 'none'; -} \ No newline at end of file +function displaySelected() { + const dayElements = document.querySelectorAll(".days div"); + dayElements.forEach((day) => { + day.addEventListener("click", (e) => { + const selectedDate = e.target.dataset.date; + selected.innerHTML = `Selected Date : ${selectedDate}`; + window.open("/Sprint 2/AI Fitness Project/templates/fitness-log.html", '_blank') + }); + }); + } + displaySelected(); + +previous.addEventListener("click", () => { + month--; + if (month < 0) { + month = 11; + year--; + } + date.setFullYear(year, month); + calendarDisplay(); +}); + +next.addEventListener("click", () => { + month++; + if (month > 11) { + month = 0; + year++; + } + date.setFullYear(year, month); + calendarDisplay(); +}); + +calendarDisplay(); \ No newline at end of file diff --git a/Sprint 2/AI Fitness Project/static/scripts/workout-log.js b/Sprint 2/AI Fitness Project/static/scripts/workout-log.js new file mode 100644 index 000000000..b65fec771 --- /dev/null +++ b/Sprint 2/AI Fitness Project/static/scripts/workout-log.js @@ -0,0 +1,21 @@ +document.getElementById("add-form-btn").addEventListener("click", function() { + const formContainer = document.getElementById("workout-form"); + const lastFormChild = document.querySelector(".form-child"); + const submitButton = document.getElementById("submit-button"); + + if (lastFormChild && submitButton) { + const clonedFormChild = lastFormChild.cloneNode(true); + clonedFormChild.querySelectorAll("input").forEach(input => input.value = ""); + + clonedFormChild.querySelector("#sets_field input").value = 1; + clonedFormChild.querySelector("#reps_field input").value = 1; + + formContainer.insertBefore(clonedFormChild, submitButton); + + clonedFormChild.querySelector("#delete-field").addEventListener("click", function() { + clonedFormChild.remove(); + }); + } +}); + + diff --git a/Sprint 2/AI Fitness Project/static/styles/cardio-log.css b/Sprint 2/AI Fitness Project/static/styles/cardio-log.css new file mode 100644 index 000000000..1a68f4918 --- /dev/null +++ b/Sprint 2/AI Fitness Project/static/styles/cardio-log.css @@ -0,0 +1,56 @@ +.forms-wrapper { + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + margin-top: 25px; + +} + + +.cardio-form { + width: 800px; +} + +.form-child{ + display: inline-flex; + border-style: solid; + padding: 15px; + border-radius: 10px; + background-color: rgb(228, 224, 224); + font-weight: 1000; + margin-bottom: 10px; +} + +#delete-field { + all: unset; + color: black; + border-radius: 5px; + size: 5px; + padding-right: 15px; + cursor: pointer; +} + +#minute_field { + padding-right: 10px; +} + + +#distance_field { + padding-right: 20px; +} + + + +#submit-button { + padding-top: 15px; +} + +#add-form-btn { + float: right; + margin-right: 965px; +} + +#back-btn{ + padding-left: 15px; +} \ No newline at end of file diff --git a/Sprint 2/AI Fitness Project/static/styles/workout-log.css b/Sprint 2/AI Fitness Project/static/styles/workout-log.css new file mode 100644 index 000000000..f67868b4c --- /dev/null +++ b/Sprint 2/AI Fitness Project/static/styles/workout-log.css @@ -0,0 +1,56 @@ +.forms-wrapper { + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + margin-top: 25px; + +} + + +.workout-form { + width: 800px; +} + +.form-child{ + display: inline-flex; + border-style: solid; + padding: 15px; + border-radius: 10px; + background-color: rgb(228, 224, 224); + font-weight: 1000; + margin-bottom: 10px; +} + +#delete-field { + all: unset; + color: black; + border-radius: 5px; + size: 5px; + padding-right: 15px; + cursor: pointer; +} + +#sets_field { + margin-right: 15px; +} + + +#exercise_field { + padding-right: 20px; +} + + + +#submit-button { + padding-top: 15px; +} + +#add-form-btn { + float: right; + margin-right: 965px; +} + +#back-btn{ + padding-left: 15px; +} \ No newline at end of file diff --git a/Sprint 2/AI Fitness Project/templates/cardio-log.html b/Sprint 2/AI Fitness Project/templates/cardio-log.html new file mode 100644 index 000000000..7e5884876 --- /dev/null +++ b/Sprint 2/AI Fitness Project/templates/cardio-log.html @@ -0,0 +1,39 @@ + + + + + + Fitness Log + + + + {% include 'navbar.html' %} + Back

+ + + +
+
+
+
+ +
+ + {{ form.distance_field }} +
+
+ + {{ form.minute_field }} +
+
+ + {{ form.second_field }} +
+
+
{{ form.submit }}
+
+
+ + + + diff --git a/Sprint 2/AI Fitness Project/templates/fitness-log.html b/Sprint 2/AI Fitness Project/templates/fitness-log.html index 696126f5e..04f72e49e 100644 --- a/Sprint 2/AI Fitness Project/templates/fitness-log.html +++ b/Sprint 2/AI Fitness Project/templates/fitness-log.html @@ -3,72 +3,143 @@ - Fitness Log - + Calendar + - - {% include 'navbar.html' %} -

Fitness Log

+ + + {% include 'navbar.html' %} +
+
+
+
+
+

""

+
+
+
+
+
Su
+
Mo
+
Tu
+
We
+
Th
+
Fr
+
Sa
+
+
+
+
+
+
+

+
+
+ - + \ No newline at end of file diff --git a/Sprint 2/AI Fitness Project/templates/workout-log.html b/Sprint 2/AI Fitness Project/templates/workout-log.html new file mode 100644 index 000000000..e19d6b454 --- /dev/null +++ b/Sprint 2/AI Fitness Project/templates/workout-log.html @@ -0,0 +1,41 @@ + + + + + + Fitness Log + + + + {% include 'navbar.html' %} + Back

+ + + +
+
+
+
+ +
+ {{ form.exercise_input }} +
+
+ + {{ form.sets_field }} +
+ +
+ + {{ form.reps_field }} +
+
+ + +
{{ form.submit }}
+
+
+ + + + diff --git a/Sprint 2/AI Fitness Project/test.txt b/Sprint 2/AI Fitness Project/test.txt deleted file mode 100644 index 30d74d258..000000000 --- a/Sprint 2/AI Fitness Project/test.txt +++ /dev/null @@ -1 +0,0 @@ -test \ No newline at end of file From b376934fbbc7819122ed878a85be9d9d98c55afc Mon Sep 17 00:00:00 2001 From: rayanm231 <160540674+rayanm231@users.noreply.github.com> Date: Sun, 13 Apr 2025 11:54:10 -0400 Subject: [PATCH 18/19] calendar update-sprint2 --- .../templates/fitness-calendar.html | 60 +----- .../static/scripts/calendarScript.js | 83 +++++++- .../templates/calendarPage.html | 121 ++++++++++- .../templates/fitness-log.html | 194 ++++++------------ 4 files changed, 252 insertions(+), 206 deletions(-) diff --git a/Sprint 1/AI Fitness Project/templates/fitness-calendar.html b/Sprint 1/AI Fitness Project/templates/fitness-calendar.html index 7629a9081..993066d05 100644 --- a/Sprint 1/AI Fitness Project/templates/fitness-calendar.html +++ b/Sprint 1/AI Fitness Project/templates/fitness-calendar.html @@ -16,8 +16,8 @@ } .calendar { - width: 900px; - height:400px; + width: 1800px; + height:1350px; background: white; border-radius: 5px; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2); @@ -31,21 +31,16 @@ margin-bottom: 10px; color: black; } - - hr{ - width:900px; - font-weight:bold; - } - .calendar-days { + .day { display: grid; grid-template-columns: repeat(7, 1fr); gap: 15px; font-size: 16px; } - .day { - padding: 10px; + .day button{ + padding: 50px; background: #AAB7B8; border-radius: 5px; transition: 0.1s; @@ -72,7 +67,6 @@
March 2025
-
Sun
Mon
@@ -82,49 +76,9 @@
Fri
Sat
- +
-
-
-
-
-
-
1
-
2
- -
3
-
4
-
5
-
6
-
7
-
8
-
9
- -
10
-
11
-
12
-
13
-
14
-
15
-
16
- -
17
-
18
-
19
-
20
-
21
-
22
-
23
- -
24
-
25
-
26
-
27
-
28
-
29
-
30
- -
31
+
diff --git a/Sprint 2/AI Fitness Project/static/scripts/calendarScript.js b/Sprint 2/AI Fitness Project/static/scripts/calendarScript.js index 43c6718a9..310c70e6e 100644 --- a/Sprint 2/AI Fitness Project/static/scripts/calendarScript.js +++ b/Sprint 2/AI Fitness Project/static/scripts/calendarScript.js @@ -31,14 +31,24 @@ function calendarDisplay() { div.innerHTML = ""; days.appendChild(div); } - for (let i = 1; i <= numberOfDays; i++) { let div = document.createElement("div"); - div.classList.add("day"); - div.innerHTML = i; + + let dayNum = document.createElement("div"); + dayNum.classList.add("days"); + dayNum.textContent = i; + div.appendChild(dayNum); + + let plusButton = document.createElement("button"); + plusButton.classList.add("plus-button"); + plusButton.textContent = "+"; + + div.appendChild(plusButton); + days.appendChild(div); + let currentDate = new Date(year, month, i); if ( currentDate.getFullYear() === new Date().getFullYear() && @@ -47,22 +57,73 @@ function calendarDisplay() { ) { div.classList.add("current-date"); } - } + } + displaySelectedDate(); + displaySelectedPlus(); +} + +function displaySelectedPlus(){ + const plusElement = document.querySelectorAll(".plus-button"); + plusElement.forEach((plusButton) => { + plusButton.addEventListener("click", (e) => { + e.stopPropagation(); + createPage(); + }); + }); +} + +function createPage(){ + const bottomPage = document.createElement("div"); + bottomPage.classList.add("bottom-page"); + bottomPage.innerHTML = ` +
+ +

FITNESS LOG INFO TO BE PLACED HERE

+
+`; +document.body.appendChild(bottomPage); - displaySelected(); +bottomPage.querySelector(".close-button").addEventListener("click", () => { + bottomPage.remove(); +}); } -function displaySelected() { - const dayElements = document.querySelectorAll(".days div"); +function displaySelectedDate() { + const dayElements = document.querySelectorAll(".day"); dayElements.forEach((day) => { day.addEventListener("click", (e) => { - const selectedDate = e.target.dataset.date; - selected.innerHTML = `Selected Date : ${selectedDate}`; - window.open("/Sprint 2/AI Fitness Project/templates/fitness-log.html", '_blank') + openPopup(); }); }); } - displaySelected(); +function openPopup(){ + const popup = document.createElement("div"); + popup.classList.add("popup-container"); + + popup.innerHTML = ` + + `; + + document.body.appendChild(popup); + + popup.querySelector(".removeButton").addEventListener("click", () => { + popup.remove(); + }); + popup.querySelector(".cardio").addEventListener("click", cardioLink); + popup.querySelector(".muscular").addEventListener("click", muscularLink); +} + +function cardioLink() { + window.open("/Sprint 2/AI Fitness Project/templates/cardio-log.html", "_blank"); +} + +function muscularLink() { + window.open("/Sprint 2/AI Fitness Project/templates/fitness-log.html", "_blank"); +} previous.addEventListener("click", () => { month--; diff --git a/Sprint 2/AI Fitness Project/templates/calendarPage.html b/Sprint 2/AI Fitness Project/templates/calendarPage.html index 79acbe2e5..44a007a62 100644 --- a/Sprint 2/AI Fitness Project/templates/calendarPage.html +++ b/Sprint 2/AI Fitness Project/templates/calendarPage.html @@ -18,8 +18,8 @@ } .calendar { - width: 1200px; - height:600px; + width: 2500px; + height:1500px; background: white; border-radius: 5px; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2); @@ -33,7 +33,7 @@ justify-content: space-between; align-items: center; padding: 20px; - font-size: 30px; + font-size: 60px; color: black; font-weight: bold; margin-bottom: 10px; @@ -46,7 +46,7 @@ padding: 10px; margin: 0; cursor: pointer; - font-size: 1.2rem; + font-size: 25px; color: black; border-radius: 5px; } @@ -55,7 +55,7 @@ padding: 10px; margin: 0; cursor: pointer; - font-size: 1.2rem; + font-size: 25px; color: black; border-radius: 5px; } @@ -64,16 +64,81 @@ display: grid; grid-template-columns: repeat(7, 1fr); gap: 10px; - font-size: 13px; + font-size: 20px; } .day{ - padding: 10px; + display: flex; + justify-content: space-between; + align-items: left; + padding: 50px; background: #AAB7B8; - border-radius: 10px; + border-radius: 40px; transition: 0.1s; + height: 100px; + position: relative; + } + + .plus-button:hover{ + background: transparent; + color: white; + cursor: pointer; + } + + .popup{ + width: 900px; + background-color: #f1f1f1; + padding: 40px; + text-align: center; + position: fixed; + bottom: 200px; + left: 1050px; + right: 500px; + border-radius: 30px; + align-items: center; + height: 400px; + bottom: 700px; + } + + .cardio{ + background-color: white; + padding: 110px; + border-radius: 20px; + gap: 30px; + color: black; + position: relative; + margin-left: auto; + margin-right: auto; + font-size: 20px; + border: white; + } + + .muscular{ + background-color: white; + padding: 110px; + word-spacing: 40px; + border-radius: 20px; + gap: 30px; + font-size: 20px; + color: black; + position: relative; + margin-left: auto; + margin-right: auto; + border: white; } + .plus-button { + color: black; + gap: 10px; + font-size: 20px; + border: #AAB7B8; + background: transparent; + align-items: right; + height: 5px; + margin-top: 10px; + } + + .days-blank{ padding: 10px; background: white; @@ -82,6 +147,43 @@ transition: 0.1s; } + .bottom-page { + width: 100%; + background-color: #f1f1f1; + padding: 30px; + text-align: center; + position: fixed; + bottom: 0; + left: 0; + z-index: 999; + height: 500px; + } + + .close-button{ + text-align: right; + vertical-align: top; + font-size: 20px; + cursor: pointer; + background: transparent; + width: 200px; + height: 200px; + left: 400px; + right: 10px; + } + + .removeButton{ + position: absolute; + top: 10px; + right: 10px; + font-size: 20px; + cursor: pointer; + background: transparent; + width: 40px; + height: 40px; + text-align: center; + line-height: 40px; + } + .current-date{ background: red; color: white; @@ -131,8 +233,7 @@
Fr
Sa
-
-
+
diff --git a/Sprint 2/AI Fitness Project/templates/fitness-log.html b/Sprint 2/AI Fitness Project/templates/fitness-log.html index 053744ca9..696126f5e 100644 --- a/Sprint 2/AI Fitness Project/templates/fitness-log.html +++ b/Sprint 2/AI Fitness Project/templates/fitness-log.html @@ -3,142 +3,72 @@ - Calendar - + Fitness Log + - - - {% include 'navbar.html' %} -
-
-
-
-
-

""

-
-
-
-
-
Su
-
Mo
-
Tu
-
We
-
Th
-
Fr
-
Sa
-
-
-
-
+
+ {{ cardio_form.hidden_tag() }} +
+ + {{ cardio_form.miles }} +
+
{{ cardio_form.submit }}
+
-
-

-
-
- + + + - \ No newline at end of file + From 50e8273369c920e58bf931c8dcdc3c2f6cc8036e Mon Sep 17 00:00:00 2001 From: rayanm231 <160540674+rayanm231@users.noreply.github.com> Date: Sun, 13 Apr 2025 12:11:24 -0400 Subject: [PATCH 19/19] calendar update sprint2->3 --- .../static/scripts/calendarScript.js | 12 ++++++------ .../AI Fitness Project/templates/calendarPage.html | 5 +++-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Sprint 2/AI Fitness Project/static/scripts/calendarScript.js b/Sprint 2/AI Fitness Project/static/scripts/calendarScript.js index 310c70e6e..7ea0082cf 100644 --- a/Sprint 2/AI Fitness Project/static/scripts/calendarScript.js +++ b/Sprint 2/AI Fitness Project/static/scripts/calendarScript.js @@ -63,9 +63,9 @@ function calendarDisplay() { } function displaySelectedPlus(){ - const plusElement = document.querySelectorAll(".plus-button"); - plusElement.forEach((plusButton) => { - plusButton.addEventListener("click", (e) => { + const dayElements = document.querySelectorAll(".day"); + dayElements.forEach((day) => { + day.addEventListener("click", (e) => { e.stopPropagation(); createPage(); }); @@ -89,9 +89,9 @@ bottomPage.querySelector(".close-button").addEventListener("click", () => { } function displaySelectedDate() { - const dayElements = document.querySelectorAll(".day"); - dayElements.forEach((day) => { - day.addEventListener("click", (e) => { + const plusElement = document.querySelectorAll(".plus-button"); + plusElement.forEach((plusButton)=> { + plusButton.addEventListener("click", (e) => { openPopup(); }); }); diff --git a/Sprint 2/AI Fitness Project/templates/calendarPage.html b/Sprint 2/AI Fitness Project/templates/calendarPage.html index 44a007a62..7ba719654 100644 --- a/Sprint 2/AI Fitness Project/templates/calendarPage.html +++ b/Sprint 2/AI Fitness Project/templates/calendarPage.html @@ -165,8 +165,9 @@ font-size: 20px; cursor: pointer; background: transparent; - width: 200px; - height: 200px; + border: #f1f1f1; + width: 20px; + height: 20px; left: 400px; right: 10px; }