Merge remote-tracking branch 'origin/master'

This commit is contained in:
Yapollon 2024-03-06 11:05:16 +01:00
commit 776eaec21b
10 changed files with 327 additions and 33 deletions

126
app.py
View File

@ -207,6 +207,10 @@ def habit_create():
except ValueError: except ValueError:
errors['list_query'] = 'Die Anzahl muss eine Zahl sein.' errors['list_query'] = 'Die Anzahl muss eine Zahl sein.'
# Check if unit is day and times is one
if unit == 'Tag' and times != 1:
errors['times'] = 'Die Anzahl muss 1 sein, wenn das Habit täglich ist.'
if errors: if errors:
return render_template( return render_template(
'habit.html', 'habit.html',
@ -312,26 +316,107 @@ def profile_change():
@app.route('/edit-habit') @app.route('/edit-habit')
@login_required @login_required
def edit_habit(): def edit_habit():
habit_id = request.args.get("habit") habit_id = int(request.args.get("habit"))
#habit_id = request.get_json()["editHabitId"]
habit = Habit.get(habit_id) habit = Habit.get(habit_id)
units = ["Tag", "Woche", "Monat", "Jahr"]
return render_template( return render_template(
"edit-habit.html", "edit-habit.html",
title=habit.name title=habit.name,
habit=habit.id,
name=habit.name,
note=habit.note,
times=habit.times,
unit=units[habit.unit],
errors={}
) )
'''
@app.route('/edit-habit', methods=['POST']) @app.route('/edit-habit', methods=['POST'])
@login_required @login_required
def edit_habit_change(): def edit_habit_change():
#habit_id = request.get_json()["habitId"]
#habit = Habit.get(habit_id)
units = ["Tag", "Woche", "Monat", "Jahr"]
name = request.form.get('name')
note = request.form.get('note')
times = request.form.get('times')
unit = request.form.get('unit')
list_id = request.form.get('habit')
habit = Habit.get(list_id)
# Check for errors
errors = {}
if not name:
errors['name'] = 'Der Name ist erforderlich.'
if not times:
errors['times'] = 'Die Anzahl ist erforderlich.'
if not note:
note = ''
if not unit:
errors['unit'] = 'Die Einheit ist erforderlich.'
if not list_id:
errors['habit'] = 'Das Habit ist erforderlich.'
# Check if times is an integer
try:
print(times)
times = int(times)
# Check that times is greater than 0
if times <= 0:
errors['times'] = 'Die Anzahl muss größer als 0 sein.'
except ValueError:
errors['times'] = 'Die Anzahl muss eine Zahl sein.'
# Check that unit is valid
if unit not in ['Tag', 'Woche', 'Monat', 'Jahr']:
errors['unit'] = 'Die Einheit ist ungültig.'
# check if list_id is an int
try:
list_id = int(list_id)
except ValueError:
errors['list_query'] = 'Die Anzahl muss eine Zahl sein.'
if unit == 'Tag' and times != 1:
errors['times'] = 'Die Anzahl muss 1 sein, wenn das Habit täglich ist.'
if errors:
return render_template( return render_template(
"edit-habit.html" "edit-habit.html",
title=habit.name,
habit=habit.id,
name=habit.name,
note=habit.note,
times=habit.times,
unit=units[habit.unit],
errors={}
) )
'''
# Map unit to integer
if unit == 'Tag':
unit = 0
elif unit == 'Woche':
unit = 1
elif unit == 'Monat':
unit = 2
elif unit == 'Jahr':
unit = 3
else:
unit = 1
# Save habit to database
print(name, note, times, unit)
habit.name, habit.note, habit.times, habit.unit = name, note, times, unit
habit.update()
# Back to index
return redirect(url_for('index'))
@app.route('/check_password', methods=['POST']) @app.route('/check_password', methods=['POST'])
@login_required @login_required
def check_password(): def check_password():
@ -483,6 +568,24 @@ def delete_habit():
return {} return {}
@app.route('/delete-list', methods=['POST'])
@login_required
def delete_list():
list_id = request.get_json()["listId"]
habit_list = HabitList.get(list_id)
if habit_list is None:
return {"error": "List not found"}
# Check if habit belongs to user
if current_user not in habit_list.get_users():
return {"error": "List does not belong to user"}
habit_list.delete(current_user.id)
return {}
@app.route('/reorder', methods=['POST']) @app.route('/reorder', methods=['POST'])
@login_required @login_required
def reorder_habits(): def reorder_habits():
@ -549,11 +652,12 @@ def add_user():
if not user: if not user:
errors['email'] = 'E-Mail Adresse nicht gefunden.' errors['email'] = 'E-Mail Adresse nicht gefunden.'
if user.id == current_user.id: if user and user.id == current_user.id:
errors['email'] = 'Du kannst dich nicht selbst hinzufügen.' errors['email'] = 'Du kannst dich nicht selbst hinzufügen.'
# Check if user is already in the habit list # Check if user is already in the habit list
already = False already = False
if user:
for u in habit_list.get_users(): for u in habit_list.get_users():
if u.id == user.id: if u.id == user.id:
already = True already = True
@ -581,4 +685,4 @@ def add_user():
# Run the application # Run the application
if __name__ == '__main__': if __name__ == '__main__':
app.run(port=5000, debug=True) app.run(host="0.0.0.0", port=5000, debug=True)

View File

@ -190,7 +190,7 @@ def update_slot(id: int, slot: int):
def update_habit(id: int, name: str, note: str, times: int, unit: int): def update_habit(id: int, name: str, note: str, times: int, unit: int):
now = datetime.now().isoformat() now = datetime.now().isoformat()
query = (f"UPDATE habits SET name = {name}, note = {note}, times = {times}, unit = {unit}, updated_at = '{now}' " query = (f"UPDATE habits SET name = '{name}', note = '{note}', times = {times}, unit = {unit}, updated_at = '{now}' "
f"WHERE id = {id};") f"WHERE id = {id};")
conn = con3() conn = con3()
cursor = conn.cursor() cursor = conn.cursor()

3
requirements.txt Normal file
View File

@ -0,0 +1,3 @@
pillow~=10.2.0
flask~=3.0.0
flask-login~=0.6.3

View File

@ -0,0 +1,20 @@
<div class="modal fade" id="listenModal" tabindex="-1" aria-labelledby="listenModal" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="listenModalLabel">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 diese Liste wirklich löschen?
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">abbrechen</button>
<button type="button" class="btn btn-primary btn-danger" data-bs-dismiss="modal"
onclick="deleteList(localStorage.getItem('selectedListId'));">Löschen
</button>
</div>
</div>
</div>
</div>

View File

@ -1,4 +1,4 @@
<div class="flex-fill col-md-8 col-12 card bg-light p-6 mb-6"> <div class="flex-fill col-md-7 col-lg-8 col-12 card bg-light p-6 mb-6">
<!-- Listen erstellen --> <!-- Listen erstellen -->
<div class="row mb-3"> <div class="row mb-3">
@ -15,7 +15,7 @@
<ul class="nav nav-tabs card-header-tabs" role="tablist"> <ul class="nav nav-tabs card-header-tabs" role="tablist">
{% for habit_list in habit_lists %} {% for habit_list in habit_lists %}
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation" id="tab-{{ habit_list.id }}">
<a class="nav-link {% if habit_list == habit_lists[0] %} active {% endif %}" <a class="nav-link {% if habit_list == habit_lists[0] %} active {% endif %}"
id="simple-tab-{{habit_list.id}}" id="simple-tab-{{habit_list.id}}"
data-bs-toggle="tab" href="#simple-tabpanel-{{habit_list.id}}" role="tab" data-bs-toggle="tab" href="#simple-tabpanel-{{habit_list.id}}" role="tab"
@ -63,6 +63,25 @@
{% for habit_list in habit_lists %} {% for habit_list in habit_lists %}
<div class="tab-pane {% if habit_list == habit_lists[0] %} active {% endif %}" <div class="tab-pane {% if habit_list == habit_lists[0] %} active {% endif %}"
id="simple-tabpanel-{{habit_list.id}}" role="tabpanel" aria-labelledby="simple-tab-{{habit_list.id}}"> id="simple-tabpanel-{{habit_list.id}}" role="tabpanel" aria-labelledby="simple-tab-{{habit_list.id}}">
<!-- Beschreibung und Löschen von der Liste -->
<div class="row mb-3">
<div class="col">
{{ habit_list.description }}
</div>
<div class="col-2">
<button type="button" class="btn btn-xs me-3" data-bs-toggle="modal"
data-bs-target="#listenModal" style="width: 40px; height: 40px"
onclick="{
localStorage.setItem('selectedListId', {{ habit_list.id }});
}">
<!---onclick="setSelectedListId({{ habit_list.id }})"-->
<i class="bi bi-trash3"></i>
</button>
</div>
</div>
<div class="row mb-3 align-items-center"> <div class="row mb-3 align-items-center">
<!-- Personen die zur Liste gehören --> <!-- Personen die zur Liste gehören -->
@ -103,7 +122,7 @@
{% for habit in habit_list.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 }}">
<!-- Handle zum verschieben --> <!-- Handle zum Verschieben -->
<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>
@ -172,5 +191,9 @@
selectedHabitId = habitId; selectedHabitId = habitId;
} }
var selectedListId = null;
function setSelectedListId(listId) {
selectedlistId = listId;
}
</script> </script>

View File

@ -1,5 +1,5 @@
<div class="flex-fill col-md-4 col-12 card bg-light mb-6"> <div class="flex-fill col-md-5 col-lg-4 col-12 card bg-light mb-6">
<div class="card-body"> <div class="card-body">
<h5 class="card-title">📅 Heatmap</h5> <h5 class="card-title">📅 Heatmap</h5>
<div id="heatmap"></div> <div id="heatmap"></div>

View File

@ -48,14 +48,6 @@
}); });
} }
function sendHabitId(Id) {
var habitId = document.getElementById(Id);
// Make a POST request to /check with the habit id
// axios.post('/edit-habit', {editHabitId: habitId})
}
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
@ -76,6 +68,28 @@
}); });
} }
function deleteList(listId) {
// Make a POST request to /delete with the habit id
axios.post('/delete-list', {listId: listId}, {
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("simple-tabpanel-" + listId);
habitElement.remove();
var habitElement = document.getElementById("tab-" + listId);
habitElement.remove();
}).catch(function (error) {
// Handle the error if needed
console.error('Error:', error);
});
}
document.addEventListener('DOMContentLoaded', (event) => { document.addEventListener('DOMContentLoaded', (event) => {
var elements = document.querySelectorAll('.task-list').values() var elements = document.querySelectorAll('.task-list').values()

View File

@ -2,6 +2,81 @@
{% block content %} {% block content %}
test <h1 class="mt-5">Habit Bearbeiten📋</h1>
{{ title }}
<form action="/edit-habit" method="POST">
<div class="mb-3">
<label for="name" class="form-label">Name der Gewohnheit</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="note" class="form-label">Beschreibung</label>
<input type="text" class="form-control {% if errors.get('note') %} is-invalid {% endif %}" id="note" name="note" value="{{note}}">
<div class="invalid-feedback">
{{ errors.get('note', '') }}
</div>
</div>
<div class="row">
<div class="mb-3 col-2">
<label for="times" class="form-label">Häufigkeit</label>
<input type="number" min="1" class="form-control {% if errors.get('times') %} is-invalid {% endif %}" id="times" name="times" value="{{times}}">
<div class="invalid-feedback">
{{ errors.get('times', '') }}
</div>
</div>
<div class="mb-3 col-10">
<label for="unit" class="form-label">Im Zeitraum</label>
<select class="form-select {% if errors.get('unit') %} is-invalid {% endif %}" id="unit" name="unit">
<option value="Tag">Tag</option>
<option value="Woche">Woche</option>
<option value="Monat">Monat</option>
<option value="Jahr">Jahr</option>
</select>
<script>
document.addEventListener('DOMContentLoaded', (event) => {
let selectedElement = document.getElementById('unit');
for (let option of selectedElement.options) {
if (option.value == '{{ unit }}') {
option.selected = true;
break;
}
}
});
</script>
<div class="invalid-feedback">
{{ errors.get('unit', '') }}
</div>
</div>
</div>
<input type="hidden" name="habit" id="habit" class="{% if errors.get('habit') %} 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('habit');
if ("{{ habit }}" != "") {
listQuery = "{{ habit }}";
// Add the list_id to the URL
var url = new URL(window.location.href);
url.searchParams.set('habit', listQuery);
// window.history.pushState({}, '', url);
}
// Setting the list-query as the value of the hidden input field
document.getElementById('habit').value = listQuery;
});
</script>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
{% endblock %} {% endblock %}

View File

@ -27,8 +27,54 @@
table-layout: fixed; table-layout: fixed;
} }
@media (max-width: 1400px) {
.day {
width: 40px;
height: 40px;
}
}
@media (max-width: 1200px) {
.day {
width: 35px;
height: 35px;
}
}
@media (max-width: 992px) {
.day {
width: 30px;
height: 30px;
}
}
@media (max-width: 770px) {
.day {
width: 50px;
height: 50px;
}
}
@media (max-width: 450px) {
.day {
width: 40px;
height: 40px;
}
}
@media (max-width: 400px) {
.day {
width: 35px;
height: 35px;
}
}
@media (max-width: 350px) {
.day {
width: 30px;
height: 30px;
}
}
</style> </style>
@ -47,6 +93,15 @@
{% include 'components/delete_button.html' %} {% include 'components/delete_button.html' %}
{% endif %} {% endif %}
{% if current_user.is_authenticated %}
{% include 'components/delete_list.html' %}
{% endif %}
{% if not current_user.is_authenticated %}
<script type="module" src="https://unpkg.com/@splinetool/viewer@1.0.55/build/spline-viewer.js"></script>
<spline-viewer loading-anim-type="spinner-small-dark" url="https://prod.spline.design/4mCpd7DzpXgN2X9q/scene.splinecode"></spline-viewer>
{% endif %}
</div> </div>
{% include 'components/scripts.html' %} {% include 'components/scripts.html' %}

View File

@ -44,7 +44,7 @@
<a class="btn btn-outline-secondary" aria-current="page" href="{{ url_for('signup') }}">Signup</a> <a class="btn btn-outline-secondary" aria-current="page" href="{{ url_for('signup') }}">Signup</a>
</li> </li>
{% else %} {% else %}
<li class="nav-item me-2"> <li class="nav-item me-2 mb-2 mb-lg-0">
<a class="btn text-white btn-primary" aria-current="page" href="{{ url_for('profile') }}">Profil</a> <a class="btn text-white btn-primary" aria-current="page" href="{{ url_for('profile') }}">Profil</a>
</li> </li>
<li class="nav-item me-2"> <li class="nav-item me-2">