Add feeding method history (#774)

* add feeding method history

* Make it a specialized breastfeeding card instead.

* Minor improvements:

 - don't print days for an empty card.
 - make the width of the bar for each day proportional to that day's total feeding time.

* Don't make bar width proportional to feeding time, actually, it's kinda ugly.

---------

Co-authored-by: ag <ag@ag.com>
Co-authored-by: Christopher C. Wells <git-2022@chris-wells.net>
This commit is contained in:
abog854 2024-03-14 03:59:50 +01:00 committed by GitHub
parent 25d3c9f58c
commit ab5bb66c8f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 123 additions and 2 deletions

View File

@ -73,6 +73,10 @@
font-size: 2em; font-size: 2em;
} }
} }
.progress {
height: $progress-height * 2;
}
} }
.card-sleep { .card-sleep {

View File

@ -0,0 +1,36 @@
{% extends 'cards/base.html' %}
{% load duration i18n %}
{% block header %}
<a href="{% url "core:feeding-list" %}">{% trans "Breastfeeding" %}</a>
{% endblock %}
{% block title %}
{% if total == 0 %}
{% trans "None" %}
{% else %}
{% trans "Past Week" %}
{% endif %}
{% endblock %}
{% block content %}
{% for key, info in stats.items %}
{% if info.left_count > 0 or info.right_count > 0 %}
<div class="progress mt-3" role="progressbar">
<div class="progress-bar bg-primary lead"
style="width: {{ info.left_pct|safe }}%">{{ info.left_count }}&nbsp;{% trans "left" %}</div>
<div class="progress-bar bg-secondary lead"
style="width: {{ info.right_pct|safe }}%">{{ info.right_count }}&nbsp;{% trans "right" %}</div>
</div>
<div class="text-center text-light small">
{% if key == 0 %}
{% trans "today" %}
{% elif key == 1 %}
{% trans "yesterday" %}
{% else %}
{% blocktrans with days_ago=key %}{{ days_ago }} days ago{% endblocktrans %}
{% endif %}
{% if info.count > 0 %}
({{ info.count }} {% trans "feedings in" %} {{ info.duration|duration_string:'m' }})
{% endif %}
</div>
{% endif %}
{% endfor %}
{% endblock %}

View File

@ -26,6 +26,7 @@
<div class="col-sm-6 col-lg-4">{% card_sleep_naps_day object %}</div> <div class="col-sm-6 col-lg-4">{% card_sleep_naps_day object %}</div>
<div class="col-sm-6 col-lg-4">{% card_tummytime_day object %}</div> <div class="col-sm-6 col-lg-4">{% card_tummytime_day object %}</div>
<div class="col-sm-6 col-lg-4">{% card_diaperchange_types object %}</div> <div class="col-sm-6 col-lg-4">{% card_diaperchange_types object %}</div>
<div class="col-sm-6 col-lg-4">{% card_breastfeeding object %}</div>
</div> </div>
{% endblock %} {% endblock %}
{% block javascript %} {% block javascript %}

View File

@ -5,7 +5,8 @@ from django.db.models.functions import TruncDate
from django.utils import timezone from django.utils import timezone
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from datetime import date, datetime, time from datetime import date, datetime, time, timedelta
import collections
from core import models from core import models
@ -107,6 +108,77 @@ def card_diaperchange_types(context, child, date=None):
} }
@register.inclusion_tag("cards/breastfeeding.html", takes_context=True)
def card_breastfeeding(context, child, date=None):
"""
Creates a break down of breasts used for breastfeeding, for the past
seven days.
:param child: an instance of the Child model.
:param date: a Date object for the day to filter.
:returns: a dictionary with the statistics.
"""
if date:
time = timezone.datetime.combine(date, timezone.localtime().min.time())
time = timezone.make_aware(time)
else:
time = timezone.localtime()
max_date = (time + timezone.timedelta(days=1)).replace(hour=0, minute=0, second=0)
min_date = (max_date - timezone.timedelta(days=7)).replace(
hour=0, minute=0, second=0
)
instances = (
models.Feeding.objects.filter(child=child)
.filter(start__gt=min_date)
.filter(start__lt=max_date)
.filter(method__in=("left breast", "right breast", "both breasts"))
.order_by("-start")
)
empty = len(instances) == 0
# Create a `stats` dictionary, keyed by day for the past 7 days.
stats = {}
for x in range(7):
stats[x] = {}
# Group feedings per day.
per_day = collections.defaultdict(list)
for instance in instances:
key = (max_date - instance.start).days
per_day[key].append(instance)
# Go through each day, set the stats dictionary for that day.
for key, day_instances in per_day.items():
left_count = 0
right_count = 0
for instance in day_instances:
if instance.method in ("left breast", "both breasts"):
left_count += 1
if instance.method in ("right breast", "both breasts"):
right_count += 1
stats[key] = {
"count": len(day_instances),
"duration": sum(
(instance.duration for instance in day_instances), start=timedelta()
),
"left_count": left_count,
"right_count": right_count,
"left_pct": 100 * left_count // (left_count + right_count),
"right_pct": 100 * right_count // (left_count + right_count),
}
return {
"type": "feeding",
"stats": stats,
"total": len(instances),
"empty": empty,
"hide_empty": _hide_empty(context),
}
@register.inclusion_tag("cards/feeding_recent.html", takes_context=True) @register.inclusion_tag("cards/feeding_recent.html", takes_context=True)
def card_feeding_recent(context, child, end_date=None): def card_feeding_recent(context, child, end_date=None):
""" """

View File

@ -12145,6 +12145,10 @@ textarea.form-control-lg {
.card-pumping .card-body .last-feeding-method { .card-pumping .card-body .last-feeding-method {
font-size: 2em; font-size: 2em;
} }
.card-feeding .progress,
.card-pumping .progress {
height: 2rem;
}
.card-sleep { .card-sleep {
border-color: #ff8f00; border-color: #ff8f00;

View File

@ -12145,6 +12145,10 @@ textarea.form-control-lg {
.card-pumping .card-body .last-feeding-method { .card-pumping .card-body .last-feeding-method {
font-size: 2em; font-size: 2em;
} }
.card-feeding .progress,
.card-pumping .progress {
height: 2rem;
}
.card-sleep { .card-sleep {
border-color: #ff8f00; border-color: #ff8f00;

Binary file not shown.

File diff suppressed because one or more lines are too long