Compare commits
3 Commits
6464c0538e
...
05b5869be7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
05b5869be7 | ||
|
|
4764112296 | ||
|
|
4dd997ce13 |
79
app.py
79
app.py
@ -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,21 @@ 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))
|
for habit_list in habit_lists:
|
||||||
|
habit_list.habits = sorted(habit_list.get_habits(), key=lambda habit: (not 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 +158,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 +170,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 +195,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 +218,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():
|
||||||
@ -280,7 +325,8 @@ def check_habit():
|
|||||||
return {"error": "Habit not found"}
|
return {"error": "Habit not found"}
|
||||||
|
|
||||||
# Check if habit belongs to user
|
# Check if habit belongs to user
|
||||||
if habit.user_id != current_user.id:
|
users = habit.habit_list().get_users()
|
||||||
|
if current_user not in users:
|
||||||
return {"error": "Habit does not belong to user"}
|
return {"error": "Habit does not belong to user"}
|
||||||
|
|
||||||
trackings = habit.get_habitTrackings()
|
trackings = habit.get_habitTrackings()
|
||||||
@ -316,13 +362,32 @@ def delete_habit():
|
|||||||
return {"error": "Habit not found"}
|
return {"error": "Habit not found"}
|
||||||
|
|
||||||
# Check if habit belongs to user
|
# Check if habit belongs to user
|
||||||
if habit.user_id != current_user.id:
|
if current_user not in habit.habit_list().get_users():
|
||||||
return {"error": "Habit does not belong to user"}
|
return {"error": "Habit does not belong to user"}
|
||||||
|
|
||||||
habit.delete()
|
habit.delete()
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/reorder', methods=['POST'])
|
||||||
|
@login_required
|
||||||
|
def reorder_habits():
|
||||||
|
new_index = request.get_json()["newIndex"]
|
||||||
|
habit = Habit.get(request.get_json()["habitId"])
|
||||||
|
|
||||||
|
if habit is None:
|
||||||
|
return {"error": "Habit not found"}
|
||||||
|
|
||||||
|
# Check if habit belongs to user
|
||||||
|
users = habit.habit_list().get_users()
|
||||||
|
if current_user not in users:
|
||||||
|
return {"error": "Habit does not belong to user"}
|
||||||
|
|
||||||
|
habit.update_slot(new_index)
|
||||||
|
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
# Run the application
|
# Run the application
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
app.run(port=5000, debug=True)
|
app.run(port=5000, debug=True)
|
||||||
|
|||||||
@ -57,7 +57,7 @@ def update_user(id: int, name: str, email: str, password: str = None):
|
|||||||
|
|
||||||
|
|
||||||
def delete_user(id: int):
|
def delete_user(id: int):
|
||||||
query = f"DELETE FROM habits WHERE user_id = {id};"
|
query = f"DELETE FROM habit_lists WHERE (SELECT list_id FROM habit_users WHERE user_id = {id}) = id;"
|
||||||
query2 = f"DELETE FROM users WHERE id = {id};"
|
query2 = f"DELETE FROM users WHERE id = {id};"
|
||||||
conn = con3()
|
conn = con3()
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
@ -69,9 +69,9 @@ def delete_user(id: int):
|
|||||||
|
|
||||||
|
|
||||||
### Habit.py ###
|
### Habit.py ###
|
||||||
def create_habit(user_id: int, name: str, times: int, unit: int, slot: int, note: str | None=None):
|
def create_habit(list_id: int, name: str, times: int, unit: int, slot: int, note: str | None=None):
|
||||||
now = datetime.now().isoformat()
|
now = datetime.now().isoformat()
|
||||||
query = (f"INSERT INTO habits (user_id, name, note, times, unit, slot, created_at, updated_at) VALUES ('{user_id}', "
|
query = (f"INSERT INTO habits (list_id, name, note, times, unit, slot, created_at, updated_at) VALUES ('{list_id}', "
|
||||||
f"'{name}', '{note}', '{times}', '{unit}', '{slot}', '{now}', '{now}');")
|
f"'{name}', '{note}', '{times}', '{unit}', '{slot}', '{now}', '{now}');")
|
||||||
conn = con3()
|
conn = con3()
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
@ -91,8 +91,8 @@ def get_habit(id: int):
|
|||||||
return habit
|
return habit
|
||||||
|
|
||||||
|
|
||||||
def get_habits(user_id: int):
|
def get_habits(list_id: int):
|
||||||
query = f"SELECT * FROM habits WHERE user_id = {user_id};"
|
query = f"SELECT * FROM habits WHERE list_id = {list_id};"
|
||||||
conn = con3()
|
conn = con3()
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute(query)
|
cursor.execute(query)
|
||||||
@ -102,28 +102,50 @@ def get_habits(user_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 user_id = {user_id};"
|
|
||||||
query2 = (f"SELECT habits.id FROM habits, habit_trackings WHERE habits.user_id = {user_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()
|
||||||
|
|
||||||
|
# Calculate the percentage of checked Habits
|
||||||
|
if count > 0:
|
||||||
return int(count2 / count * 100)
|
return int(count2 / count * 100)
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
def get_next_slot(user_id: int):
|
def get_next_slot(list_id: int):
|
||||||
query = f"SELECT slot FROM habits WHERE user_id = {user_id} ORDER BY slot DESC LIMIT 1;"
|
query = f"SELECT slot FROM habits WHERE list_id = {list_id} ORDER BY slot DESC LIMIT 1;"
|
||||||
conn = con3()
|
conn = con3()
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute(query)
|
cursor.execute(query)
|
||||||
@ -132,8 +154,8 @@ def get_next_slot(user_id: int):
|
|||||||
return slot[0] + 1 if slot else 0
|
return slot[0] + 1 if slot else 0
|
||||||
|
|
||||||
|
|
||||||
def get_slots(user_id: int):
|
def get_slots(list_id: int):
|
||||||
query = f"SELECT id, slot FROM habits WHERE user_id = {user_id} ORDER BY slot;"
|
query = f"SELECT id, slot FROM habits WHERE list_id = {list_id} ORDER BY slot;"
|
||||||
conn = con3()
|
conn = con3()
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute(query)
|
cursor.execute(query)
|
||||||
@ -174,10 +196,10 @@ def delete_habit(id: int):
|
|||||||
|
|
||||||
|
|
||||||
### HabitTrackings.py ###
|
### HabitTrackings.py ###
|
||||||
def create_habitTrackings(habit_id: int, times: int):
|
def create_habitTrackings(habit_id: int):
|
||||||
now = datetime.now().isoformat()
|
now = datetime.now().isoformat()
|
||||||
query = (
|
query = (
|
||||||
f"INSERT INTO habit_trackings (habit_id, times, created_at) VALUES ('{habit_id}', '{times}','{now}');")
|
f"INSERT INTO habit_trackings (habit_id, created_at) VALUES ('{habit_id}','{now}');")
|
||||||
conn = con3()
|
conn = con3()
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute(query)
|
cursor.execute(query)
|
||||||
@ -215,6 +237,74 @@ def delete_habitTrackings(id: int):
|
|||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
### HabitList.py ###
|
||||||
|
def create_habitList(user_id: int, name: str, description: str):
|
||||||
|
now = datetime.now().isoformat()
|
||||||
|
query = (
|
||||||
|
f"INSERT INTO habit_lists (name, description, created_at, updated_at) VALUES ('{name}', '{description}', '{now}', '{now}');")
|
||||||
|
|
||||||
|
conn = con3()
|
||||||
|
cursor = conn.cursor()
|
||||||
|
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.close()
|
||||||
|
return cursor.lastrowid
|
||||||
|
|
||||||
|
|
||||||
|
def get_habitList(id: int):
|
||||||
|
query = f"SELECT * FROM habit_lists WHERE id = {id};"
|
||||||
|
conn = con3()
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute(query)
|
||||||
|
habit_list = cursor.fetchone()
|
||||||
|
conn.close()
|
||||||
|
return habit_list
|
||||||
|
|
||||||
|
|
||||||
|
def get_habitLists(user_id: int):
|
||||||
|
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()
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute(query)
|
||||||
|
habit_lists = cursor.fetchall()
|
||||||
|
conn.close()
|
||||||
|
return habit_lists
|
||||||
|
|
||||||
|
|
||||||
|
def update_habitList(id: int, name: str, description: str):
|
||||||
|
now = datetime.now().isoformat()
|
||||||
|
query = f"UPDATE habit_lists SET name = {name}, description = {description}, updated_at = '{now}' WHERE id = {id};"
|
||||||
|
conn = con3()
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute(query)
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
return cursor.lastrowid
|
||||||
|
|
||||||
|
|
||||||
|
def delete_habitList(id: int):
|
||||||
|
query = f"DELETE FROM habit_lists WHERE id = {id};"
|
||||||
|
conn = con3()
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute(query)
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
def get_users(list_id: int):
|
||||||
|
query = f"SELECT users.* FROM users JOIN habit_users ON users.id = habit_users.user_id WHERE habit_users.list_id = {list_id};"
|
||||||
|
conn = con3()
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute(query)
|
||||||
|
users = cursor.fetchall()
|
||||||
|
conn.close()
|
||||||
|
return users
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
habits = get_habits(1)
|
habits = get_habits(1)
|
||||||
for habit in habits:
|
for habit in habits:
|
||||||
|
|||||||
@ -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
|
|
||||||
);
|
|
||||||
@ -1 +0,0 @@
|
|||||||
DROP TABLE habits;
|
|
||||||
@ -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)
|
|
||||||
);
|
|
||||||
@ -1 +0,0 @@
|
|||||||
DROP TABLE habits;
|
|
||||||
@ -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)
|
|
||||||
);
|
|
||||||
@ -1 +0,0 @@
|
|||||||
DROP TABLE habits;
|
|
||||||
7
db/migrations/1705434250_create_habit_lists_table.sql
Normal file
7
db/migrations/1705434250_create_habit_lists_table.sql
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS habit_lists (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
description TEXT,
|
||||||
|
created_at TEXT NOT NULL,
|
||||||
|
updated_at TEXT NOT NULL
|
||||||
|
);
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS habit_users (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
user_id INTEGER,
|
||||||
|
list_id INTEGER,
|
||||||
|
created_at TEXT NOT NULL,
|
||||||
|
updated_at TEXT NOT NULL,
|
||||||
|
FOREIGN KEY (user_id) REFERENCES users(id),
|
||||||
|
FOREIGN KEY (list_id) REFERENCES habit_lists(id)
|
||||||
|
);
|
||||||
@ -1,7 +1,7 @@
|
|||||||
CREATE TABLE IF NOT EXISTS habits
|
CREATE TABLE IF NOT EXISTS habits
|
||||||
(
|
(
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
user_id INTEGER NOT NULL,
|
list_id INTEGER NOT NULL,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
note TEXT,
|
note TEXT,
|
||||||
times INTEGER NOT NULL,
|
times INTEGER NOT NULL,
|
||||||
@ -9,5 +9,5 @@ CREATE TABLE IF NOT EXISTS habits
|
|||||||
slot INTEGER NOT NULL,
|
slot INTEGER NOT NULL,
|
||||||
created_at TEXT NOT NULL,
|
created_at TEXT NOT NULL,
|
||||||
updated_at TEXT NOT NULL,
|
updated_at TEXT NOT NULL,
|
||||||
FOREIGN KEY (user_id) REFERENCES users(id)
|
FOREIGN KEY (list_id) REFERENCES habit_lists(id)
|
||||||
);
|
);
|
||||||
@ -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');
|
|
||||||
@ -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');
|
|
||||||
@ -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');
|
|
||||||
@ -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');
|
|
||||||
@ -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');
|
|
||||||
@ -2,7 +2,6 @@ CREATE TABLE IF NOT EXISTS habit_trackings
|
|||||||
(
|
(
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
habit_id INTEGER,
|
habit_id INTEGER,
|
||||||
times INTEGER NOT NULL,
|
|
||||||
created_at TEXT NOT NULL,
|
created_at TEXT NOT NULL,
|
||||||
FOREIGN KEY (habit_id) REFERENCES habits(id)
|
FOREIGN KEY (habit_id) REFERENCES habits(id)
|
||||||
);
|
);
|
||||||
@ -4,7 +4,7 @@ from datetime import datetime
|
|||||||
|
|
||||||
from models.HabitTrackings import HabitTrackings
|
from models.HabitTrackings import HabitTrackings
|
||||||
from db.SQLiteClient import update_slot, create_habit, get_habit, delete_habit, get_next_slot, \
|
from db.SQLiteClient import update_slot, create_habit, get_habit, delete_habit, get_next_slot, \
|
||||||
get_habitTrackings_by_habit_id, get_slots, update_habit
|
get_habitTrackings_by_habit_id, get_slots, update_habit, get_habitList, get_habitLists
|
||||||
|
|
||||||
|
|
||||||
# Unit wird als Integers wie folgt gemessen:
|
# Unit wird als Integers wie folgt gemessen:
|
||||||
@ -16,7 +16,7 @@ from db.SQLiteClient import update_slot, create_habit, get_habit, delete_habit,
|
|||||||
@dataclass
|
@dataclass
|
||||||
class Habit:
|
class Habit:
|
||||||
id: int
|
id: int
|
||||||
user_id: int
|
list_id: int
|
||||||
name: str
|
name: str
|
||||||
note: str
|
note: str
|
||||||
times: int
|
times: int
|
||||||
@ -28,10 +28,11 @@ class Habit:
|
|||||||
self.fill_statistics()
|
self.fill_statistics()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create(user_id: int, name: str, times: int, note: str | None = None, unit: int | None = 1):
|
def create(list_id: int, name: str, times: int, note: str | None = None, unit: int | None = 1):
|
||||||
slot = get_next_slot(user_id)
|
slot = get_next_slot(list_id)
|
||||||
id = create_habit(user_id, name, times, unit, slot, note)
|
print(slot)
|
||||||
return Habit(id, user_id, name, note, times, unit, slot)
|
id = create_habit(list_id, name, times, unit, slot, note)
|
||||||
|
return Habit(id, list_id, name, note, times, unit, slot)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get(id: int):
|
def get(id: int):
|
||||||
@ -54,7 +55,7 @@ class Habit:
|
|||||||
|
|
||||||
|
|
||||||
def update_slot(self, new_slot: int):
|
def update_slot(self, new_slot: int):
|
||||||
slots = get_slots(self.user_id)
|
slots = get_slots(self.list_id)
|
||||||
if new_slot > self.slot:
|
if new_slot > self.slot:
|
||||||
slots = slots[self.slot:new_slot]
|
slots = slots[self.slot:new_slot]
|
||||||
for slot in slots:
|
for slot in slots:
|
||||||
@ -67,7 +68,7 @@ class Habit:
|
|||||||
|
|
||||||
|
|
||||||
def delete(self):
|
def delete(self):
|
||||||
slots = get_slots(self.user_id)[self.slot+1:]
|
slots = get_slots(self.list_id)[self.slot+1:]
|
||||||
print(slots)
|
print(slots)
|
||||||
for slot in slots:
|
for slot in slots:
|
||||||
update_slot(slot[0], slot[1] - 1)
|
update_slot(slot[0], slot[1] - 1)
|
||||||
@ -77,7 +78,7 @@ class Habit:
|
|||||||
def get_habitTrackings(self) -> list[HabitTrackings]:
|
def get_habitTrackings(self) -> list[HabitTrackings]:
|
||||||
trackings = []
|
trackings = []
|
||||||
for rawTracking in get_habitTrackings_by_habit_id(self.id):
|
for rawTracking in get_habitTrackings_by_habit_id(self.id):
|
||||||
trackings.append(HabitTrackings(rawTracking[0], rawTracking[1], rawTracking[2], datetime.strptime(rawTracking[3], "%Y-%m-%dT%H:%M:%S.%f")))
|
trackings.append(HabitTrackings(rawTracking[0], rawTracking[1], datetime.strptime(rawTracking[2], "%Y-%m-%dT%H:%M:%S.%f")))
|
||||||
|
|
||||||
return trackings
|
return trackings
|
||||||
|
|
||||||
@ -115,3 +116,9 @@ class Habit:
|
|||||||
|
|
||||||
def to_json(self):
|
def to_json(self):
|
||||||
return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True, indent=4)
|
return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True, indent=4)
|
||||||
|
|
||||||
|
def habit_list(self):
|
||||||
|
from models.HabitList import HabitList
|
||||||
|
raw_habitLists = get_habitList(self.list_id)
|
||||||
|
|
||||||
|
return HabitList(raw_habitLists[0], raw_habitLists[1], raw_habitLists[2], datetime.strptime(raw_habitLists[3], "%Y-%m-%dT%H:%M:%S.%f"), datetime.strptime(raw_habitLists[4], "%Y-%m-%dT%H:%M:%S.%f")) if raw_habitLists else None
|
||||||
|
|||||||
48
models/HabitList.py
Normal file
48
models/HabitList.py
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
from dataclasses import dataclass
|
||||||
|
from datetime import date, datetime
|
||||||
|
|
||||||
|
from db.SQLiteClient import create_habitTrackings, get_habitTrackings, delete_habitTrackings, create_habitList, \
|
||||||
|
get_habitList, get_habits, get_users
|
||||||
|
from models.Habit import Habit
|
||||||
|
from models.User import User
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class HabitList:
|
||||||
|
id: int
|
||||||
|
name: str
|
||||||
|
description: str
|
||||||
|
created_at: date
|
||||||
|
updated_at: date
|
||||||
|
habits: list = None
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def create(user_id: int, name: str, description: str):
|
||||||
|
id = create_habitList(user_id, name, description)
|
||||||
|
return HabitList(id, name, description, datetime.now(), datetime.now())
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get(id: int):
|
||||||
|
habitList = get_habitList(id)
|
||||||
|
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):
|
||||||
|
delete_habitTrackings(self.id)
|
||||||
|
|
||||||
|
def get_habits(self):
|
||||||
|
raw_habits = get_habits(self.id)
|
||||||
|
habits = []
|
||||||
|
for habit in raw_habits:
|
||||||
|
habit = Habit(habit[0], habit[1], habit[2], habit[3], habit[4], habit[5], habit[6])
|
||||||
|
habits.append(habit)
|
||||||
|
|
||||||
|
return habits
|
||||||
|
|
||||||
|
def get_users(self):
|
||||||
|
raw_users = get_users(self.id)
|
||||||
|
users = []
|
||||||
|
for user in raw_users:
|
||||||
|
user = User(user[0], user[1], user[2], user[3])
|
||||||
|
users.append(user)
|
||||||
|
|
||||||
|
return users
|
||||||
@ -8,18 +8,17 @@ from db.SQLiteClient import create_habitTrackings, get_habitTrackings, delete_ha
|
|||||||
class HabitTrackings:
|
class HabitTrackings:
|
||||||
id: int
|
id: int
|
||||||
habit_id: int
|
habit_id: int
|
||||||
times: int
|
|
||||||
created_at: date
|
created_at: date
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create(habit_id: int, times: int):
|
def create(habit_id: int, times: int):
|
||||||
id = create_habitTrackings(habit_id, times)
|
id = create_habitTrackings(habit_id)
|
||||||
return HabitTrackings(id, habit_id, times, datetime.now())
|
return HabitTrackings(id, habit_id, datetime.now())
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get(id: int):
|
def get(id: int):
|
||||||
habitTrackings = get_habitTrackings(id)
|
habitTrackings = get_habitTrackings(id)
|
||||||
return HabitTrackings(habitTrackings[0], habitTrackings[1], habitTrackings[2], datetime.strptime(habitTrackings[3], "%Y-%m-%dT%H:%M:%S.%f")) if habitTrackings else None
|
return HabitTrackings(habitTrackings[0], habitTrackings[1], datetime.strptime(habitTrackings[2], "%Y-%m-%dT%H:%M:%S.%f")) if habitTrackings else None
|
||||||
|
|
||||||
def delete(self):
|
def delete(self):
|
||||||
delete_habitTrackings(self.id)
|
delete_habitTrackings(self.id)
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
|
||||||
from flask_login import UserMixin
|
from flask_login import UserMixin
|
||||||
from db.SQLiteClient import create_user, get_user, get_user_by_email, get_habits, delete_user, update_user
|
from db.SQLiteClient import create_user, get_user, get_user_by_email, get_habits, delete_user, update_user, \
|
||||||
from models.Habit import Habit
|
get_habitLists
|
||||||
|
|
||||||
|
|
||||||
class User(UserMixin):
|
class User(UserMixin):
|
||||||
@ -31,10 +33,21 @@ class User(UserMixin):
|
|||||||
def delete(self):
|
def delete(self):
|
||||||
delete_user(self.id)
|
delete_user(self.id)
|
||||||
|
|
||||||
def get_habits(self):
|
# def get_habits(self):
|
||||||
raw_habits = get_habits(self.id)
|
# raw_habits = get_habits(self.id)
|
||||||
habits = []
|
# habits = []
|
||||||
for habit in raw_habits:
|
# for habit in raw_habits:
|
||||||
habit = Habit(habit[0], habit[1], habit[2], habit[3], habit[4], habit[5], habit[6])
|
# habit = Habit(habit[0], habit[1], habit[2], habit[3], habit[4], habit[5], habit[6])
|
||||||
habits.append(habit)
|
# habits.append(habit)
|
||||||
return habits
|
# return habits
|
||||||
|
|
||||||
|
def get_habitLists(self):
|
||||||
|
from models.HabitList import HabitList
|
||||||
|
|
||||||
|
raw_habitLists = get_habitLists(self.id)
|
||||||
|
habitLists = []
|
||||||
|
for habitList in raw_habitLists:
|
||||||
|
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)
|
||||||
|
|
||||||
|
return habitLists
|
||||||
|
|||||||
25
templates/habit-list.html
Normal file
25
templates/habit-list.html
Normal 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 %}
|
||||||
@ -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>
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
{% 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 */
|
||||||
@ -20,9 +20,9 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
||||||
<div class="col-md-5 col-12">
|
<div class="col-md-5 col-12">
|
||||||
<div id="heatmap"></div>
|
<div id="heatmap"></div>
|
||||||
@ -82,20 +82,28 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="col-md-7 col-12">
|
<div class="col-md-7 col-12">
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<h2 class="col-9">Gewohnheiten</h2>
|
<h2 class="col-9">Gewohnheiten</h2>
|
||||||
<a class="col-3 btn btn-primary" role="button" href="/habit">Gewohnheit erstellen</a>
|
<a class="col-3 btn btn-primary" role="button" href="/habit-list">Neue Liste erstellen</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% for habit_list in habit_lists %}
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<h2 class="col-9">{{ habit_list.name }}</h2>
|
||||||
|
<a class="col-3 btn btn-primary" role="button" href="/habit?list={{ habit_list.id }}">Gewohnheit erstellen</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul class="task-list row">
|
<ul class="task-list row">
|
||||||
{% for habit in habits %}
|
{% for habit in habit_list.habits %}
|
||||||
<li class="row d-flex align-items-center mb-2" id="habit-{{habit.id}}">
|
<li class="row d-flex align-items-center mb-2" id="habit-{{ habit.id }}">
|
||||||
<div class="col-auto drag-handle" style="cursor: grab;">
|
<div class="col-auto drag-handle" style="cursor: grab;">
|
||||||
<i class="bi bi-grip-vertical"></i>
|
<i class="bi bi-grip-vertical"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
<input {% if habit.checked %} checked {% endif %} type="checkbox" class="task-checkbox" id="{{habit.id}}" onclick="sendPostRequest('{{habit.id}}')">
|
<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">
|
<div class="col" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis">
|
||||||
@ -113,18 +121,25 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<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}})">
|
<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 }})">
|
||||||
<i class="bi bi-trash3"></i>
|
<i class="bi bi-trash3"></i>
|
||||||
</button>
|
</button>
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="progress" style="height: 2px; width: 90%">
|
<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 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>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@ -147,7 +162,9 @@
|
|||||||
</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>
|
||||||
@ -180,7 +197,7 @@
|
|||||||
var habitId = checkboxId;
|
var habitId = checkboxId;
|
||||||
|
|
||||||
// Make a POST request to /check with the habit id
|
// Make a POST request to /check with the habit id
|
||||||
axios.post('/check', { habitId: habitId }, {
|
axios.post('/check', {habitId: habitId}, {
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
}
|
}
|
||||||
@ -202,7 +219,7 @@
|
|||||||
function deleteHabit(habitId) {
|
function deleteHabit(habitId) {
|
||||||
// Make a POST request to /delete with the habit id
|
// Make a POST request to /delete with the habit id
|
||||||
|
|
||||||
axios.post('/delete', { habitId: habitId }, {
|
axios.post('/delete', {habitId: habitId}, {
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
}
|
}
|
||||||
@ -219,28 +236,25 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener('DOMContentLoaded', (event) => {
|
document.addEventListener('DOMContentLoaded', (event) => {
|
||||||
var el = document.querySelector('.task-list');
|
var el = document.querySelector('.task-list');
|
||||||
Sortable.create(el, {
|
Sortable.create(el, {
|
||||||
handle: '.drag-handle',
|
handle: '.drag-handle',
|
||||||
animation: 150,
|
animation: 150,
|
||||||
onEnd: function(evt) {
|
onEnd: function (evt) {
|
||||||
console.log(evt.oldIndex, evt.newIndex);
|
|
||||||
|
|
||||||
var habitId = el.children[evt.newIndex].id.split('-')[1];
|
var habitId = el.children[evt.newIndex].id.split('-')[1];
|
||||||
var oldIndex = evt.oldIndex;
|
var oldIndex = evt.oldIndex;
|
||||||
var newIndex = evt.newIndex;
|
var newIndex = evt.newIndex;
|
||||||
|
|
||||||
axios.post('/reorder', { habitId: habitId, oldIndex: oldIndex, newIndex: 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);
|
|
||||||
}).catch(function (error) {
|
}).catch(function (error) {
|
||||||
// Handle the error if needed
|
// Handle the error if needed
|
||||||
console.error('Error:', error);
|
console.error('Error:', error);
|
||||||
@ -248,5 +262,5 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -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 %}
|
|
||||||
@ -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 %}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user