diff --git a/dashboard/templates/cards/sleep_day.html b/dashboard/templates/cards/sleep_day.html index 6f1a8d61c..3621953fe 100644 --- a/dashboard/templates/cards/sleep_day.html +++ b/dashboard/templates/cards/sleep_day.html @@ -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 %} + +{% else %} +{% trans "None" %} +{% endif %} {% endblock %} \ No newline at end of file diff --git a/dashboard/templatetags/cards.py b/dashboard/templatetags/cards.py index 55924856b..b53c0db0a 100644 --- a/dashboard/templatetags/cards.py +++ b/dashboard/templatetags/cards.py @@ -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), } diff --git a/dashboard/tests/tests_templatetags.py b/dashboard/tests/tests_templatetags.py index cc5180de7..a8c6a3b73 100644 --- a/dashboard/tests/tests_templatetags.py +++ b/dashboard/tests/tests_templatetags.py @@ -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)