mirror of https://github.com/snachodog/mybuddy.git
Populate the all-children timeline
This commit is contained in:
parent
0990678325
commit
10af931279
|
@ -29,77 +29,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-8 offset-lg-4 col-md-6 offset-md-6">
|
<div class="col-lg-8 offset-lg-4 col-md-6 offset-md-6">
|
||||||
<h3 class="text-center">
|
{% include 'timeline/_timeline.html' %}
|
||||||
{% if date_previous %}
|
|
||||||
<a class="btn btn-sm btn-default" href="?date={{ date_previous|date:"Y-m-d" }}" aria-label="{% trans "Previous" %}">
|
|
||||||
<i class="icon icon-chevron-left" aria-hidden="true"></i>
|
|
||||||
<span class="sr-only">{% trans "Previous" %}</span>
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
{{ date|date }}
|
|
||||||
{% if date_next %}
|
|
||||||
<a class="btn btn-sm btn-default" href="?date={{ date_next|date:"Y-m-d" }}" aria-label="{% trans "Next" %}">
|
|
||||||
<i class="icon icon-chevron-right" aria-hidden="true"></i>
|
|
||||||
<span class="sr-only">{% trans "Next" %}</span>
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
</h3>
|
|
||||||
{% if timeline_objects %}
|
|
||||||
<ul class="timeline m-auto">
|
|
||||||
{% for object in timeline_objects %}
|
|
||||||
<li{% cycle "" ' class="timeline-inverted"' %}>
|
|
||||||
<div class="timeline-badge {% if object.type == "start" %}bg-success{% elif object.type == "end" %}bg-danger{% else %}bg-info{% endif %}">
|
|
||||||
<i class="icon icon-{{ object.model_name }}"></i>
|
|
||||||
</div>
|
|
||||||
<div class="card text-right">
|
|
||||||
<div class="card-body">
|
|
||||||
{{ object.event }}
|
|
||||||
{% for detail in object.details %}
|
|
||||||
<div><small>{{ detail }}</small></div>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
<div class="card-footer text-muted">
|
|
||||||
{% blocktrans trimmed with since=object.time|timesince time=object.time|time %}
|
|
||||||
{{ since }} ago ({{ time }})
|
|
||||||
{% endblocktrans %}
|
|
||||||
{% if object.duration %}
|
|
||||||
<div>
|
|
||||||
<small>Duration: {{ object.duration }}</small>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% if object.time_since_prev %}
|
|
||||||
<div>
|
|
||||||
<small>{{ object.time_since_prev }} since previous</small>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% if object.edit_link %}
|
|
||||||
<div>
|
|
||||||
<small><a href="{{ object.edit_link }}">Edit</a></small>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
<h3 class="text-center">
|
|
||||||
{% if date_previous %}
|
|
||||||
<a class="btn btn-sm btn-default" href="?date={{ date_previous|date:"Y-m-d" }}" aria-label="{% trans "Previous" %}">
|
|
||||||
<i class="icon icon-chevron-left" aria-hidden="true"></i>
|
|
||||||
<span class="sr-only">{% trans "Previous" %}</span>
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
{{ date|date }}
|
|
||||||
{% if date_next %}
|
|
||||||
<a class="btn btn-sm btn-default" href="?date={{ date_next|date:"Y-m-d" }}" aria-label="{% trans "Next" %}">
|
|
||||||
<i class="icon icon-chevron-right" aria-hidden="true"></i>
|
|
||||||
<span class="sr-only">{% trans "Next" %}</span>
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
</h3>
|
|
||||||
{% else %}
|
|
||||||
<div class="text-center">No events</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
<h3 class="text-center">
|
||||||
|
{% if date_previous %}
|
||||||
|
<a class="btn btn-sm btn-default" href="?date={{ date_previous|date:"Y-m-d" }}" aria-label="{% trans "Previous" %}">
|
||||||
|
<i class="icon icon-chevron-left" aria-hidden="true"></i>
|
||||||
|
<span class="sr-only">{% trans "Previous" %}</span>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
{{ date|date }}
|
||||||
|
{% if date_next %}
|
||||||
|
<a class="btn btn-sm btn-default" href="?date={{ date_next|date:"Y-m-d" }}" aria-label="{% trans "Next" %}">
|
||||||
|
<i class="icon icon-chevron-right" aria-hidden="true"></i>
|
||||||
|
<span class="sr-only">{% trans "Next" %}</span>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</h3>
|
||||||
|
{% if timeline_objects %}
|
||||||
|
<ul class="timeline m-auto">
|
||||||
|
{% for object in timeline_objects %}
|
||||||
|
<li{% cycle "" ' class="timeline-inverted"' %}>
|
||||||
|
<div class="timeline-badge {% if object.type == "start" %}bg-success{% elif object.type == "end" %}bg-danger{% else %}bg-info{% endif %}">
|
||||||
|
<i class="icon icon-{{ object.model_name }}"></i>
|
||||||
|
</div>
|
||||||
|
<div class="card text-right">
|
||||||
|
<div class="card-body">
|
||||||
|
{{ object.event }}
|
||||||
|
{% for detail in object.details %}
|
||||||
|
<div><small>{{ detail }}</small></div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<div class="card-footer text-muted">
|
||||||
|
{% blocktrans trimmed with since=object.time|timesince time=object.time|time %}
|
||||||
|
{{ since }} ago ({{ time }})
|
||||||
|
{% endblocktrans %}
|
||||||
|
{% if object.duration %}
|
||||||
|
<div>
|
||||||
|
<small>Duration: {{ object.duration }}</small>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if object.time_since_prev %}
|
||||||
|
<div>
|
||||||
|
<small>{{ object.time_since_prev }} since previous</small>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if object.edit_link %}
|
||||||
|
<div>
|
||||||
|
<small><a href="{{ object.edit_link }}">Edit</a></small>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
<h3 class="text-center">
|
||||||
|
{% if date_previous %}
|
||||||
|
<a class="btn btn-sm btn-default" href="?date={{ date_previous|date:"Y-m-d" }}" aria-label="{% trans "Previous" %}">
|
||||||
|
<i class="icon icon-chevron-left" aria-hidden="true"></i>
|
||||||
|
<span class="sr-only">{% trans "Previous" %}</span>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
{{ date|date }}
|
||||||
|
{% if date_next %}
|
||||||
|
<a class="btn btn-sm btn-default" href="?date={{ date_next|date:"Y-m-d" }}" aria-label="{% trans "Next" %}">
|
||||||
|
<i class="icon icon-chevron-right" aria-hidden="true"></i>
|
||||||
|
<span class="sr-only">{% trans "Next" %}</span>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</h3>
|
||||||
|
{% else %}
|
||||||
|
<div class="text-center">No events</div>
|
||||||
|
{% endif %}
|
|
@ -8,5 +8,9 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{# TODO! #}
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
{% include 'timeline/_timeline.html' %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -7,30 +7,32 @@ from core.models import DiaperChange, Feeding, Sleep, TummyTime
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
|
||||||
|
|
||||||
def get_objects(child, date):
|
def get_objects(date, child=None):
|
||||||
"""
|
"""
|
||||||
Create a time-sorted dictionary of all events for a child.
|
Create a time-sorted dictionary of all events for a child.
|
||||||
:param child: an instance of a Child.
|
|
||||||
:param date: a DateTime instance for the day to be summarized.
|
:param date: a DateTime instance for the day to be summarized.
|
||||||
|
:param child: Child instance to filter results for (no filter if `None`).
|
||||||
:returns: a list of the day's events.
|
:returns: a list of the day's events.
|
||||||
"""
|
"""
|
||||||
min_date = date
|
min_date = date
|
||||||
max_date = date.replace(hour=23, minute=59, second=59)
|
max_date = date.replace(hour=23, minute=59, second=59)
|
||||||
events = []
|
events = []
|
||||||
|
|
||||||
_add_diaper_changes(child, min_date, max_date, events)
|
_add_diaper_changes(min_date, max_date, events, child)
|
||||||
_add_feedings(child, min_date, max_date, events)
|
_add_feedings(min_date, max_date, events, child)
|
||||||
_add_sleeps(child, min_date, max_date, events)
|
_add_sleeps(min_date, max_date, events, child)
|
||||||
_add_tummy_times(child, min_date, max_date, events)
|
_add_tummy_times(min_date, max_date, events, child)
|
||||||
|
|
||||||
events.sort(key=lambda x: x['time'], reverse=True)
|
events.sort(key=lambda x: x['time'], reverse=True)
|
||||||
|
|
||||||
return events
|
return events
|
||||||
|
|
||||||
|
|
||||||
def _add_tummy_times(child, min_date, max_date, events):
|
def _add_tummy_times(min_date, max_date, events, child=None):
|
||||||
instances = TummyTime.objects.filter(child=child).filter(
|
instances = TummyTime.objects.filter(
|
||||||
start__range=(min_date, max_date)).order_by('-start')
|
start__range=(min_date, max_date)).order_by('-start')
|
||||||
|
if child:
|
||||||
|
instances = instances.filter(child=child)
|
||||||
for instance in instances:
|
for instance in instances:
|
||||||
details = []
|
details = []
|
||||||
if instance.milestone:
|
if instance.milestone:
|
||||||
|
@ -59,9 +61,11 @@ def _add_tummy_times(child, min_date, max_date, events):
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
def _add_sleeps(child, min_date, max_date, events):
|
def _add_sleeps(min_date, max_date, events, child=None):
|
||||||
instances = Sleep.objects.filter(child=child).filter(
|
instances = Sleep.objects.filter(
|
||||||
start__range=(min_date, max_date)).order_by('-start')
|
start__range=(min_date, max_date)).order_by('-start')
|
||||||
|
if child:
|
||||||
|
instances = instances.filter(child=child)
|
||||||
for instance in instances:
|
for instance in instances:
|
||||||
details = []
|
details = []
|
||||||
if instance.notes:
|
if instance.notes:
|
||||||
|
@ -90,12 +94,15 @@ def _add_sleeps(child, min_date, max_date, events):
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
def _add_feedings(child, min_date, max_date, events):
|
def _add_feedings(min_date, max_date, events, child=None):
|
||||||
yesterday = min_date - timedelta(days=1) # So first feeding has a previous
|
# Ensure first feeding has a previous.
|
||||||
|
yesterday = min_date - timedelta(days=1)
|
||||||
prev_start = None
|
prev_start = None
|
||||||
|
|
||||||
instances = Feeding.objects.filter(child=child).filter(
|
instances = Feeding.objects.filter(
|
||||||
start__range=(yesterday, max_date)).order_by('start')
|
start__range=(yesterday, max_date)).order_by('start')
|
||||||
|
if child:
|
||||||
|
instances = instances.filter(child=child)
|
||||||
for instance in instances:
|
for instance in instances:
|
||||||
details = []
|
details = []
|
||||||
if instance.notes:
|
if instance.notes:
|
||||||
|
@ -136,9 +143,11 @@ def _add_feedings(child, min_date, max_date, events):
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
def _add_diaper_changes(child, min_date, max_date, events):
|
def _add_diaper_changes(min_date, max_date, events, child):
|
||||||
instances = DiaperChange.objects.filter(child=child).filter(
|
instances = DiaperChange.objects.filter(
|
||||||
time__range=(min_date, max_date)).order_by('-time')
|
time__range=(min_date, max_date)).order_by('-time')
|
||||||
|
if child:
|
||||||
|
instances = instances.filter(child=child)
|
||||||
for instance in instances:
|
for instance in instances:
|
||||||
contents = []
|
contents = []
|
||||||
if instance.wet:
|
if instance.wet:
|
||||||
|
@ -153,7 +162,7 @@ def _add_diaper_changes(child, min_date, max_date, events):
|
||||||
events.append({
|
events.append({
|
||||||
'time': timezone.localtime(instance.time),
|
'time': timezone.localtime(instance.time),
|
||||||
'event': _('%(child)s had a diaper change.') % {
|
'event': _('%(child)s had a diaper change.') % {
|
||||||
'child': child.first_name
|
'child': instance.child.first_name
|
||||||
},
|
},
|
||||||
'details': details,
|
'details': details,
|
||||||
'edit_link': reverse('core:diaperchange-update',
|
'edit_link': reverse('core:diaperchange-update',
|
||||||
|
|
|
@ -17,6 +17,17 @@ from babybuddy.views import BabyBuddyFilterView
|
||||||
from core import forms, models, timeline
|
from core import forms, models, timeline
|
||||||
|
|
||||||
|
|
||||||
|
def _prepare_timeline_context_data(context, date, child=None):
|
||||||
|
date = timezone.datetime.strptime(date, '%Y-%m-%d')
|
||||||
|
date = timezone.localtime(timezone.make_aware(date))
|
||||||
|
context['timeline_objects'] = timeline.get_objects(date, child)
|
||||||
|
context['date'] = date
|
||||||
|
context['date_previous'] = date - timezone.timedelta(days=1)
|
||||||
|
if date.date() < timezone.localdate():
|
||||||
|
context['date_next'] = date + timezone.timedelta(days=1)
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class CoreAddView(PermissionRequired403Mixin, SuccessMessageMixin, CreateView):
|
class CoreAddView(PermissionRequired403Mixin, SuccessMessageMixin, CreateView):
|
||||||
def get_success_message(self, cleaned_data):
|
def get_success_message(self, cleaned_data):
|
||||||
cleaned_data['model'] = self.model._meta.verbose_name.title()
|
cleaned_data['model'] = self.model._meta.verbose_name.title()
|
||||||
|
@ -92,13 +103,7 @@ class ChildDetail(PermissionRequired403Mixin, DetailView):
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(ChildDetail, self).get_context_data(**kwargs)
|
context = super(ChildDetail, self).get_context_data(**kwargs)
|
||||||
date = self.request.GET.get('date', str(timezone.localdate()))
|
date = self.request.GET.get('date', str(timezone.localdate()))
|
||||||
date = timezone.datetime.strptime(date, '%Y-%m-%d')
|
_prepare_timeline_context_data(context, date, self.object)
|
||||||
date = timezone.localtime(timezone.make_aware(date))
|
|
||||||
context['timeline_objects'] = timeline.get_objects(self.object, date)
|
|
||||||
context['date'] = date
|
|
||||||
context['date_previous'] = date - timezone.timedelta(days=1)
|
|
||||||
if date.date() < timezone.localdate():
|
|
||||||
context['date_next'] = date + timezone.timedelta(days=1)
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
@ -284,8 +289,8 @@ class Timeline(LoginRequiredMixin, TemplateView):
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(Timeline, self).get_context_data(**kwargs)
|
context = super(Timeline, self).get_context_data(**kwargs)
|
||||||
# TODO: Get relevant data for a given day.
|
date = self.request.GET.get('date', str(timezone.localdate()))
|
||||||
context['objects'] = models.Child.objects.all()
|
_prepare_timeline_context_data(context, date)
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue