Finished Multi-Habit-List feature and multiple habits for each habit_list

This commit is contained in:
Verox 2024-02-12 22:06:27 +01:00
parent 4dd997ce13
commit 4764112296
20 changed files with 348 additions and 493 deletions

54
app.py
View File

@ -5,6 +5,7 @@ from flask import Flask, render_template, redirect, url_for, request
from flask_login import login_required, LoginManager, login_user, logout_user, current_user from flask_login import login_required, LoginManager, login_user, logout_user, current_user
from models.Habit import Habit from models.Habit import Habit
from models.HabitList import HabitList
from models.HabitTrackings import HabitTrackings from models.HabitTrackings import HabitTrackings
from models.User import User from models.User import User
from utils import anonymous_required from utils import anonymous_required
@ -120,20 +121,20 @@ def logout():
@app.route('/') @app.route('/')
def index(): def index():
if current_user.is_authenticated: if current_user.is_authenticated:
habits = current_user.get_habits() habit_lists = current_user.get_habitLists()
name = "Hallo " + current_user.name name = "Hallo " + current_user.name
else: else:
habits = [] habit_lists = []
name = "Bitte melde dich an." name = "Bitte melde dich an."
# Sort habits by whether they have been checked today and then by slot # Sort habits by whether they have been checked today and then by slot
habits.sort(key=lambda habit: (habit.checked, habit.slot)) # habits.sort(key=lambda habit: (habit.checked, habit.slot))
return render_template( return render_template(
'index.html', 'index.html',
title=name, title=name,
utc_dt=datetime.datetime.now().strftime("%d.%m.%Y %H:%M %A"), utc_dt=datetime.datetime.now().strftime("%d.%m.%Y %H:%M %A"),
habits=habits, habit_lists=habit_lists,
errors={}, errors={},
) )
@ -156,6 +157,7 @@ def habit_create():
note = request.form.get('note') note = request.form.get('note')
times = request.form.get('times') times = request.form.get('times')
unit = request.form.get('unit') unit = request.form.get('unit')
list_id = request.form.get('list_query')
# Check for errors # Check for errors
errors = {} errors = {}
@ -167,6 +169,8 @@ def habit_create():
note = '' note = ''
if not unit: if not unit:
errors['unit'] = 'Die Einheit ist erforderlich.' errors['unit'] = 'Die Einheit ist erforderlich.'
if not list_id:
errors['list_query'] = 'Die Habitliste ist erforderlich.'
# Check if times is an integer # Check if times is an integer
try: try:
@ -190,7 +194,8 @@ def habit_create():
note=note, note=note,
times=times, times=times,
unit=unit, unit=unit,
errors=errors errors=errors,
list_id=list_id
) )
# Map unit to integer # Map unit to integer
@ -212,6 +217,45 @@ def habit_create():
return redirect(url_for('index')) return redirect(url_for('index'))
@app.route('/habit-list')
@login_required
def habit_list_creation():
return render_template(
'habit-list.html',
title='Erstelle eine Habitliste',
errors={},
)
@app.route('/habit-list', methods=['POST'])
@login_required
def habit_list_create():
name = request.form.get('name')
description = request.form.get('description')
# Check for errors
errors = {}
if not name:
errors['name'] = 'Der Name ist erforderlich.'
if not description:
note = ''
if errors:
return render_template(
'habit-list.html',
title='Erstelle eine Habitliste',
name=name,
description=description,
errors=errors
)
# Save habit to database
habit = HabitList.create(current_user.id, name, description)
# Back to index
return redirect(url_for('index'))
@app.route('/profile') @app.route('/profile')
@login_required @login_required
def profile(): def profile():

View File

@ -102,24 +102,46 @@ def get_habits(list_id: int):
def get_heatmap_value(user_id: int, days: int): def get_heatmap_value(user_id: int, days: int):
# Berechnet das Datum, ab dem die Habits gezählt werden sollen
date = (datetime.now() - timedelta(days=days)).date() date = (datetime.now() - timedelta(days=days)).date()
print(date) print(date)
query = f"SELECT id FROM habits WHERE (SELECT id FROM habit_lists WHERE (SELECT list_id FROM habit_users WHERE user_id = {user_id}) = id) = list_id;"
query2 = (f"SELECT habits.id FROM habits, habit_trackings WHERE (SELECT id FROM habit_lists WHERE (SELECT list_id FROM habit_users WHERE user_id = {user_id}) = id) = list_id " # Uses JOINs to get all Habits
f"AND habits.created_at LIKE '{date}%' AND habit_trackings.habit_id = habits.id;") query = (f"SELECT habits.id FROM habits "
print(query2) f"JOIN habit_lists ON habits.list_id = habit_lists.id "
f"JOIN habit_users ON habit_lists.id = habit_users.list_id "
f"WHERE habit_users.user_id = {user_id};")
# Uses JOINs to get all checked Habits on a specific date
query2 = (f"SELECT habits.id FROM habits "
f"JOIN habit_lists ON habits.list_id = habit_lists.id "
f"JOIN habit_users ON habit_lists.id = habit_users.list_id "
f"JOIN habit_trackings ON habits.id = habit_trackings.habit_id "
f"WHERE habit_users.user_id = {user_id} AND DATE(habit_trackings.created_at) = '{date}';")
conn = con3() conn = con3()
cursor = conn.cursor() cursor = conn.cursor()
# Execute the queries
cursor.execute(query) cursor.execute(query)
all_habits = cursor.fetchall() all_habits = cursor.fetchall()
cursor.execute(query2) cursor.execute(query2)
checked_habits = cursor.fetchall() checked_habits = cursor.fetchall()
# Close the database connection
count = len(all_habits) count = len(all_habits)
print(count) print(count)
count2 = len(checked_habits) count2 = len(checked_habits)
print(count2) print(count2)
# Close the database connection
conn.close() conn.close()
return int(count2 / count * 100)
# Calculate the percentage of checked Habits
if count > 0:
return int(count2 / count * 100)
else:
return 0
def get_next_slot(list_id: int): def get_next_slot(list_id: int):
@ -219,17 +241,22 @@ def delete_habitTrackings(id: int):
def create_habitList(user_id: int, name: str, description: str): def create_habitList(user_id: int, name: str, description: str):
now = datetime.now().isoformat() now = datetime.now().isoformat()
query = ( query = (
f"INSERT INTO habit_lists (user_id, name, description, created_at, updated_at) VALUES ('{user_id}', '{name}', '{description}', '{now}');") f"INSERT INTO habit_lists (name, description, created_at, updated_at) VALUES ('{name}', '{description}', '{now}', '{now}');")
conn = con3() conn = con3()
cursor = conn.cursor() cursor = conn.cursor()
cursor.execute(query) cursor.execute(query)
query1 = f"INSERT INTO habit_users (user_id, list_id, created_at, updated_at) VALUES ('{user_id}', '{cursor.lastrowid}', '{now}', '{now}');"
cursor.execute(query1)
conn.commit() conn.commit()
conn.close() conn.close()
return cursor.lastrowid return cursor.lastrowid
def get_habitList(id: int): def get_habitList(id: int):
query = f"SELECT * FROM habit_list WHERE id = {id};" query = f"SELECT * FROM habit_lists WHERE id = {id};"
conn = con3() conn = con3()
cursor = conn.cursor() cursor = conn.cursor()
cursor.execute(query) cursor.execute(query)
@ -239,7 +266,7 @@ def get_habitList(id: int):
def get_habitLists(user_id: int): def get_habitLists(user_id: int):
query = f"SELECT * FROM habit_list WHERE user_id = {user_id};" query = f"SELECT habit_lists.* FROM habit_lists JOIN habit_users ON habit_lists.id = habit_users.list_id WHERE habit_users.user_id = {user_id};"
conn = con3() conn = con3()
cursor = conn.cursor() cursor = conn.cursor()
cursor.execute(query) cursor.execute(query)
@ -250,7 +277,7 @@ def get_habitLists(user_id: int):
def update_habitList(id: int, name: str, description: str): def update_habitList(id: int, name: str, description: str):
now = datetime.now().isoformat() now = datetime.now().isoformat()
query = f"UPDATE habit_list SET name = {name}, description = {description}, updated_at = '{now}' WHERE id = {id};" query = f"UPDATE habit_lists SET name = {name}, description = {description}, updated_at = '{now}' WHERE id = {id};"
conn = con3() conn = con3()
cursor = conn.cursor() cursor = conn.cursor()
cursor.execute(query) cursor.execute(query)
@ -260,7 +287,7 @@ def update_habitList(id: int, name: str, description: str):
def delete_habitList(id: int): def delete_habitList(id: int):
query = f"DELETE FROM habit_list WHERE id = {id};" query = f"DELETE FROM habit_lists WHERE id = {id};"
conn = con3() conn = con3()
cursor = conn.cursor() cursor = conn.cursor()
cursor.execute(query) cursor.execute(query)

View File

@ -1,9 +0,0 @@
CREATE TABLE IF NOT EXISTS habits
(
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
note TEXT NULL,
times INTEGER NOT NULL,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);

View File

@ -1 +0,0 @@
DROP TABLE habits;

View File

@ -1,12 +0,0 @@
CREATE TABLE IF NOT EXISTS habits
(
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER,
name TEXT NOT NULL,
note TEXT,
times INTEGER NOT NULL,
unit INTEGER,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id)
);

View File

@ -1 +0,0 @@
DROP TABLE habits;

View File

@ -1,13 +0,0 @@
CREATE TABLE IF NOT EXISTS habits
(
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
name TEXT NOT NULL,
note TEXT,
times INTEGER NOT NULL,
unit INTEGER,
list_index INTEGER NOT NULL,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id)
);

View File

@ -1 +0,0 @@
DROP TABLE habits;

View File

@ -1,2 +0,0 @@
INSERT INTO users (name, email, password, created_at, updated_at)
VALUES ('Nikolaus MikeyMouse', 'Nordpol@icloud.com', 'a36c101570cc4410993de5385ad7034adb2dae6a05139ac7672577803084634d', '23:00', '23:00');

View File

@ -1,2 +0,0 @@
INSERT INTO habits (user_id, name, note, times, unit, slot, created_at, updated_at)
VALUES ('1', 'Sport', '10x Liegestutze', '1', '1', '1', '23:00', '23:00');

View File

@ -1,2 +0,0 @@
INSERT INTO habits (user_id, name, note, times, unit, slot, created_at, updated_at)
VALUES ('1', 'Sport', '10x Klimmzuge', '1', '1', '3', '23:00', '23:00');

View File

@ -1,2 +0,0 @@
INSERT INTO habits (user_id, name, note, times, unit, slot, created_at, updated_at)
VALUES ('1', 'Essen', '1x Gemüse', '1', '2', '2', '23:00', '23:00');

View File

@ -1,2 +0,0 @@
INSERT INTO habits (user_id, name, note, times, unit, slot, created_at, updated_at)
VALUES ('2', 'Sport', '10x Liegestutze', '1', '1', '2', '23:00', '23:00');

View File

@ -9,7 +9,6 @@ from models.Habit import Habit
@dataclass @dataclass
class HabitList: class HabitList:
id: int id: int
user_id: int
name: str name: str
description: str description: str
created_at: date created_at: date
@ -18,12 +17,12 @@ class HabitList:
@staticmethod @staticmethod
def create(user_id: int, name: str, description: str): def create(user_id: int, name: str, description: str):
id = create_habitList(user_id, name, description) id = create_habitList(user_id, name, description)
return HabitList(id, user_id, name, description, datetime.now(), datetime.now()) return HabitList(id, name, description, datetime.now(), datetime.now())
@staticmethod @staticmethod
def get(id: int): def get(id: int):
habitList = get_habitList(id) habitList = get_habitList(id)
return HabitList(habitList[0], habitList[1], habitList[2], habitList[3], datetime.strptime(habitList[4], "%Y-%m-%dT%H:%M:%S.%f"), datetime.strptime(habitList[5], "%Y-%m-%dT%H:%M:%S.%f")) if habitList else None return HabitList(habitList[0], habitList[1], habitList[2], datetime.strptime(habitList[3], "%Y-%m-%dT%H:%M:%S.%f"), datetime.strptime(habitList[4], "%Y-%m-%dT%H:%M:%S.%f")) if habitList else None
def delete(self): def delete(self):
delete_habitTrackings(self.id) delete_habitTrackings(self.id)

View File

@ -47,7 +47,7 @@ class User(UserMixin):
raw_habitLists = get_habitLists(self.id) raw_habitLists = get_habitLists(self.id)
habitLists = [] habitLists = []
for habitList in raw_habitLists: for habitList in raw_habitLists:
habitList = HabitList(habitList[0], habitList[1], habitList[2], habitList[3], datetime.strptime(habitList[4], "%Y-%m-%dT%H:%M:%S.%f"), datetime.strptime(habitList[5], "%Y-%m-%dT%H:%M:%S.%f")) habitList = HabitList(habitList[0], habitList[1], habitList[2], datetime.strptime(habitList[3], "%Y-%m-%dT%H:%M:%S.%f"), datetime.strptime(habitList[4], "%Y-%m-%dT%H:%M:%S.%f"))
habitLists.append(habitList) habitLists.append(habitList)
return habitLists return habitLists

25
templates/habit-list.html Normal file
View File

@ -0,0 +1,25 @@
{% extends 'layouts/main.html' %}
{% block content %}
<h1 class="mt-5">Habitliste erstellen📋</h1>
<form action="/habit-list" method="POST">
<div class="mb-3">
<label for="name" class="form-label">Name der Liste</label>
<input type="text" class="form-control {% if errors.get('name') %} is-invalid {% endif %}" id="name" name="name" value="{{name}}">
<div class="invalid-feedback">
{{ errors.get('name', '') }}
</div>
</div>
<div class="mb-3">
<label for="description" class="form-label">Beschreibung</label>
<input type="text" class="form-control {% if errors.get('description') %} is-invalid {% endif %}" id="description" name="description" value="{{description}}">
<div class="invalid-feedback">
{{ errors.get('description', '') }}
</div>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
{% endblock %}

View File

@ -54,6 +54,28 @@
</div> </div>
</div> </div>
<input type="hidden" name="list_query" id="list_query" class="{% if errors.get('list_query') %} is-invalid {% endif %}">
<div class="invalid-feedback">
{{ errors.get('list_query', '') }}
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Extracting the list-query from the URL
var listQuery = new URLSearchParams(window.location.search).get('list');
if ("{{ list_id }}" != "") {
listQuery = "{{ list_id }}";
// Add the list_id to the URL
var url = new URL(window.location.href);
url.searchParams.set('list', listQuery);
// window.history.pushState({}, '', url);
}
// Setting the list-query as the value of the hidden input field
document.getElementById('list_query').value = listQuery;
});
</script>
<button type="submit" class="btn btn-primary">Submit</button> <button type="submit" class="btn btn-primary">Submit</button>
</form> </form>

View File

@ -1,252 +1,269 @@
{% extends 'layouts/main.html' %} {% extends 'layouts/main.html' %}
{% block content %} {% block content %}
<h1>{{ title }}</h1> <h1>{{ title }}</h1>
<h3>{{ utc_dt }}</h3> <h3>{{ utc_dt }}</h3>
<style> <style>
#heatmap { #heatmap {
display: grid; display: grid;
grid-template-columns: repeat(7, 0fr); /* 7 Tage in einer Woche */ grid-template-columns: repeat(7, 0fr); /* 7 Tage in einer Woche */
gap: 5px; gap: 5px;
}
.day {
width: 50px;
height: 50px;
border: 1px solid #ccc;
display: flex;
align-items: center;
justify-content: center;
}
</style>
<div class="row">
<div class="col-md-5 col-12">
<div id="heatmap"></div>
</div>
<script>
// Funktion zur Rückgabe des Montagsdatums
function getMonday(date) {
const day = date.getDay();
const diff = date.getDate() - day + (day === 0 ? -6 : 1); // Anpassung für Sonntag
return new Date(date.setDate(diff));
} }
// Simulierte Aktivitätsdaten (ersetze dies durch deine echten Daten) .day {
const activityData = [5, 3, 10, 5, 24, 2, 10, 47, 32, 45, 9, 5, 11, 39, 24, 2, 10, 47, 32, 45]; width: 50px;
height: 50px;
border: 1px solid #ccc;
display: flex;
align-items: center;
justify-content: center;
}
</style>
// Funktion zum Erstellen der Heatmap <div class="row">
function createHeatmap(data) {
const heatmapContainer = document.getElementById('heatmap');
// Aktuelles Datum des Montags <div class="col-md-5 col-12">
const days = ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So'] <div id="heatmap"></div>
</div>
for (let i = 0; i < 7; i++) { <script>
const dayElement = document.createElement('div'); // Funktion zur Rückgabe des Montagsdatums
dayElement.classList.add('day'); function getMonday(date) {
dayElement.textContent = days[i]; const day = date.getDay();
heatmapContainer.appendChild(dayElement); const diff = date.getDate() - day + (day === 0 ? -6 : 1); // Anpassung für Sonntag
// currentDate.setDate(currentDate.getDate() + 1); return new Date(date.setDate(diff));
} }
// Aktuelles Datum des Montags in der neuen linken Spalte // Simulierte Aktivitätsdaten (ersetze dies durch deine echten Daten)
for (let i = 0; i < 7; i++) { const activityData = [5, 3, 10, 5, 24, 2, 10, 47, 32, 45, 9, 5, 11, 39, 24, 2, 10, 47, 32, 45];
for (let j = 0; j < 7; j++) {
// console.log(i * 7 + j, data[i * 7 + j], Math.max(...data));
const opacity = data[i * 7 + j] / Math.max(...data); // Berechne die Opazität basierend auf Aktivitätsanzahl
if (data[i * 7 + j]) { // Funktion zum Erstellen der Heatmap
const dayElement = document.createElement('div'); function createHeatmap(data) {
dayElement.classList.add('day'); const heatmapContainer = document.getElementById('heatmap');
dayElement.style.backgroundColor = `rgba(0, 255, 0, ${opacity})`;
heatmapContainer.appendChild(dayElement); // Aktuelles Datum des Montags
} else { const days = ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So']
const dayElement = document.createElement('div');
// dayElement.classList.add('day'); for (let i = 0; i < 7; i++) {
// dayElement.style.backgroundColor = `rgba(0, 255, 0, ${opacity})`; const dayElement = document.createElement('div');
heatmapContainer.appendChild(dayElement); dayElement.classList.add('day');
dayElement.textContent = days[i];
heatmapContainer.appendChild(dayElement);
// currentDate.setDate(currentDate.getDate() + 1);
}
// Aktuelles Datum des Montags in der neuen linken Spalte
for (let i = 0; i < 7; i++) {
for (let j = 0; j < 7; j++) {
// console.log(i * 7 + j, data[i * 7 + j], Math.max(...data));
const opacity = data[i * 7 + j] / Math.max(...data); // Berechne die Opazität basierend auf Aktivitätsanzahl
if (data[i * 7 + j]) {
const dayElement = document.createElement('div');
dayElement.classList.add('day');
dayElement.style.backgroundColor = `rgba(0, 255, 0, ${opacity})`;
heatmapContainer.appendChild(dayElement);
} else {
const dayElement = document.createElement('div');
// dayElement.classList.add('day');
// dayElement.style.backgroundColor = `rgba(0, 255, 0, ${opacity})`;
heatmapContainer.appendChild(dayElement);
}
} }
} }
} }
}
// Erstelle die Heatmap mit den simulierten Daten // Erstelle die Heatmap mit den simulierten Daten
createHeatmap(activityData); createHeatmap(activityData);
</script> </script>
<div class="col-md-7 col-12"> <div class="col-md-7 col-12">
<div class="row mb-3">
<h2 class="col-9">Gewohnheiten</h2>
<a class="col-3 btn btn-primary" role="button" href="/habit-list">Neue Liste erstellen</a>
</div>
<div class="row mb-3"> {% for habit_list in habit_lists %}
<h2 class="col-9">Gewohnheiten</h2>
<a class="col-3 btn btn-primary" role="button" href="/habit">Gewohnheit erstellen</a>
</div>
<ul class="task-list row"> <div class="row mb-3">
{% for habit in habits %} <h2 class="col-9">{{ habit_list.name }}</h2>
<li class="row d-flex align-items-center mb-2" id="habit-{{habit.id}}"> <a class="col-3 btn btn-primary" role="button" href="/habit?list={{ habit_list.id }}">Gewohnheit erstellen</a>
<div class="col-auto drag-handle" style="cursor: grab;">
<i class="bi bi-grip-vertical"></i>
</div>
<div class="col-auto">
<input {% if habit.checked %} checked {% endif %} type="checkbox" class="task-checkbox" id="{{habit.id}}" onclick="sendPostRequest('{{habit.id}}')">
</div> </div>
<div class="col" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis"> <ul class="task-list row">
{{ habit.name }} {% for habit in habit_list.get_habits() %}
</div> <li class="row d-flex align-items-center mb-2" id="habit-{{ habit.id }}">
<div class="col-auto drag-handle" style="cursor: grab;">
<i class="bi bi-grip-vertical"></i>
</div>
<div class="col-auto">
<input {% if habit.checked %} checked {% endif %} type="checkbox" class="task-checkbox"
id="{{ habit.id }}"
onclick="sendPostRequest('{{ habit.id }}')">
</div>
<div class="col-6" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis"> <div class="col" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis">
{{ habit.note }} {{ habit.name }}
</div> </div>
<div class="col-2" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis"> <div class="col-6" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis">
{% if habit %} {{ habit.note }}
5 🔥 </div>
{% endif %}
</div> <div class="col-2" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis">
{% if habit %}
5 🔥
{% endif %}
<button type="button" class="btn btn-xs btn-danger rounded-circle" data-bs-toggle="modal" data-bs-target="#exampleModal" style="width: 40px; height: 40px" onclick="setSelectedHabitId({{habit.id}})"> </div>
<i class="bi bi-trash3"></i>
</button> <button type="button" class="btn btn-xs btn-danger rounded-circle" data-bs-toggle="modal"
<div class="col-12"> data-bs-target="#exampleModal" style="width: 40px; height: 40px"
<div class="progress" style="height: 2px; width: 90%"> onclick="setSelectedHabitId({{ habit.id }})">
<div class="progress-bar" id="progress-bar-{{habit.id}}" role="progressbar" style="width: {{ habit.percentage }}%; background-color: {% if habit.percentage >= 100 %} green {% else %} primary {% endif %}" aria-valuenow="{{ habit.percentage }}" aria-valuemin="0" aria-valuemax="100"></div> <i class="bi bi-trash3"></i>
</div> </button>
</div> <div class="col-12">
</li> <div class="progress" style="height: 2px; width: 90%">
<div class="progress-bar" id="progress-bar-{{ habit.id }}" role="progressbar"
style="width: {{ habit.percentage }}%; background-color: {% if habit.percentage >= 100 %} green {% else %} primary {% endif %}"
aria-valuenow="{{ habit.percentage }}" aria-valuemin="0"
aria-valuemax="100"></div>
</div>
</div>
</li>
{% endfor %}
</ul>
{% endfor %} {% endfor %}
</ul> </div>
</div>
<script> <script>
var selectedHabitId = null; var selectedHabitId = null;
function setSelectedHabitId(habitId) { function setSelectedHabitId(habitId) {
selectedHabitId = habitId; selectedHabitId = habitId;
} }
</script> </script>
<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true"> <div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<h1 class="modal-title fs-5" id="exampleModalLabel">Bestätige</h1> <h1 class="modal-title fs-5" id="exampleModalLabel">Bestätige</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
Möchtest du dieses Habit wirklich löschen? Möchtest du dieses Habit wirklich löschen?
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary btn-danger" data-bs-dismiss="modal" onclick="deleteHabit(selectedHabitId)">Löschen</button> <button type="button" class="btn btn-primary btn-danger" data-bs-dismiss="modal"
onclick="deleteHabit(selectedHabitId)">Löschen
</button>
</div>
</div> </div>
</div> </div>
</div> </div>
</div>
<script> <script>
function checkCompletionAndAnimate(habitId, percentage) { function checkCompletionAndAnimate(habitId, percentage) {
var progressBar = document.getElementById("progress-bar-" + habitId);
var habitBlock = document.getElementById("habit-" + habitId);
if (percentage == 100) {
progressBar.style.backgroundColor = "green";
habitBlock.classList.add("animate-bounce");
setTimeout(function () {
habitBlock.classList.remove("animate-bounce");
}, 2000);
} else {
progressBar.style.backgroundColor = "";
habitBlock.classList.remove("animate-bounce");
}
}
function sendPostRequest(checkboxId) {
// Get the checkbox element using the provided ID
var checkbox = document.getElementById(checkboxId);
// console.log(checkbox);
// Get the habit id from the checkbox id attribute
var habitId = checkboxId;
// Make a POST request to /check with the habit id
axios.post('/check', { habitId: habitId }, {
headers: {
'Content-Type': 'application/json'
}
}).then(function (response) {
// Handle the success response if needed
console.log(response.data);
// Set the percentage of the habit. percentage received as integer
var percentage = response.data.percentage;
var progressBar = document.getElementById("progress-bar-" + habitId); var progressBar = document.getElementById("progress-bar-" + habitId);
progressBar.style.width = percentage + "%"; var habitBlock = document.getElementById("habit-" + habitId);
checkCompletionAndAnimate(habitId, percentage);
}).catch(function (error) {
// Handle the error if needed
console.error('Error:', error);
});
}
function deleteHabit(habitId) { if (percentage == 100) {
// Make a POST request to /delete with the habit id progressBar.style.backgroundColor = "green";
habitBlock.classList.add("animate-bounce");
axios.post('/delete', { habitId: habitId }, { setTimeout(function () {
headers: { habitBlock.classList.remove("animate-bounce");
'Content-Type': 'application/json' }, 2000);
} else {
progressBar.style.backgroundColor = "";
habitBlock.classList.remove("animate-bounce");
} }
}).then(function (response) { }
// Handle the success response if needed
console.log(response.data);
// Remove the habit from the DOM function sendPostRequest(checkboxId) {
var habitElement = document.getElementById("habit-" + habitId); // Get the checkbox element using the provided ID
habitElement.remove(); var checkbox = document.getElementById(checkboxId);
}).catch(function (error) { // console.log(checkbox);
// Handle the error if needed
console.error('Error:', error);
});
}
</script>
</div>
<script> // Get the habit id from the checkbox id attribute
document.addEventListener('DOMContentLoaded', (event) => { var habitId = checkboxId;
var el = document.querySelector('.task-list');
Sortable.create(el, {
handle: '.drag-handle',
animation: 150,
onEnd: function(evt) {
console.log(evt.oldIndex, evt.newIndex);
var habitId = el.children[evt.newIndex].id.split('-')[1]; // Make a POST request to /check with the habit id
var oldIndex = evt.oldIndex; axios.post('/check', {habitId: habitId}, {
var newIndex = evt.newIndex;
axios.post('/reorder', { habitId: habitId, oldIndex: oldIndex, newIndex: newIndex }, {
headers: { headers: {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
} }
}).then(function (response) { }).then(function (response) {
// Handle the success response if needed // Handle the success response if needed
console.log(response.data); console.log(response.data);
// Set the percentage of the habit. percentage received as integer
var percentage = response.data.percentage;
var progressBar = document.getElementById("progress-bar-" + habitId);
progressBar.style.width = percentage + "%";
checkCompletionAndAnimate(habitId, percentage);
}).catch(function (error) { }).catch(function (error) {
// Handle the error if needed // Handle the error if needed
console.error('Error:', error); console.error('Error:', error);
}); });
} }
function deleteHabit(habitId) {
// Make a POST request to /delete with the habit id
axios.post('/delete', {habitId: habitId}, {
headers: {
'Content-Type': 'application/json'
}
}).then(function (response) {
// Handle the success response if needed
console.log(response.data);
// Remove the habit from the DOM
var habitElement = document.getElementById("habit-" + habitId);
habitElement.remove();
}).catch(function (error) {
// Handle the error if needed
console.error('Error:', error);
});
}
</script>
</div>
<script>
document.addEventListener('DOMContentLoaded', (event) => {
var el = document.querySelector('.task-list');
Sortable.create(el, {
handle: '.drag-handle',
animation: 150,
onEnd: function (evt) {
console.log(evt.oldIndex, evt.newIndex);
var habitId = el.children[evt.newIndex].id.split('-')[1];
var oldIndex = evt.oldIndex;
var newIndex = evt.newIndex;
axios.post('/reorder', {habitId: habitId, oldIndex: oldIndex, newIndex: newIndex}, {
headers: {
'Content-Type': 'application/json'
}
}).then(function (response) {
// Handle the success response if needed
console.log(response.data);
}).catch(function (error) {
// Handle the error if needed
console.error('Error:', error);
});
}
});
}); });
}); </script>
</script>
{% endblock %} {% endblock %}

View File

@ -1,167 +0,0 @@
{% extends 'layouts/main.html' %}
{% block content %}
<h1>{{ title }}</h1>
<h3>{{ utc_dt }}</h3>
<style>
table {
border-collapse: collapse;
width: 100%;
}
th, td {
border: 1px solid #dddddd;
text-align: center;
padding: 8px;
}
th {
background-color: #f2f2f2;
}
.current-week {
/* Change the color for the current week */
background-color: rgba(255, 204, 0, 1); /* Full opacity */
}
.past-week {
/* Change the color for past weeks */
background-color: rgba(224, 224, 224, 1); /* Full opacity */
}
.future-week {
/* Change the color for future weeks */
background-color: rgba(192, 224, 192, 1); /* Full opacity */
}
.current-day {
/* Highlight the current day */
border: 2px solid #ff0000;
border-radius: 5px;
}
</style>
<table id="heatmap">
<thead>
<tr>
<th></th> <!-- Empty cell for spacing -->
<th class="past-week">-2</th>
<th class="past-week">-1</th>
<th class="current-week">0</th>
<th class="future-week">+1</th>
<th class="future-week">+2</th>
</tr>
</thead>
<tbody>
<tr>
<td >Montag</td>
<td class="past-week" data-tasks="5">15</td>
<td class="past-week" data-tasks="8">20</td>
<td class="current-week" data-tasks="12">25</td>
<td class="future-week" data-tasks="7">30</td>
<td class="future-week" data-tasks="10">35</td>
</tr>
<tr>
<td class="current-day">Dienstag</td>
<td class="past-week" data-tasks="5">15</td>
<td class="past-week" data-tasks="8">20</td>
<td class="current-week" data-tasks="12">25</td>
<td class="future-week" data-tasks="7">30</td>
<td class="future-week" data-tasks="10">35</td>
</tr>
<tr>
<td >Mittwoch</td>
<td class="past-week" data-tasks="5">15</td>
<td class="past-week" data-tasks="8">20</td>
<td class="current-week" data-tasks="12">25</td>
<td class="future-week" data-tasks="7">30</td>
<td class="future-week" data-tasks="10">35</td>
</tr>
<tr>
<td >Donnerstag</td>
<td class="past-week" data-tasks="5">15</td>
<td class="past-week" data-tasks="8">20</td>
<td class="current-week" data-tasks="12">25</td>
<td class="future-week" data-tasks="7">30</td>
<td class="future-week" data-tasks="10">35</td>
</tr>
<tr>
<td >Freitag</td>
<td class="past-week" data-tasks="5">15</td>
<td class="past-week" data-tasks="8">20</td>
<td class="current-week" data-tasks="12">25</td>
<td class="future-week" data-tasks="7">30</td>
<td class="future-week" data-tasks="10">35</td>
</tr>
<tr>
<td >Samstag</td>
<td class="past-week" data-tasks="5">15</td>
<td class="past-week" data-tasks="8">20</td>
<td class="current-week" data-tasks="12">25</td>
<td class="future-week" data-tasks="7">30</td>
<td class="future-week" data-tasks="10">35</td>
</tr> <tr>
<td >Sonntag</td>
<td class="past-week" data-tasks="5">15</td>
<td class="past-week" data-tasks="8">20</td>
<td class="current-week" data-tasks="12">25</td>
<td class="future-week" data-tasks="7">30</td>
<td class="future-week" data-tasks="10">35</td>
</tr>
</tbody>
</table>
<script>
// Adjust background color based on the number of tasks
document.addEventListener('DOMContentLoaded', function () {
var cells = document.querySelectorAll('#heatmap tbody td');
cells.forEach(function (cell) {
var tasks = parseInt(cell.getAttribute('data-tasks')) || 0;
var opacity = tasks / 20; // Adjust the denominator based on your preference
// Get the RGB values from the background color
var rgb = cell.style.backgroundColor.match(/\d+/g);
// Calculate the green value based on the number of tasks
var greenValue = Math.round(opacity * 255);
// Set the new background color with adjusted green value
cell.style.backgroundColor = 'rgba(0,' + greenValue + ',0,' + opacity + ')';
});
});
</script>
<div class="row">
<h2 class="col-10">Task List</h2>
<a class="col-2 btn btn-primary" role="button" href="/habit">
Task erstellen
</a>
</div>
<ul class="task-list row">
{% for habit in habits %}
<li class="row col-md-4">
<div class="col-auto">
<input type="checkbox" class="task-checkbox">
</div>
<div class="col" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis">
{{ habit.name }} hhhbhghbhjndjksbeujsdkfheuwaihgkjfgfjnsidkgjnkdghujds
</div>
</li>
<div class="col-md-8" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis">
{{ habit.note }}
</div>
{% endfor %}
</ul>
{% endblock %}

View File

@ -1,65 +0,0 @@
{% extends 'layouts/main.html' %}
{% block content %}
<h1>{{ title }}</h1>
<h3>{{ utc_dt }}</h3>
<div class="heatmap" id="heatmap"></div>
<script>
// Simulierte Aktivitätsdaten (ersetze dies durch deine echten Daten)
const activityData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 5, 4, 3, 2, 1, 9, 5, 36, 75, 8, 9, 1, 0, 23, 0, 0, 0, 64, 0, 0, 64, 0, 0, 19, 84];
// Funktion zum Erstellen der Heatmap
function createHeatmap(data) {
const heatmapContainer = document.getElementById('heatmap');
for (let i = 0; i < data.length; i++) {
const opacity = data[i] / Math.max(...data); // Berechne die Opazität basierend auf Aktivitätsanzahl
const dayElement = document.createElement('div');
dayElement.classList.add('day');
dayElement.style.backgroundColor = `rgba(0, 255, 0, ${opacity})`;
heatmapContainer.appendChild(dayElement);
}
}
// Erstelle die Heatmap mit den simulierten Daten
createHeatmap(activityData);
</script>
<div class="row">
<h2 class="col-10">Task List</h2>
<a class="col-2 btn btn-primary" role="button" href="/habit">
Task erstellen
</a>
</div>
<ul class="task-list row">
{% for habit in habits %}
<li class="row col-md-4">
<div class="col-auto">
<input type="checkbox" class="task-checkbox">
</div>
<div class="col" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis">
{{ habit.name }} hhhbhghbhjndjksbeujsdkfheuwaihgkjfgfjnsidkgjnkdghujds
</div>
</li>
<div class="col-md-8" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis">
{{ habit.note }}
</div>
{% endfor %}
</ul>
{% endblock %}