Get project working locally

This commit is contained in:
Peter Stockings
2024-12-24 00:57:08 +11:00
parent d4fc1868ab
commit 11239fd4f5
22 changed files with 1214 additions and 14 deletions

View File

@@ -0,0 +1,58 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}BP Tracker{% endblock %}</title>
<script src="/static/js/tailwindcss@3.2.4.js"></script>
</head>
<body class="bg-gray-100 text-gray-800">
<!-- Navbar -->
<nav class="bg-blue-600 text-white p-4">
<div class="container mx-auto flex justify-between items-center">
<a href="/" class="text-2xl font-bold">BP Tracker</a>
<div>
{% if current_user.is_authenticated %}
<a href="{{ url_for('main.dashboard') }}" class="px-4 py-2 hover:underline">Dashboard</a>
<a href="{{ url_for('user.profile') }}" class="px-4 py-2 hover:underline">Profile</a>
<a href="{{ url_for('auth.logout') }}" class="px-4 py-2 bg-red-500 rounded hover:bg-red-600">Logout</a>
{% else %}
<a href="{{ url_for('auth.login') }}" class="px-4 py-2 hover:underline">Login</a>
<a href="{{ url_for('auth.signup') }}"
class="px-4 py-2 bg-white text-blue-600 rounded hover:bg-gray-200">Signup</a>
{% endif %}
</div>
</div>
</nav>
{% with messages = get_flashed_messages(with_categories=True) %}
{% if messages %}
<div class="container mx-auto mt-4">
{% for category, message in messages %}
<div class="p-4 mb-4 rounded text-white bg-{{ 'red' if category == 'danger' else 'green' }}-500">
{{ message }}
</div>
{% endfor %}
</div>
{% endif %}
{% endwith %}
<!-- Main Content -->
<main class="container mx-auto mt-6">
{% block content %}
<!-- Content goes here -->
{% endblock %}
</main>
<!-- Footer -->
<footer class="bg-gray-800 text-white py-4 mt-10">
<div class="container mx-auto text-center">
<p>&copy; 2024 BP Tracker. All rights reserved.</p>
</div>
</footer>
</body>
</html>

View File

@@ -0,0 +1,55 @@
{% extends "_layout.html" %}
{% block content %}
<div class="max-w-lg mx-auto bg-white p-8 rounded-lg shadow-md">
<h1 class="text-3xl font-bold text-center text-gray-800 mb-6">Add Reading</h1>
<form method="POST" action="{{ url_for('main.add_reading') }}" novalidate class="space-y-6">
{{ form.hidden_tag() }}
<!-- Timestamp Field -->
<div>
{{ form.timestamp.label(class="block text-sm font-medium text-gray-700 mb-2") }}
{{ form.timestamp(class="w-full p-3 border border-gray-300 rounded-lg shadow-sm focus:outline-none
focus:ring-2 focus:ring-blue-500 focus:border-blue-500") }}
{% for error in form.timestamp.errors %}
<p class="text-sm text-red-600 mt-1">{{ error }}</p>
{% endfor %}
</div>
<!-- Systolic Field -->
<div>
{{ form.systolic.label(class="block text-sm font-medium text-gray-700 mb-2") }}
{{ form.systolic(class="w-full p-3 border border-gray-300 rounded-lg shadow-sm focus:outline-none
focus:ring-2 focus:ring-blue-500 focus:border-blue-500") }}
{% for error in form.systolic.errors %}
<p class="text-sm text-red-600 mt-1">{{ error }}</p>
{% endfor %}
</div>
<!-- Diastolic Field -->
<div>
{{ form.diastolic.label(class="block text-sm font-medium text-gray-700 mb-2") }}
{{ form.diastolic(class="w-full p-3 border border-gray-300 rounded-lg shadow-sm focus:outline-none
focus:ring-2 focus:ring-blue-500 focus:border-blue-500") }}
{% for error in form.diastolic.errors %}
<p class="text-sm text-red-600 mt-1">{{ error }}</p>
{% endfor %}
</div>
<!-- Heart Rate Field -->
<div>
{{ form.heart_rate.label(class="block text-sm font-medium text-gray-700 mb-2") }}
{{ form.heart_rate(class="w-full p-3 border border-gray-300 rounded-lg shadow-sm focus:outline-none
focus:ring-2 focus:ring-blue-500 focus:border-blue-500") }}
{% for error in form.heart_rate.errors %}
<p class="text-sm text-red-600 mt-1">{{ error }}</p>
{% endfor %}
</div>
<!-- Submit Button -->
<div>
{{ form.submit(class="w-full bg-gradient-to-r from-blue-500 to-blue-700 text-white py-3 rounded-lg
font-semibold hover:from-blue-600 hover:to-blue-800 shadow-lg") }}
</div>
</form>
</div>
{% endblock %}

View File

@@ -0,0 +1,106 @@
{% extends "_layout.html" %}
{% block content %}
<div class="max-w-5xl mx-auto p-4 space-y-6">
<!-- Header Section with "Add New Reading" Button -->
<div class="flex justify-between items-center">
<h1 class="text-2xl font-bold text-gray-800">Dashboard</h1>
<a href="{{ url_for('main.add_reading') }}"
class="bg-blue-600 text-white px-4 py-2 rounded shadow hover:bg-blue-700">
+ Add New Reading
</a>
</div>
<!-- Weekly Summary -->
<div class="bg-gradient-to-r from-blue-500 to-blue-700 text-white p-6 rounded-lg shadow-md">
<h3 class="text-lg font-bold">Weekly Summary</h3>
<div class="flex justify-between mt-4">
<div>
<p class="text-sm font-semibold">Systolic Average</p>
<p class="text-2xl">{{ systolic_avg }} <span class="text-base">mmHg</span></p>
</div>
<div>
<p class="text-sm font-semibold">Diastolic Average</p>
<p class="text-2xl">{{ diastolic_avg }} <span class="text-base">mmHg</span></p>
</div>
<div>
<p class="text-sm font-semibold">Heart Rate Average</p>
<p class="text-2xl">{{ heart_rate_avg }} <span class="text-base">bpm</span></p>
</div>
</div>
</div>
<!-- Progress Badges -->
<div>
<h3 class="text-lg font-bold text-gray-800 mb-2">Progress Badges</h3>
<div class="flex flex-wrap gap-4">
{% for badge in badges %}
<div class="bg-green-100 text-green-800 px-4 py-2 rounded shadow text-sm font-medium">
{{ badge }}
</div>
{% endfor %}
</div>
</div>
<!-- Filter Form -->
<form method="POST" action="{{ url_for('main.filter_dashboard') }}" class="p-4 bg-white rounded-lg shadow-md">
<h3 class="text-lg font-bold text-gray-800 mb-4">Filter Readings</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label for="start_date" class="block text-sm font-medium text-gray-700">Start Date</label>
<input type="date" name="start_date" id="start_date" class="w-full p-2 border rounded">
</div>
<div>
<label for="end_date" class="block text-sm font-medium text-gray-700">End Date</label>
<input type="date" name="end_date" id="end_date" class="w-full p-2 border rounded">
</div>
</div>
<div class="mt-4">
<button type="submit" class="w-full md:w-auto bg-blue-600 text-white px-6 py-2 rounded hover:bg-blue-700">
Apply Filters
</button>
</div>
</form>
<!-- Readings Table -->
<div class="bg-white rounded-lg shadow-md overflow-hidden">
<table class="w-full bg-white rounded shadow border-collapse">
<thead class="bg-gray-200">
<tr>
<th class="p-2 text-left">Timestamp</th>
<th class="p-2 text-left">Systolic</th>
<th class="p-2 text-left">Diastolic</th>
<th class="p-2 text-left">Heart Rate</th>
<th class="p-2 text-left">Actions</th>
</tr>
</thead>
<tbody>
{% for reading in readings %}
<tr class="border-t hover:bg-gray-100">
<td class="p-2">{{ reading.timestamp }}</td>
<td class="p-2">{{ reading.systolic }}</td>
<td class="p-2">{{ reading.diastolic }}</td>
<td class="p-2">{{ reading.heart_rate }}</td>
<td class="p-2">
<a href="{{ url_for('main.edit_reading', reading_id=reading.id) }}"
class="text-blue-600 hover:underline">Edit</a>
<form method="POST" action="{{ url_for('main.delete_reading', reading_id=reading.id) }}"
class="inline">
{{ delete_form.hidden_tag() }}
<button type="submit" class="text-red-600 hover:underline ml-2">
Delete
</button>
</form>
</td>
</tr>
{% else %}
<tr>
<td colspan="5" class="p-2 text-center text-gray-500">No readings found.</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,56 @@
{% extends "_layout.html" %}
{% block content %}
<div class="max-w-lg mx-auto bg-white p-8 rounded-lg shadow-md">
<h1 class="text-3xl font-bold text-center text-gray-800 mb-6">Edit Reading</h1>
<form method="POST" action="{{ url_for('main.edit_reading', reading_id=reading.id) }}" novalidate>
{{ form.hidden_tag() }}
<!-- Timestamp Field -->
<div class="mb-4">
{{ form.timestamp.label(class="block text-sm font-medium text-gray-700") }}
{{ form.timestamp(class="w-full p-3 border rounded-lg shadow-sm focus:outline-none focus:ring-2
focus:ring-blue-500 focus:border-blue-500") }}
{% for error in form.timestamp.errors %}
<p class="text-sm text-red-600 mt-1">{{ error }}</p>
{% endfor %}
</div>
<!-- Systolic Field -->
<div class="mb-4">
{{ form.systolic.label(class="block text-sm font-medium text-gray-700") }}
{{ form.systolic(class="w-full p-3 border rounded-lg shadow-sm focus:outline-none focus:ring-2
focus:ring-blue-500 focus:border-blue-500") }}
{% for error in form.systolic.errors %}
<p class="text-sm text-red-600 mt-1">{{ error }}</p>
{% endfor %}
</div>
<!-- Diastolic Field -->
<div class="mb-4">
{{ form.diastolic.label(class="block text-sm font-medium text-gray-700") }}
{{ form.diastolic(class="w-full p-3 border rounded-lg shadow-sm focus:outline-none focus:ring-2
focus:ring-blue-500 focus:border-blue-500") }}
{% for error in form.diastolic.errors %}
<p class="text-sm text-red-600 mt-1">{{ error }}</p>
{% endfor %}
</div>
<!-- Heart Rate Field -->
<div class="mb-4">
{{ form.heart_rate.label(class="block text-sm font-medium text-gray-700") }}
{{ form.heart_rate(class="w-full p-3 border rounded-lg shadow-sm focus:outline-none focus:ring-2
focus:ring-blue-500 focus:border-blue-500") }}
{% for error in form.heart_rate.errors %}
<p class="text-sm text-red-600 mt-1">{{ error }}</p>
{% endfor %}
</div>
<!-- Submit Button -->
<div>
<button type="submit" class="w-full bg-blue-600 text-white py-3 rounded-lg font-semibold hover:bg-blue-700">
Save Changes
</button>
</div>
</form>
</div>
{% endblock %}

32
app/templates/login.html Normal file
View File

@@ -0,0 +1,32 @@
{% extends "_layout.html" %}
{% block content %}
<div class="max-w-md mx-auto bg-white p-6 rounded-lg shadow-md">
<h1 class="text-2xl font-bold text-center mb-4">Login</h1>
<form method="POST" action="{{ url_for('auth.login') }}" novalidate>
{{ form.hidden_tag() }}
<!-- Username Field -->
<div class="mb-4">
{{ form.username.label(class="block text-sm font-medium text-gray-700") }}
{{ form.username(class="w-full p-2 border rounded focus:outline-none focus:ring-2 focus:ring-blue-500") }}
{% for error in form.username.errors %}
<p class="text-sm text-red-600 mt-1">{{ error }}</p>
{% endfor %}
</div>
<!-- Password Field -->
<div class="mb-4">
{{ form.password.label(class="block text-sm font-medium text-gray-700") }}
{{ form.password(class="w-full p-2 border rounded focus:outline-none focus:ring-2 focus:ring-blue-500") }}
{% for error in form.password.errors %}
<p class="text-sm text-red-600 mt-1">{{ error }}</p>
{% endfor %}
</div>
<!-- Submit Button -->
<div>
{{ form.submit(class="w-full bg-blue-600 text-white py-2 rounded hover:bg-blue-700") }}
</div>
</form>
</div>
{% endblock %}

View File

@@ -0,0 +1,58 @@
{% extends "_layout.html" %}
{% block content %}
<div class="max-w-2xl mx-auto bg-white p-6 rounded-lg shadow-md">
<h1 class="text-2xl font-bold text-center mb-6">Profile Settings</h1>
<div class="flex items-center justify-center mb-4">
{% if profile.profile_pic %}
<img src="data:image/jpeg;base64,{{ profile.profile_pic }}" alt="Profile Picture"
class="w-24 h-24 rounded-full border">
{% else %}
<img src="{{ url_for('static', filename='default.png') }}" alt="Default Profile Picture"
class="w-24 h-24 rounded-full border">
{% endif %}
</div>
<form method="POST" enctype="multipart/form-data">
{{ form.hidden_tag() }}
<div class="mb-4">
{{ form.name.label(class="block text-sm font-medium text-gray-700") }}
{{ form.name(class="w-full p-2 border rounded focus:outline-none focus:ring-2 focus:ring-blue-500") }}
</div>
<div class="mb-4">
{{ form.email.label(class="block text-sm font-medium text-gray-700") }}
{{ form.email(class="w-full p-2 border rounded focus:outline-none focus:ring-2 focus:ring-blue-500") }}
</div>
<div class="mb-4">
{{ form.profile_pic.label(class="block text-sm font-medium text-gray-700") }}
{{ form.profile_pic(class="w-full p-2 border rounded focus:outline-none focus:ring-2 focus:ring-blue-500")
}}
</div>
<div class="mb-4">
{{ form.systolic_threshold.label(class="block text-sm font-medium text-gray-700") }}
{{ form.systolic_threshold(class="w-full p-2 border rounded focus:outline-none focus:ring-2
focus:ring-blue-500") }}
</div>
<div class="mb-4">
{{ form.diastolic_threshold.label(class="block text-sm font-medium text-gray-700") }}
{{ form.diastolic_threshold(class="w-full p-2 border rounded focus:outline-none focus:ring-2
focus:ring-blue-500") }}
</div>
<div class="mb-4 flex items-center">
{{ form.dark_mode }}
{{ form.dark_mode.label(class="ml-2 text-sm font-medium text-gray-700") }}
</div>
<div>
{{ form.submit(class="w-full bg-blue-600 text-white py-2 rounded hover:bg-blue-700") }}
</div>
</form>
</div>
{% endblock %}

42
app/templates/signup.html Normal file
View File

@@ -0,0 +1,42 @@
{% extends "_layout.html" %}
{% block content %}
<div class="max-w-md mx-auto bg-white p-6 rounded-lg shadow-md">
<h1 class="text-2xl font-bold text-center mb-4">Sign Up</h1>
<form method="POST" action="{{ url_for('auth.signup') }}" novalidate>
{{ form.hidden_tag() }}
<!-- Username Field -->
<div class="mb-4">
{{ form.username.label(class="block text-sm font-medium text-gray-700") }}
{{ form.username(class="w-full p-2 border rounded focus:outline-none focus:ring-2 focus:ring-blue-500") }}
{% for error in form.username.errors %}
<p class="text-sm text-red-600 mt-1">{{ error }}</p>
{% endfor %}
</div>
<!-- Password Field -->
<div class="mb-4">
{{ form.password.label(class="block text-sm font-medium text-gray-700") }}
{{ form.password(class="w-full p-2 border rounded focus:outline-none focus:ring-2 focus:ring-blue-500") }}
{% for error in form.password.errors %}
<p class="text-sm text-red-600 mt-1">{{ error }}</p>
{% endfor %}
</div>
<!-- Confirm Password Field -->
<div class="mb-4">
{{ form.confirm_password.label(class="block text-sm font-medium text-gray-700") }}
{{ form.confirm_password(class="w-full p-2 border rounded focus:outline-none focus:ring-2
focus:ring-blue-500") }}
{% for error in form.confirm_password.errors %}
<p class="text-sm text-red-600 mt-1">{{ error }}</p>
{% endfor %}
</div>
<!-- Submit Button -->
<div>
{{ form.submit(class="w-full bg-blue-600 text-white py-2 rounded hover:bg-blue-700") }}
</div>
</form>
</div>
{% endblock %}