Get project working locally
This commit is contained in:
58
app/templates/_layout.html
Normal file
58
app/templates/_layout.html
Normal 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>© 2024 BP Tracker. All rights reserved.</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
55
app/templates/add_reading.html
Normal file
55
app/templates/add_reading.html
Normal 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 %}
|
||||
106
app/templates/dashboard.html
Normal file
106
app/templates/dashboard.html
Normal 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 %}
|
||||
56
app/templates/edit_reading.html
Normal file
56
app/templates/edit_reading.html
Normal 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
32
app/templates/login.html
Normal 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 %}
|
||||
58
app/templates/profile.html
Normal file
58
app/templates/profile.html
Normal 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
42
app/templates/signup.html
Normal 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 %}
|
||||
Reference in New Issue
Block a user