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 models.Habit import Habit
from models.HabitList import HabitList
from models.HabitTrackings import HabitTrackings
from models.User import User
from utils import anonymous_required
@ -120,20 +121,20 @@ def logout():
@app.route('/')
def index():
if current_user.is_authenticated:
habits = current_user.get_habits()
habit_lists = current_user.get_habitLists()
name = "Hallo " + current_user.name
else:
habits = []
habit_lists = []
name = "Bitte melde dich an."
# 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(
'index.html',
title=name,
utc_dt=datetime.datetime.now().strftime("%d.%m.%Y %H:%M %A"),
habits=habits,
habit_lists=habit_lists,
errors={},
)
@ -156,6 +157,7 @@ def habit_create():
note = request.form.get('note')
times = request.form.get('times')
unit = request.form.get('unit')
list_id = request.form.get('list_query')
# Check for errors
errors = {}
@ -167,6 +169,8 @@ def habit_create():
note = ''
if not unit:
errors['unit'] = 'Die Einheit ist erforderlich.'
if not list_id:
errors['list_query'] = 'Die Habitliste ist erforderlich.'
# Check if times is an integer
try:
@ -190,7 +194,8 @@ def habit_create():
note=note,
times=times,
unit=unit,
errors=errors
errors=errors,
list_id=list_id
)
# Map unit to integer
@ -212,6 +217,45 @@ def habit_create():
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')
@login_required
def profile():

View File

@ -102,24 +102,46 @@ def get_habits(list_id: 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()
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 "
f"AND habits.created_at LIKE '{date}%' AND habit_trackings.habit_id = habits.id;")
print(query2)
# Uses JOINs to get all Habits
query = (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"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()
cursor = conn.cursor()
# Execute the queries
cursor.execute(query)
all_habits = cursor.fetchall()
cursor.execute(query2)
checked_habits = cursor.fetchall()
# Close the database connection
count = len(all_habits)
print(count)
count2 = len(checked_habits)
print(count2)
# Close the database connection
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):
@ -219,17 +241,22 @@ def delete_habitTrackings(id: int):
def create_habitList(user_id: int, name: str, description: str):
now = datetime.now().isoformat()
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()
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_list WHERE id = {id};"
query = f"SELECT * FROM habit_lists WHERE id = {id};"
conn = con3()
cursor = conn.cursor()
cursor.execute(query)
@ -239,7 +266,7 @@ def get_habitList(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()
cursor = conn.cursor()
cursor.execute(query)
@ -250,7 +277,7 @@ def get_habitLists(user_id: int):
def update_habitList(id: int, name: str, description: str):
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()
cursor = conn.cursor()
cursor.execute(query)
@ -260,7 +287,7 @@ def update_habitList(id: int, name: str, description: str):
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()
cursor = conn.cursor()
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
class HabitList:
id: int
user_id: int
name: str
description: str
created_at: date
@ -18,12 +17,12 @@ class HabitList:
@staticmethod
def create(user_id: int, name: str, description: str):
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
def get(id: int):
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):
delete_habitTrackings(self.id)

View File

@ -47,7 +47,7 @@ class User(UserMixin):
raw_habitLists = get_habitLists(self.id)
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)
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>
<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>
</form>

View File

@ -1,252 +1,269 @@
{% extends 'layouts/main.html' %}
{% block content %}
<h1>{{ title }}</h1>
<h3>{{ utc_dt }}</h3>
<h1>{{ title }}</h1>
<h3>{{ utc_dt }}</h3>
<style>
#heatmap {
display: grid;
grid-template-columns: repeat(7, 0fr); /* 7 Tage in einer Woche */
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));
<style>
#heatmap {
display: grid;
grid-template-columns: repeat(7, 0fr); /* 7 Tage in einer Woche */
gap: 5px;
}
// Simulierte Aktivitätsdaten (ersetze dies durch deine echten Daten)
const activityData = [5, 3, 10, 5, 24, 2, 10, 47, 32, 45, 9, 5, 11, 39, 24, 2, 10, 47, 32, 45];
.day {
width: 50px;
height: 50px;
border: 1px solid #ccc;
display: flex;
align-items: center;
justify-content: center;
}
</style>
// Funktion zum Erstellen der Heatmap
function createHeatmap(data) {
const heatmapContainer = document.getElementById('heatmap');
<div class="row">
// Aktuelles Datum des Montags
const days = ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So']
<div class="col-md-5 col-12">
<div id="heatmap"></div>
</div>
for (let i = 0; i < 7; i++) {
const dayElement = document.createElement('div');
dayElement.classList.add('day');
dayElement.textContent = days[i];
heatmapContainer.appendChild(dayElement);
// currentDate.setDate(currentDate.getDate() + 1);
<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));
}
// 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
// Simulierte Aktivitätsdaten (ersetze dies durch deine echten Daten)
const activityData = [5, 3, 10, 5, 24, 2, 10, 47, 32, 45, 9, 5, 11, 39, 24, 2, 10, 47, 32, 45];
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);
// Funktion zum Erstellen der Heatmap
function createHeatmap(data) {
const heatmapContainer = document.getElementById('heatmap');
// Aktuelles Datum des Montags
const days = ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So']
for (let i = 0; i < 7; i++) {
const dayElement = document.createElement('div');
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
createHeatmap(activityData);
// Erstelle die Heatmap mit den simulierten Daten
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">
<h2 class="col-9">Gewohnheiten</h2>
<a class="col-3 btn btn-primary" role="button" href="/habit">Gewohnheit erstellen</a>
</div>
{% for habit_list in habit_lists %}
<ul class="task-list row">
{% for habit in habits %}
<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 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 class="col" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis">
{{ habit.name }}
</div>
<ul class="task-list row">
{% for habit in habit_list.get_habits() %}
<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">
{{ habit.note }}
</div>
<div class="col" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis">
{{ habit.name }}
</div>
<div class="col-2" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis">
{% if habit %}
5 🔥
{% endif %}
<div class="col-6" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis">
{{ habit.note }}
</div>
</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}})">
<i class="bi bi-trash3"></i>
</button>
<div class="col-12">
<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>
</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 }})">
<i class="bi bi-trash3"></i>
</button>
<div class="col-12">
<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 %}
</ul>
</div>
</div>
<script>
var selectedHabitId = null;
<script>
var selectedHabitId = null;
function setSelectedHabitId(habitId) {
selectedHabitId = habitId;
}
</script>
function setSelectedHabitId(habitId) {
selectedHabitId = habitId;
}
</script>
<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<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>
</div>
<div class="modal-body">
Möchtest du dieses Habit wirklich löschen?
</div>
<div class="modal-footer">
<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>
<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<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>
</div>
<div class="modal-body">
Möchtest du dieses Habit wirklich löschen?
</div>
<div class="modal-footer">
<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>
</div>
</div>
</div>
</div>
</div>
<script>
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;
<script>
function checkCompletionAndAnimate(habitId, percentage) {
var progressBar = document.getElementById("progress-bar-" + habitId);
progressBar.style.width = percentage + "%";
checkCompletionAndAnimate(habitId, percentage);
}).catch(function (error) {
// Handle the error if needed
console.error('Error:', error);
});
}
var habitBlock = document.getElementById("habit-" + habitId);
function deleteHabit(habitId) {
// Make a POST request to /delete with the habit id
axios.post('/delete', { habitId: habitId }, {
headers: {
'Content-Type': 'application/json'
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");
}
}).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>
function sendPostRequest(checkboxId) {
// Get the checkbox element using the provided ID
var checkbox = document.getElementById(checkboxId);
// console.log(checkbox);
<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);
// Get the habit id from the checkbox id attribute
var habitId = checkboxId;
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 }, {
// 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);
progressBar.style.width = percentage + "%";
checkCompletionAndAnimate(habitId, percentage);
}).catch(function (error) {
// Handle the error if needed
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 %}

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 %}