Skip to content

Commit

Permalink
Add sleep stats carousel for last 7 days
Browse files Browse the repository at this point in the history
  • Loading branch information
DanBeard committed Jun 15, 2022
1 parent dcc1275 commit 8f92725
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 34 deletions.
52 changes: 42 additions & 10 deletions dashboard/templates/cards/sleep_day.html
Expand Up @@ -8,15 +8,47 @@
{% endblock %}

{% block title %}
{% if total %}
{{ total|duration_string }}
{% else %}
{% trans "None" %}
{% endif %}
{% endblock %}

{% block content %}
{% if count > 0 %}
{% blocktrans %}{{ count }} sleep entries{% endblocktrans %}
{% if sleeps|length > 0 %}
<div id="sleep-days-carousel" class="carousel slide" data-interval="false">
<div class="carousel-inner">
{% for sleep in sleeps %}
<div class="carousel-item{% if forloop.counter == 1 %} active{% endif %}">
<div class="last-sleep-method text-center">
{% if sleep.total %}
{{ sleep.total|duration_string:"m" }}
{% else %}
{% trans "None" %}
{% endif %}
</div>
<div class="text-center small">
{% if sleep.count > 0 %}
{% blocktrans trimmed count counter=sleep.count %}
{{ counter }} sleep
{% plural %}
{{ counter }} sleep
{% endblocktrans %}
{% endif %}
</div>
{% blocktrans trimmed with since=sleep.date.date|dayssince %}
<div class="text-center small text-muted">
{{ since }}
</div>
{% endblocktrans %}
</div>
{% endfor %}
</div>
{% if sleeps|length > 1 %}
<a class="carousel-control-prev" href="#sleep-days-carousel" role="button" data-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="sr-only">{% trans "Previous" %}</span>
</a>
<a class="carousel-control-next" href="#sleep-days-carousel" role="button" data-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="sr-only">{% trans "Next" %}</span>
</a>
{% endif %}
</div>
{% else %}
{% trans "None" %}
{% endif %}
{% endblock %}
73 changes: 51 additions & 22 deletions dashboard/templatetags/cards.py
Expand Up @@ -222,41 +222,70 @@ def card_sleep_last(context, child):


@register.inclusion_tag("cards/sleep_day.html", takes_context=True)
def card_sleep_day(context, child, date=None):
def card_sleep_day(context, child, end_date=None):
"""
Filters Sleep instances to get count and total values for a specific date.
Filters sleeping instances to get total amount for a specific date and for 7 days before
:param child: an instance of the Child model.
:param date: a Date object for the day to filter.
:returns: a dictionary with count and total values for the Sleep instances.
:param end_date: a Date object for the day to filter.
:returns: a dict with count and total amount for the sleeping instances.
"""
if not date:
date = timezone.localtime().date()
if not end_date:
end_date = timezone.localtime()

# push end_date to very end of that day
end_date = end_date.replace(hour=23, minute=59, second=59, microsecond=9999)
# we need a datetime to use the range helper in the model
start_date = end_date - timezone.timedelta(
days=8
) # end of the -8th day so we get the FULL 7th day

instances = models.Sleep.objects.filter(child=child).filter(
start__year=date.year, start__month=date.month, start__day=date.day
start__range=[start_date, end_date]
) | models.Sleep.objects.filter(child=child).filter(
end__year=date.year, end__month=date.month, end__day=date.day
end__range=[start_date, end_date]
)
empty = len(instances) == 0

total = timezone.timedelta(seconds=0)
# prepare the result list for the last 7 days
dates = [end_date - timezone.timedelta(days=i) for i in range(8)]
results = [{"date": d, "total": timezone.timedelta(), "count": 0} for d in dates]

# do one pass over the data and add it to the appropriate day
for instance in instances:
# convert to local tz and push feed_date to end so we're comparing apples to apples for the date
start = timezone.localtime(instance.start)
end = timezone.localtime(instance.end)
# Account for dates crossing midnight.
if start.date() != date:
start = start.replace(
year=end.year, month=end.month, day=end.day, hour=0, minute=0, second=0
)

total += end - start

count = len(instances)
sleep_start_date = start.replace(
hour=23, minute=59, second=59, microsecond=9999
)
sleep_end_date = end.replace(hour=23, minute=59, second=59, microsecond=9999)
start_idx = (end_date - sleep_start_date).days
end_idx = (end_date - sleep_end_date).days
# this is more complicated than feedings because we only want to capture the PORTION of sleep
# that is a part of this day (e.g. starts sleep at 7PM and finished at 7AM = 5 hrs yesterday 7 hrs today)
# (Assuming you have a unicorn sleeper. Congratulations)
if start_idx == end_idx: # if we're in the same day it's simple
result = results[start_idx]
result["total"] += end - start
result["count"] += 1
else: # otherwise we need to split the time up
midnight = end.replace(hour=0, minute=0, second=0)

if 0 <= start_idx < len(results):
result = results[start_idx]
# only the portion that is today
result["total"] += midnight - start
result["count"] += 1

if 0 <= end_idx < len(results):
result = results[end_idx]
# only the portion that is tomorrow
result["total"] += end - midnight
result["count"] += 1

return {
"sleeps": results,
"type": "sleep",
"total": total,
"count": count,
"empty": empty,
"empty": len(instances) == 0,
"hide_empty": _hide_empty(context),
}

Expand Down
10 changes: 8 additions & 2 deletions dashboard/tests/tests_templatetags.py
Expand Up @@ -208,8 +208,14 @@ def test_card_sleep_day(self):
self.assertEqual(data["type"], "sleep")
self.assertFalse(data["empty"])
self.assertFalse(data["hide_empty"])
self.assertEqual(data["total"], timezone.timedelta(2, 7200))
self.assertEqual(data["count"], 4)
self.assertEqual(data["sleeps"][0]["total"], timezone.timedelta(hours=7))
self.assertEqual(data["sleeps"][0]["count"], 4)

self.assertEqual(data["sleeps"][1]["total"], timezone.timedelta(minutes=30))
self.assertEqual(data["sleeps"][1]["count"], 1)

self.assertEqual(data["sleeps"][6]["total"], timezone.timedelta(hours=1))
self.assertEqual(data["sleeps"][6]["count"], 1)

def test_card_sleep_naps_day(self):
data = cards.card_sleep_naps_day(self.context, self.child, self.date)
Expand Down

0 comments on commit 8f92725

Please sign in to comment.