allow deleting accomplishment

Squashed commit of the following:

commit 846aa01f3bb2e88cc2141506dbad8fefce1cf75b
Author: Wojciech Kwolek <wojciech@kwolek.xyz>
Date:   Mon Aug 31 21:02:58 2020 +0200

    remove unimplemented edit link

commit d094e321c7e9d526646adad411d47fd03dc4d37b
Author: Wojciech Kwolek <wojciech@kwolek.xyz>
Date:   Mon Aug 31 20:59:53 2020 +0200

    implement deleting accomplishments

commit 5c33caba1baf0ad6a0c62cccba35209c7e28a71c
Author: Wojciech Kwolek <wojciech@kwolek.xyz>
Date:   Mon Aug 31 17:33:12 2020 +0200

    add edit buttons to the day view

commit 6cc826c5cbb0a0260f5745a8392c3bc92afb6c71
Author: Wojciech Kwolek <wojciech@kwolek.xyz>
Date:   Mon Aug 31 16:38:35 2020 +0200

    add __pycache__ to gitignore

commit 1593e4c6cfa1a45096421292152185579a449e53
Author: Wojciech Kwolek <wojciech@kwolek.xyz>
Date:   Mon Aug 31 16:35:40 2020 +0200

    extract a method for getting all day related data for a template
This commit is contained in:
Wojciech Kwolek 2020-08-31 21:03:31 +02:00
parent 845f5dbe65
commit d78e483ad2
7 changed files with 152 additions and 52 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
node_modules/
*.db
__pycache__

View File

@ -40,31 +40,35 @@ form input[type=password]:focus {
}
form input[type=submit] {
@apply w-full px-4 py-2 mt-2 font-bold rounded;
@apply px-4 py-2 mt-2 font-bold rounded;
}
form.auth-form input[type=submit] {
@apply text-white bg-blue-500;
@apply w-full text-white bg-blue-500;
}
.green-btn {
@apply text-white bg-green-500;
}
.accomplishment .text {
@apply flex-grow;
}
.accomplishment .difficulty {
@apply flex-shrink-0 pl-1 font-bold text-right;
min-width: 3em;
}
.accomplishment .difficulty-easy {
.difficulty-easy {
@apply text-green-700;
}
.accomplishment .difficulty-medium {
.difficulty-medium {
@apply text-orange-700;
}
.accomplishment .difficulty-hard {
.difficulty-hard {
@apply text-red-700;
}

View File

@ -1,6 +1,6 @@
from . import timeutils
from flask import Blueprint, render_template, redirect, url_for
from flask_login import current_user
from flask import Blueprint, render_template, redirect, url_for, abort
from flask_login import current_user, login_required
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired, Length
@ -35,22 +35,45 @@ def handle_accomplishment_submission(form):
return redirect(url_for('main.index'))
def get_day_template_data(day_string):
day_datetime = None
if day_string == "today":
day_datetime = timeutils.today()
else:
day_datetime = timeutils.from_str(day_string)
day_string_clean = timeutils.as_str(day_datetime)
accomplishments = list(reversed(
Accomplishment.get_day(current_user.id, day_datetime)))
total = sum(a.difficulty for a in accomplishments)
yesterday = timeutils.day_before(day_datetime)
tomorrow = timeutils.day_after(day_datetime)
if timeutils.is_future(tomorrow):
tomorrow = None
return {
"day": {
"datetime": day_datetime,
"string": day_string_clean,
"fancy": timeutils.as_fancy_str(day_datetime),
"is_today": timeutils.is_today(day_datetime)
},
"links": {
"yesterday": url_for('main.index', day=timeutils.as_str(yesterday)),
"tomorrow": url_for('main.index', day=timeutils.as_str(tomorrow)) if tomorrow is not None else None
},
"accomplishments": accomplishments,
"total_xp": sum(a.difficulty for a in accomplishments),
}
@main.route('/', defaults={'day': 'today'}, methods=['GET', 'POST'])
@main.route('/day/<day>')
def index(day):
day_datetime = None
day_string = None
is_today = False
if day == "today":
day_datetime = timeutils.today()
day_string = "Today"
is_today = True
else:
day_datetime = timeutils.from_str(day)
if timeutils.is_today(day_datetime):
return redirect('/')
day_string = timeutils.as_fancy_str(day_datetime)
if not current_user.is_authenticated:
return render_template('index.html')
@ -58,23 +81,50 @@ def index(day):
if form.validate_on_submit():
return handle_accomplishment_submission(form)
accomplishments = list(reversed(Accomplishment.get_day(
current_user.id, day_datetime)))
total = sum(a.difficulty for a in accomplishments)
return render_template(
'main/app.html',
form=form,
**get_day_template_data(day)
)
tomorrow = timeutils.day_after(day_datetime)
yesterday = timeutils.day_before(day_datetime)
if timeutils.is_future(tomorrow):
tomorrow = None
@main.route('/day/<day>/edit')
@login_required
def edit_day(day):
form = NewAccomplishementForm()
if form.validate_on_submit():
return handle_accomplishment_submission(form)
return render_template(
'main/app.html',
form=form,
day=day_string,
accomplishments=accomplishments,
total=total,
tomorrow=timeutils.as_str(tomorrow),
yesterday=timeutils.as_str(yesterday),
is_today=is_today,
edit=True,
**get_day_template_data(day)
)
class DeleteForm(FlaskForm):
submit = SubmitField('Delete')
@main.route('/accomplishment/<accomplishment_id>/delete', methods=['GET', 'POST'])
@login_required
def delete_accomplishment(accomplishment_id):
a = Accomplishment.query.get_or_404(accomplishment_id)
if a.user_id != current_user.id:
abort(403)
back_url = url_for(
'main.edit_day', day=timeutils.as_str(timeutils.day(a.time)))
form = DeleteForm()
if form.validate_on_submit():
db.session.delete(a)
db.session.commit()
return redirect(back_url)
return render_template(
'main/delete.html',
form=form,
accomplishment=a,
cancel=back_url)

View File

@ -22083,7 +22083,6 @@ form input[type=password]:focus {
}
form input[type=submit] {
width: 100%;
padding-left: 1rem;
padding-right: 1rem;
padding-top: 0.5rem;
@ -22094,6 +22093,7 @@ form input[type=submit] {
}
form.auth-form input[type=submit] {
width: 100%;
--text-opacity: 1;
color: #fff;
color: rgba(255, 255, 255, var(--text-opacity));
@ -22111,6 +22111,10 @@ form.auth-form input[type=submit] {
background-color: rgba(72, 187, 120, var(--bg-opacity));
}
.accomplishment .text {
flex-grow: 1;
}
.accomplishment .difficulty {
flex-shrink: 0;
padding-left: 0.25rem;
@ -22119,19 +22123,19 @@ form.auth-form input[type=submit] {
min-width: 3em;
}
.accomplishment .difficulty-easy {
.difficulty-easy {
--text-opacity: 1;
color: #2f855a;
color: rgba(47, 133, 90, var(--text-opacity));
}
.accomplishment .difficulty-medium {
.difficulty-medium {
--text-opacity: 1;
color: #c05621;
color: rgba(192, 86, 33, var(--text-opacity));
}
.accomplishment .difficulty-hard {
.difficulty-hard {
--text-opacity: 1;
color: #c53030;
color: rgba(197, 48, 48, var(--text-opacity));

View File

@ -1,7 +1,7 @@
{% extends "_skel.html" %}
{% block title %}{% if is_today %}Home{% else %}{{ day }}{% endif %}{% endblock %}
{% block title %}{{ day.fancy }}{% endblock %}
{% block content %}
<div class="max-w-lg mx-auto card">
<div class="max-w-xl mx-auto card">
<form method="POST" action="{{ url_for('main.index') }}">
{{ form.csrf_token }}
{{ form.text(placeholder="What did you accomplish today?", class_="placeholder-black", autofocus=True) }}
@ -13,19 +13,40 @@
</form>
</div>
<div class="max-w-lg mx-auto card">
<h3 class="mb-4 text-2xl">{{ day }}</h3>
{% for accomplishment in accomplishments %}
<div class="flex justify-between my-1 ml-2 accomplishment">
<div>{{ accomplishment.text }}</div>
<div class="difficulty-{{ accomplishment.difficulty_class }} difficulty">{{ accomplishment.difficulty }} XP
<div class="flex items-baseline justify-between mb-4">
<div>
<h3 class="text-2xl">{{ day.fancy }}</h3>
</div>
{% if edit %}
<div><a href="{{ url_for('main.index', day=day.string) }}" class="link">done</a></div>
{% else %}
{% if accomplishments %}
<div><a href="{{ url_for('main.edit_day', day=day.string) }}" class="link">edit</a></div>
{% endif %}
{% endif %}
</div>
{% for accomplishment in accomplishments %}
<div class="flex ml-2 accomplishment">
<div class="py-1 text">{{ accomplishment.text }}</div>
<div class="py-1 {% if edit %} mr-2 {% endif %} difficulty-{{ accomplishment.difficulty_class }} difficulty">
{{ accomplishment.difficulty }} XP
</div>
{% if edit %}
<div class="flex-shrink-0 py-1 pl-2 text-sm italic border-l border-gray-300 border-solid">
<div>
<a class="text-red-700 underline hover:text-red-500"
href="{{ url_for('main.delete_accomplishment', accomplishment_id=accomplishment.id) }}">delete</a>
</div>
</div>
{% endif %}
</div>
<hr>
{% else %}
<div class="my-1 ml-2 text-sm accomplishment">
{% if false %}
<!-- TODO: random text if no accomplishments -->{% endif %}
{% if is_today %}
<!-- TODO: random text if no accomplishments -->
{% endif %}
{% if day.is_today %}
<p>No accomplishments today... yet!</p>
{% else %}
<p>Nothing logged that day... but it's okay to take a break!</p>
@ -33,14 +54,13 @@
</div>
{% endfor %}
<div class="flex justify-end my-1 ml-2 accomplishment">
<div><span class="pr-1 text-xs text-gray-700">total:</span> <span class="difficulty">{{ total }} XP</div>
<div><span class="pr-1 text-xs text-gray-700">total:</span> <span class="difficulty">{{ total_xp }} XP</div>
</div>
<div class="flex justify-between mt-2 text-sm accomplishment">
<div><a href="{{ url_for('main.index', day=yesterday) }}" class="text-blue-700">Previous day</a></div>
{% if tomorrow %}<a href="{{ url_for('main.index', day=tomorrow) }}" class="text-blue-700">Next day</a>
</div>{% endif %}
<div><a href="{{ links.yesterday }}" class="text-blue-700">Previous day</a></div>
{% if links.tomorrow %}<a href="{{ links.tomorrow }}" class="text-blue-700">Next day</a>
{% endif %}
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,19 @@
{% extends "_skel.html" %}
{% block content %}
<div class="max-w-xl mx-auto text-center card">
<p class="italic">
{{ accomplishment.text }}
</p>
<p class="mt-2 font-bold difficulty-{{ accomplishment.difficulty_class }}">({{ accomplishment.difficulty }}
XP)
</p>
</div>
<div class="max-w-lg mx-auto text-center card">
<h3 class="text-lg">Are you sure you want to remove this accomplishment?</h3>
<form class="mt-2" method="POST">
{{ form.csrf_token }}
{{ form.submit(class_="hover:bg-red-500 bg-red-700 text-white") }}
<a href="{{ cancel }}" class="block mt-2 text-sm text-blue-700 hover:text-blue-500">cancel</a>
</form>
</div>
{% endblock %}

View File

@ -25,6 +25,8 @@ def _suffix(d):
def as_fancy_str(day_):
if day_ is None:
return None
if is_today(day_):
return "Today"
return day_.strftime("%B {S}, %Y").replace('{S}', str(day_.day) + _suffix(day_.day))