From 5f477bf9b166415213dc0d335f69dcb09dc244c0 Mon Sep 17 00:00:00 2001 From: Laila-2006 Date: Tue, 2 Dec 2025 14:33:12 -0500 Subject: [PATCH 1/7] Create Health_Analyst_Blueprint creates folder to host file for blueprint --- api/Health_Analyst_Blueprint | 1 + 1 file changed, 1 insertion(+) create mode 100644 api/Health_Analyst_Blueprint diff --git a/api/Health_Analyst_Blueprint b/api/Health_Analyst_Blueprint new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/api/Health_Analyst_Blueprint @@ -0,0 +1 @@ + From d87abf9e38bc9a3a6ab5d9573c5d7e9985a65d13 Mon Sep 17 00:00:00 2001 From: Laila-2006 Date: Tue, 2 Dec 2025 23:25:55 -0500 Subject: [PATCH 2/7] Routes --- api/Health_Analyst_Blueprint | 1 - .../Health_Analyst_Blueprint/average_duration | 50 ++++++++ .../Health_Analyst_Blueprint/client_info | 68 +++++++++++ .../Health_Analyst_Blueprint/health_metrics | 114 ++++++++++++++++++ 4 files changed, 232 insertions(+), 1 deletion(-) delete mode 100644 api/Health_Analyst_Blueprint create mode 100644 api/backend/Health_Analyst_Blueprint/average_duration create mode 100644 api/backend/Health_Analyst_Blueprint/client_info create mode 100644 api/backend/Health_Analyst_Blueprint/health_metrics diff --git a/api/Health_Analyst_Blueprint b/api/Health_Analyst_Blueprint deleted file mode 100644 index 8b13789179..0000000000 --- a/api/Health_Analyst_Blueprint +++ /dev/null @@ -1 +0,0 @@ - diff --git a/api/backend/Health_Analyst_Blueprint/average_duration b/api/backend/Health_Analyst_Blueprint/average_duration new file mode 100644 index 0000000000..810cefba2d --- /dev/null +++ b/api/backend/Health_Analyst_Blueprint/average_duration @@ -0,0 +1,50 @@ +from flask import Blueprint, jsonify, request +from backend.db_connection import db +from mysql.connector import Error +from flask import current_app + +# Create a Blueprint for average duration route +average_duration = Blueprint("average_duration", __name__) + +@average_duration.route("/client_workout_log/avg_duration", methods=["GET"]) +def get_average_workout_duration(): + # Get query parameters for filtering + try: + year = request.args.get("year") + week = request.args.get("week") + + current_app.logger.debug(f'Query parameters - country: {country}, focus_area: {focus_area}, founding_year: {founding_year}') + + # Prepare the Base query + query = """ + SELECT + c.client_id, + YEAR(cwl.date) AS year, + WEEK(cwl.date, 1) AS week, + AVG(cwl.duration_minutes) AS avg_duration + FROM Client c + JOIN Client_Workout_Log cwl ON c.client_id = cwl.client_id + WHERE cwl.completion_status = 'completed' + """ + params = [] + if year: + query += " AND YEAR(cwl.date) = %s" + params.append(year) + if week: + query += " AND WEEK(cwl.date, 1) = %s" + params.append(week) + query += """ + GROUP BY c.client_id, YEAR(cwl.date), WEEK(cwl.date, 1) + ORDER BY c.client_id, year, week; + """ + + current_app.logger.debug(f'Executing query: {query} with params: {params}') + cursor.execute(query, params) + duration = cursor.fetchall() + cursor.close() + + current_app.logger.info(f'Successfully retrieved {len(ngos)} NGOs') + return jsonify(duration), 200 + except Error as e: + current_app.logger.error(f'Database error in get_average_workout_duration: {str(e)}') + return jsonify({"error": str(e)}), 500 diff --git a/api/backend/Health_Analyst_Blueprint/client_info b/api/backend/Health_Analyst_Blueprint/client_info new file mode 100644 index 0000000000..ab7c571aa6 --- /dev/null +++ b/api/backend/Health_Analyst_Blueprint/client_info @@ -0,0 +1,68 @@ +from flask import Blueprint, jsonify, request +from backend.db_connection import db +from mysql.connector import Error +from flask import current_app + + +client_info = Blueprint('client_info', __name__) +@client_info.route("/client/", methods=["GET"]) +def get_client_info(client_id): + try: + query = """ + SELECT + c.client_id, + c.first_name, + c.last_name, + c.date_of_birth, + c.Goals, + c.fitness_level, + c.Age, + c.join_date + FROM Client c; + """ + + cursor = db.get_db().cursor() + cursor.execute(query) + clients = cursor.fetchall() + cursor.close() + return jsonify(clients), 200 + except Error as e: + return jsonify({"error": str(e)}), 500 + + +@client_info.route("/client/", methods=["PUT"]) +def update_client_info(client_id): + try: + data = request.getjson() + + fields = [ + 'first_name', + 'last_name', + 'date_of_birth', + 'Goals', + 'fitness_level', + 'Age', + 'join_date' + ] + updates = [] + params = [] + + for f in fields: + if f in data: + updates.append(f"{f} = %s") + params.append(date[f]) + if not updates: + return jsonify({"error": "No valid fields provided."}), 400 + params.append(client_id) + + query = f""" + UPDATE Client + SET {", ".join(updates)} + WHERE client_id = %s + """ + cursor = db.get_db().cursor() + cursor.execute(query, params) + cursor.close() + return jsonify({"message: Client demographic information updated"}), 200 + except Error as e: + return jsonify({"error": str(e)}), 500 \ No newline at end of file diff --git a/api/backend/Health_Analyst_Blueprint/health_metrics b/api/backend/Health_Analyst_Blueprint/health_metrics new file mode 100644 index 0000000000..ced261f6ff --- /dev/null +++ b/api/backend/Health_Analyst_Blueprint/health_metrics @@ -0,0 +1,114 @@ +from flask import Blueprint, jsonify, request +from backend.db_connection import db +from mysql.connector import Error +from flask import current_app + + +health_metrics = Blueprint('health_metrics', __name__) +@health_metrics.route("/health_metrics", methods=["GET"]) +def get_most_recent_health_metrics(): + try: + query = """ + SELECT + hm.client_id, + hm.record_date, + hm.weight_kg, + hm.body_fat_percentage, + hm.heart_rate + FROM Health_Metrics hm + WHERE hm.record_date = ( + SELECT MAX(record_date) + FROM Health_Metrics + WHERE client_id = hm.client_id + ); + """ + current_app.logger.debug(f'Executing query: {query}') + cursor.execute(query) + metrics = cursor.fetchall() + cursor.close() + + current_app.logger.info(f'Successfully retrieved {len(metrics)} health metric records') + return jsonify(metrics), 200 + except Error as e: + current_app.logger.error(f'Database error in get_most_recent_health_metric: {str(e)}') + return jsonify({"error": str(e)}), 500 + + +@health_metrics.route("/health_metrics", methods=["POST"]) +def add_health_metric(): + try: + data = request.get_json() + required_fields = [ + 'client_id', + 'record_date', + 'weight_kg', + 'body_fat_percentage', + 'heart-rate' + ] + + for field in allowed_fields: + if field not in data: + return jsonify({"error": f"Missing required field: {field}"}) + + query = """ + INSERT INTO Health_Metrics + (client_id, record_date, weight_kg, body_fat_percentage, heart_rate) + VALUES (%s, %s, %s, %s, %s); + """ + params = ( + data['client_id'], + data['record_date'], + data['weight_kg'], + data['body_fat_percentage'], + data['heart_rate'] + ) + + current_app.logger.debug(f'Executing query: {query}') + cursor.execute(query, params) + cursor.close() + + current_app.logger.info("New metric successfully created") + return jsonify({"message: Health metric record added successfully"}), 201 + except Error as e: + current_app.logger.error(f'Database error in add_health_metric: {str(e)}') + return jsonify({"error": str(e)}), 500 + + +@health_metrics.route("/health_metrics", methods=["PUT"]) +def update_health_metric(metric_id): + try: + data = request.get_json() + + fields = [ + 'record_date', + 'weight_kg', + 'body_fat_percentage', + 'heart_rate' + ] + + updates = [] + params = [] + + for f in fields: + if f in data: + updates.append(f"{f} = %s") + params.append(data[f]) + if not updates: + return jsonify({"error": "No valid fields provided"}, 400) + params.append(metric_id) + + query = f""" + UPDATE Health_Metrics + SET{", ".join(updates)} + WHERE metric_id = %s; + """ + + current_app.logger.debug(f'Executing query: {query}') + cursor.execute(query, params) + cursor.close() + + current_app.logger.info("Health metric successfully updated") + return jsonify({"message: Health metric record updated successfully"}), 200 + except Error as e: + current_app.logger.error(f'Database error in update_health_metric: {str(e)}') + return jsonify({"error": str(e)}), 500 From ea4e0609b601d8daeada48470c5456d1ca0d96a8 Mon Sep 17 00:00:00 2001 From: Laila-2006 Date: Wed, 3 Dec 2025 09:01:50 -0500 Subject: [PATCH 3/7] routes --- .../health_progression | 31 ++++++++++++++++ .../program_completion_rate | 36 +++++++++++++++++++ .../workout_program_frequency | 9 +++++ 3 files changed, 76 insertions(+) create mode 100644 api/backend/Health_Analyst_Blueprint/health_progression create mode 100644 api/backend/Health_Analyst_Blueprint/program_completion_rate create mode 100644 api/backend/Health_Analyst_Blueprint/workout_program_frequency diff --git a/api/backend/Health_Analyst_Blueprint/health_progression b/api/backend/Health_Analyst_Blueprint/health_progression new file mode 100644 index 0000000000..4d7c740a25 --- /dev/null +++ b/api/backend/Health_Analyst_Blueprint/health_progression @@ -0,0 +1,31 @@ +from flask import Blueprint, jsonify, request +from backend.db_connection import db +from mysql.connector import Error +from flask import current_app + + +health_progression = Blueprint('health_progression', __name__) +@health_progression.route("/health_metric//month", methods=["GET"]) +def get_health_progression(): + try: + query = """ + SELECT + client_id, + MONTH(hm.record_date) AS month, + AVG(weight_kg), + AVG(body_fat_percentage) + FROM Health_Metrics hm + GROUP BY client_id, MONTH(hm.record_date) + ORDER BY client_id, month; + """ + + current_app.logger.debug(f'Executing query: {query}') + cursor.execute(query) + progression = cursor.fetchall() + cursor.close() + + current_app.logger.info(f'Successfully retrieved {len(progression)} health metric records') + return jsonify(progression), 200 + except Error as e: + current_app.logger.error(f'Database error in get_health_progression: {str(e)}') + return jsonify({"error": str(e)}), 500 \ No newline at end of file diff --git a/api/backend/Health_Analyst_Blueprint/program_completion_rate b/api/backend/Health_Analyst_Blueprint/program_completion_rate new file mode 100644 index 0000000000..3e4b68a56b --- /dev/null +++ b/api/backend/Health_Analyst_Blueprint/program_completion_rate @@ -0,0 +1,36 @@ +from flask import Blueprint, jsonify, request +from backend.db_connection import db +from mysql.connector import Error +from flask import current_app + + +analytics = Blueprint('analytics', __name__) +@analytics.route("/client_specific_workout_program//completion_rate", methods=["GET"]) +def get_program_completion_rate(): + try: + query = """ + SELECT + cswp.program_id, + cswp.name AS program_name, + COUNT(cwl.log_id) AS total_workouts, + SUM(cwl.completion_status = 'completed') AS completed_workouts, + ROUND( + SUM(cwl.completion_status = 'completed') / COUNT(cwl.log_id), + 3 + ) AS completion_rate + FROM Client_Specific_Workout_Program cswp JOIN Client_Workout_Log cwl + ON cswp.workout_id = cwl.workout_id + AND cswp.client_id = cwl.client_id + GROUP BY cswp.program_id, cswp.name + ORDER BY completion_rate DESC; + """ + current_app.logger.debug(f'Executing query: {query}') + cursor.execute(query) + completion = cursor.fetchall() + cursor.close() + + current_app.logger.info(f'Successfully retrieved program completion rate') + return jsonify(completion), 200 + except Error as e: + current_app.logger.error(f'Database error in get_program_completion_rate: {str(e)}') + return jsonify({"error": str(e)}), 500 diff --git a/api/backend/Health_Analyst_Blueprint/workout_program_frequency b/api/backend/Health_Analyst_Blueprint/workout_program_frequency new file mode 100644 index 0000000000..a2f801cd27 --- /dev/null +++ b/api/backend/Health_Analyst_Blueprint/workout_program_frequency @@ -0,0 +1,9 @@ +from flask import Blueprint, jsonify, request +from backend.db_connection import db +from mysql.connector import Error +from flask import current_app + + +analytics = Blueprint('analytics', __name__) +@analytics.route("/workout_session_template/used", methods=["GET"]) +def get_program_frequency(): \ No newline at end of file From ae1026fdc238b4ac160edc05fb7993fc0393a7fd Mon Sep 17 00:00:00 2001 From: Laila-2006 Date: Wed, 3 Dec 2025 14:39:29 -0500 Subject: [PATCH 4/7] routes --- .../Health_Analyst_Blueprint/average_duration | 4 +--- .../workout_program_frequency | 24 ++++++++++++++++++- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/api/backend/Health_Analyst_Blueprint/average_duration b/api/backend/Health_Analyst_Blueprint/average_duration index 810cefba2d..8b7fe7d147 100644 --- a/api/backend/Health_Analyst_Blueprint/average_duration +++ b/api/backend/Health_Analyst_Blueprint/average_duration @@ -13,8 +13,6 @@ def get_average_workout_duration(): year = request.args.get("year") week = request.args.get("week") - current_app.logger.debug(f'Query parameters - country: {country}, focus_area: {focus_area}, founding_year: {founding_year}') - # Prepare the Base query query = """ SELECT @@ -38,7 +36,7 @@ def get_average_workout_duration(): ORDER BY c.client_id, year, week; """ - current_app.logger.debug(f'Executing query: {query} with params: {params}') + current_app.logger.debug(f'Executing query: {query}') cursor.execute(query, params) duration = cursor.fetchall() cursor.close() diff --git a/api/backend/Health_Analyst_Blueprint/workout_program_frequency b/api/backend/Health_Analyst_Blueprint/workout_program_frequency index a2f801cd27..449f004116 100644 --- a/api/backend/Health_Analyst_Blueprint/workout_program_frequency +++ b/api/backend/Health_Analyst_Blueprint/workout_program_frequency @@ -6,4 +6,26 @@ from flask import current_app analytics = Blueprint('analytics', __name__) @analytics.route("/workout_session_template/used", methods=["GET"]) -def get_program_frequency(): \ No newline at end of file +def get_program_frequency(): + try: + query = """ + SELECT + cwl.workout_id, + wst.name, + COUNT(*) AS used + FROM Client_Workout_Log cwl JOIN Workout_Session_Template wst + ON cwl.workout_id = wst.workout_id + GROUP BY cwl.workout_id, wst.name + ORDER BY used DESC; + """ + + current_app.logger.debug(f'Executing query: {query}') + cursor.execute(query) + frequency = cursor.fetchall() + cursor.close() + + current_app.logger.info(f'Successfully retried workout program frequency') + return jsonify(frequency), 200 + except Error as e: + current_app.logger.error(f'Database error in get_program_frequecy: {str(e)}') + return jsonify({"error": str(e)}), 500 From df0ef39d0b38a62f9cf6ecccd5e900c3b8149610 Mon Sep 17 00:00:00 2001 From: Laila-2006 Date: Thu, 4 Dec 2025 19:22:35 -0500 Subject: [PATCH 5/7] routes --- .../Health_Analyst_Blueprint/workout_program_frequency | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/api/backend/Health_Analyst_Blueprint/workout_program_frequency b/api/backend/Health_Analyst_Blueprint/workout_program_frequency index 449f004116..233965c188 100644 --- a/api/backend/Health_Analyst_Blueprint/workout_program_frequency +++ b/api/backend/Health_Analyst_Blueprint/workout_program_frequency @@ -4,8 +4,8 @@ from mysql.connector import Error from flask import current_app -analytics = Blueprint('analytics', __name__) -@analytics.route("/workout_session_template/used", methods=["GET"]) +frequency = Blueprint('frequency', __name__) +@frequency.route("/workout_session_template/used", methods=["GET"]) def get_program_frequency(): try: query = """ @@ -21,11 +21,11 @@ def get_program_frequency(): current_app.logger.debug(f'Executing query: {query}') cursor.execute(query) - frequency = cursor.fetchall() + count = cursor.fetchall() cursor.close() current_app.logger.info(f'Successfully retried workout program frequency') - return jsonify(frequency), 200 + return jsonify(count), 200 except Error as e: current_app.logger.error(f'Database error in get_program_frequecy: {str(e)}') return jsonify({"error": str(e)}), 500 From 512c1d96c13b4ba81e8922c70aead9e33c0af71e Mon Sep 17 00:00:00 2001 From: Laila-2006 Date: Thu, 4 Dec 2025 19:22:46 -0500 Subject: [PATCH 6/7] pages --- app/src/pages/03_Average_Duration | 0 app/src/pages/04_Client_info | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 app/src/pages/03_Average_Duration create mode 100644 app/src/pages/04_Client_info diff --git a/app/src/pages/03_Average_Duration b/app/src/pages/03_Average_Duration new file mode 100644 index 0000000000..e69de29bb2 diff --git a/app/src/pages/04_Client_info b/app/src/pages/04_Client_info new file mode 100644 index 0000000000..e69de29bb2 From cbe34faa5bb09f53d536420425a11c2e24a56c90 Mon Sep 17 00:00:00 2001 From: Laila-2006 Date: Fri, 5 Dec 2025 15:20:36 -0500 Subject: [PATCH 7/7] pages --- app/src/pages/05_Health_Metrics | 0 app/src/pages/06_Progression | 0 app/src/pages/07_Program_Completion | 0 app/src/pages/08_Program_Frequency | 0 app/src/pages/Analyst_Home | 0 5 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 app/src/pages/05_Health_Metrics create mode 100644 app/src/pages/06_Progression create mode 100644 app/src/pages/07_Program_Completion create mode 100644 app/src/pages/08_Program_Frequency create mode 100644 app/src/pages/Analyst_Home diff --git a/app/src/pages/05_Health_Metrics b/app/src/pages/05_Health_Metrics new file mode 100644 index 0000000000..e69de29bb2 diff --git a/app/src/pages/06_Progression b/app/src/pages/06_Progression new file mode 100644 index 0000000000..e69de29bb2 diff --git a/app/src/pages/07_Program_Completion b/app/src/pages/07_Program_Completion new file mode 100644 index 0000000000..e69de29bb2 diff --git a/app/src/pages/08_Program_Frequency b/app/src/pages/08_Program_Frequency new file mode 100644 index 0000000000..e69de29bb2 diff --git a/app/src/pages/Analyst_Home b/app/src/pages/Analyst_Home new file mode 100644 index 0000000000..e69de29bb2