Merge remote-tracking branch 'origin/master'

# Conflicts:
#	templates/index.html
This commit is contained in:
nikolaswollenberg 2024-02-14 10:59:24 +01:00
commit 6143f44442
3 changed files with 198 additions and 195 deletions

View File

@ -80,6 +80,9 @@ class Habit:
count = 0 count = 0
self.checked = False self.checked = False
for tracking in self.get_habitTrackings(): for tracking in self.get_habitTrackings():
if tracking.created_at.date() == datetime.today().date():
self.checked = True
# day # day
if self.unit == 0: if self.unit == 0:
if tracking.created_at.date() == datetime.today().date(): if tracking.created_at.date() == datetime.today().date():

View File

@ -1,8 +1,8 @@
from datetime import datetime 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, delete_user, update_user, \
get_habitLists get_habitLists, get_heatmap_value
class User(UserMixin): class User(UserMixin):
@ -43,3 +43,10 @@ class User(UserMixin):
habitLists.append(habitList) habitLists.append(habitList)
return habitLists return habitLists
def get_heatmap(self):
heatmap = []
for day in range (0, 27):
value = get_heatmap_value(self.id, day)
heatmap.append(value)
return heatmap

View File

@ -1,187 +1,180 @@
{% 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-4 col-12 card bg-light mb-6">
<div class="card-body">
<h5 class="card-title">Heatmap</h5>
<div id="heatmap"></div>
</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>
<div class="col-md-7 col-12 card gap-3 bg-light p-6 offset-md-1 mb-6"> </script>
<div class="row mb-3 ">
<h2 class="col-9">Gewohnheiten</h2>
<a class="col-3 btn btn-primary p" role="button" href="/habit-list">Neue Liste erstellen</a>
</div>
{% for habit_list in habit_lists %} <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">{{ habit_list.name }}</h2>
<a class="col-3 btn btn-primary" role="button" href="/habit?list={{ habit_list.id }}">Gewohnheit
erstellen</a>
</div>
<ul class="task-list row"> <div class="row mb-3">
{% for habit in habit_list.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.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-5 text-black text-opacity-50" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis"> <div class="col" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis">
{{ habit.name }}
</div>
{{ habit.note }} <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 %}
<div class="col-2" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis"> </div>
{% if habit %}
{% else %} <button type="button" class="btn btn-xs btn-danger rounded-circle" data-bs-toggle="modal"
5 🔥 data-bs-target="#exampleModal" style="width: 40px; height: 40px"
{% endif %} 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> {% endfor %}
</ul>
<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 %} {% endfor %}
</ul> </div>
{% endfor %} <script>
</div> var selectedHabitId = null;
<script> function setSelectedHabitId(habitId) {
var selectedHabitId = null; selectedHabitId = habitId;
}
</script>
function setSelectedHabitId(habitId) { <div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
selectedHabitId = habitId; <div class="modal-dialog">
} <div class="modal-content">
</script> <div class="modal-header">
<h1 class="modal-title fs-5" id="exampleModalLabel">Bestätige</h1>
<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true"> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<div class="modal-dialog"> </div>
<div class="modal-content"> <div class="modal-body">
<div class="modal-header"> Möchtest du dieses Habit wirklich löschen?
<h1 class="modal-title fs-5" id="exampleModalLabel">Bestätige</h1> </div>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> <div class="modal-footer">
</div> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<div class="modal-body"> <button type="button" class="btn btn-primary btn-danger" data-bs-dismiss="modal"
Möchtest du dieses Habit wirklich löschen? onclick="deleteHabit(selectedHabitId)">Löschen
</div> </button>
<div class="modal-footer"> </div>
<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> </div>
</div>
<script> <script>
function checkCompletionAndAnimate(habitId, percentage) { function checkCompletionAndAnimate(habitId, percentage) {
var progressBar = document.getElementById("progress-bar-" + habitId); var progressBar = document.getElementById("progress-bar-" + habitId);
var habitBlock = document.getElementById("habit-" + habitId); var habitBlock = document.getElementById("habit-" + habitId);
if (percentage == 100) { if (percentage == 100) {
progressBar.style.backgroundColor = "green"; progressBar.style.backgroundColor = "green";
@ -195,22 +188,22 @@
} }
} }
function sendPostRequest(checkboxId) { function sendPostRequest(checkboxId) {
// Get the checkbox element using the provided ID // Get the checkbox element using the provided ID
var checkbox = document.getElementById(checkboxId); var checkbox = document.getElementById(checkboxId);
// console.log(checkbox); // console.log(checkbox);
// Get the habit id from the checkbox id attribute // Get the habit id from the checkbox id attribute
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'
} }
}).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 // Set the percentage of the habit. percentage received as integer
var percentage = response.data.percentage; var percentage = response.data.percentage;
@ -223,51 +216,51 @@
}); });
} }
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: {
'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) {
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: { 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);
// Remove the habit from the DOM
var habitElement = document.getElementById("habit-" + habitId);
habitElement.remove();
}).catch(function (error) { }).catch(function (error) {
// Handle the error if needed // Handle the error if needed
console.error('Error:', error); 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) {
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
}).catch(function (error) {
// Handle the error if needed
console.error('Error:', error);
});
}
});
}); });
}); </script>
</script>
{% endblock %} {% endblock %}