From 0fa3535c96cea1eb74f5692e307ca166b803be25 Mon Sep 17 00:00:00 2001 From: Peter Stockings Date: Thu, 26 Dec 2024 17:09:52 +1100 Subject: [PATCH] Add week and month view --- app/routes.py | 15 ++- app/static/css/tailwind.css | 63 +++++++++++ app/templates/dashboard.html | 211 ++++++++++++++++++++++++++--------- 3 files changed, 237 insertions(+), 52 deletions(-) diff --git a/app/routes.py b/app/routes.py index 8d9cdae..2975388 100644 --- a/app/routes.py +++ b/app/routes.py @@ -11,7 +11,7 @@ from app.models import Profile, Reading, db, User from app.forms import DeleteForm, LoginForm, ProfileForm, ReadingForm, SignupForm from flask_login import login_user, login_required, current_user, logout_user import base64 -from datetime import datetime, timedelta +from datetime import date, datetime, timedelta from PIL import Image main = Blueprint('main', __name__) @@ -193,6 +193,14 @@ def dashboard(): diastolic = [reading.diastolic for reading in readings] heart_rate = [reading.heart_rate for reading in readings] + # Group readings by date + readings_by_date = {} + for reading in readings: + date_key = reading.timestamp.date() + if date_key not in readings_by_date: + readings_by_date[date_key] = [] + readings_by_date[date_key].append(reading) + # Render template return render_template( 'dashboard.html', @@ -208,7 +216,10 @@ def dashboard(): diastolic=diastolic, heart_rate=heart_rate, start_date=start_date, - end_date=end_date + end_date=end_date, + readings_by_date=readings_by_date, + date=date, + timedelta=timedelta ) @main.route('/add-reading', methods=['GET', 'POST']) diff --git a/app/static/css/tailwind.css b/app/static/css/tailwind.css index a21c32d..6c07246 100644 --- a/app/static/css/tailwind.css +++ b/app/static/css/tailwind.css @@ -850,6 +850,10 @@ video { grid-template-columns: repeat(1, minmax(0, 1fr)); } +.grid-cols-7 { + grid-template-columns: repeat(7, minmax(0, 1fr)); +} + .flex-col { flex-direction: column; } @@ -890,6 +894,11 @@ video { gap: 1.5rem; } +.gap-x-4 { + -moz-column-gap: 1rem; + column-gap: 1rem; +} + .space-x-2 > :not([hidden]) ~ :not([hidden]) { --tw-space-x-reverse: 0; margin-right: calc(0.5rem * var(--tw-space-x-reverse)); @@ -928,6 +937,12 @@ video { overflow-x: auto; } +.truncate { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + .whitespace-nowrap { white-space: nowrap; } @@ -960,6 +975,10 @@ video { border-bottom-width: 1px; } +.border-b-2 { + border-bottom-width: 2px; +} + .border-gray-300 { --tw-border-opacity: 1; border-color: rgb(209 213 219 / var(--tw-border-opacity, 1)); @@ -970,6 +989,16 @@ video { border-color: rgb(255 255 255 / var(--tw-border-opacity, 1)); } +.border-blue-600 { + --tw-border-opacity: 1; + border-color: rgb(37 99 235 / var(--tw-border-opacity, 1)); +} + +.border-green-200 { + --tw-border-opacity: 1; + border-color: rgb(187 247 208 / var(--tw-border-opacity, 1)); +} + .bg-blue-600 { --tw-bg-opacity: 1; background-color: rgb(37 99 235 / var(--tw-bg-opacity, 1)); @@ -1025,6 +1054,16 @@ video { background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1)); } +.bg-blue-100 { + --tw-bg-opacity: 1; + background-color: rgb(219 234 254 / var(--tw-bg-opacity, 1)); +} + +.bg-green-50 { + --tw-bg-opacity: 1; + background-color: rgb(240 253 244 / var(--tw-bg-opacity, 1)); +} + .bg-gradient-to-r { background-image: linear-gradient(to right, var(--tw-gradient-stops)); } @@ -1068,6 +1107,10 @@ video { padding: 2rem; } +.p-1 { + padding: 0.25rem; +} + .px-2 { padding-left: 0.5rem; padding-right: 0.5rem; @@ -1250,6 +1293,16 @@ video { color: rgb(239 68 68 / var(--tw-text-opacity, 1)); } +.text-blue-800 { + --tw-text-opacity: 1; + color: rgb(30 64 175 / var(--tw-text-opacity, 1)); +} + +.text-green-700 { + --tw-text-opacity: 1; + color: rgb(21 128 61 / var(--tw-text-opacity, 1)); +} + .no-underline { text-decoration-line: none; } @@ -1333,6 +1386,16 @@ video { background-color: rgb(185 28 28 / var(--tw-bg-opacity, 1)); } +.hover\:bg-green-200:hover { + --tw-bg-opacity: 1; + background-color: rgb(187 247 208 / var(--tw-bg-opacity, 1)); +} + +.hover\:bg-green-100:hover { + --tw-bg-opacity: 1; + background-color: rgb(220 252 231 / var(--tw-bg-opacity, 1)); +} + .hover\:text-blue-800:hover { --tw-text-opacity: 1; color: rgb(30 64 175 / var(--tw-text-opacity, 1)); diff --git a/app/templates/dashboard.html b/app/templates/dashboard.html index 643cf44..ebabd28 100644 --- a/app/templates/dashboard.html +++ b/app/templates/dashboard.html @@ -59,7 +59,7 @@ -
+

Blood Pressure (mmHg)

@@ -142,7 +142,7 @@
-
@@ -165,55 +165,166 @@
- -
- {% for reading in readings %} - - -
- - - - - {{ reading.relative_timestamp }} - -
- - -
- Blood Pressure - {{ reading.systolic }} - / - {{ reading.diastolic }} - mmHg -
- - -
-
- Heart Rate - {{ reading.heart_rate }} - bpm -
- -
- - - - -
-
-
- {% else %} -
- No readings found. +
+ +
+ + +
- {% endfor %} + + + + + +
+ {% set today = date.today() %} + {% for i in range(7) %} + {% set day = today - timedelta(days=today.weekday() - i) %} +
+
{{ day.strftime('%A, %b %d') }}
+ {% if day in readings_by_date %} + {% for reading in readings_by_date[day]|sort(attribute="timestamp", reverse = True) %} + +

+ {{ reading.systolic }}/{{ reading.diastolic }} mmHg +

+

{{ reading.heart_rate }} bpm

+ +
+ {{ reading.timestamp.strftime('%I:%M %p') }} +
+
+ {% endfor %} + {% else %} +
+ {% endif %} +
+ {% endfor %} +
+ + +
+ {% set current_date = date.today().replace(day=1) %} + +
+

{{ current_date.strftime('%B %Y') }}

+
+ + +
+
Sun
+
Mon
+
Tue
+
Wed
+
Thu
+
Fri
+
Sat
+
+ + +
+ {% set days_in_month = (current_date.replace(month=current_date.month % 12 + 1, day=1) - + timedelta(days=1)).day %} + {% set first_weekday = current_date.weekday() %} + + + {% for _ in range((first_weekday + 1) % 7) %} +
+ {% endfor %} + + + {% for day in range(1, days_in_month + 1) %} + {% set current_day = current_date.replace(day=day) %} +
+ +
{{ current_day.day }}
+ + + {% if current_day in readings_by_date %} + + + + {% endif %} + + + {% if current_day in readings_by_date %} + {% for reading in readings_by_date[current_day]|sort(attribute="timestamp", reverse = True) %} + +

+ {{ reading.systolic }}/{{ reading.diastolic }} mmHg +

+

{{ reading.heart_rate }} bpm

+ +
+ {{ reading.timestamp.strftime('%I:%M %p') }} +
+
+ {% endfor %} + {% else %} +
+ {% endif %} +
+ {% endfor %} +
+
+ +