Improve Dashboard view.

This commit adds a placeholder image for Child objects (in the future, hopefully, photo uploads will be added) and reworks the Dashboard view to look better when more than one child is in the database. There are also some minor tweaks to the Child detail view and one new Gulp requirement to improve the flow of copying static image assets from apps.
This commit is contained in:
Christopher Charbonneau Wells 2017-11-06 16:24:21 -05:00
parent 7955cd04a7
commit e2733e6b1e
12 changed files with 117 additions and 78 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@ -0,0 +1,5 @@
#view-child {
.child-photo {
max-width: 150px;
}
}

View File

@ -1,4 +1,5 @@
{% extends 'babybuddy/page.html' %}
{% load static %}
{% block title %}{{ object }}{% endblock %}
@ -9,48 +10,12 @@
{% block content %}
<div class="jumbotron text-center">
<div class="display-3">{{ object }}</div>
<img src="{% static 'babybuddy/img/core/child-placeholder.png' %}" class="child-photo img-fluid rounded-circle" />
<div class="child-name display-4">{{ object }}</div>
<p class="lead">
Born <span class="text-secondary">{{ object.birth_date }}</span><br/>
Age <span class="text-secondary">{{ object.birth_date|timesince }}</span>
</p>
<div class="btn-group btn-group-lg center-block" role="group" aria-label="Timer actions">
{% if perms.core.view_child %}
<a href="{% url 'dashboard-child' object.slug %}" class="btn btn-success">
<i class="icon icon-dashboard" aria-hidden="true"></i>
</a>
{% endif %}
<div class="btn-group" role="group">
<button id="reports-dropdown"
class="btn btn-primary dropdown-toggle"
type="button"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"><i class="icon icon-graph" aria-hidden="true"></i></button>
<div class="dropdown-menu" aria-labelledby="reports-dropdown">
<a class="dropdown-item" href="{% url 'reports:report-diaperchange-types-child' object.slug %}">Diaper Change Types</a>
<a class="dropdown-item" href="{% url 'reports:report-diaperchange-lifetimes-child' object.slug %}">Diaper Lifetimes</a>
<a class="dropdown-item" href="{% url 'reports:report-sleep-pattern-child' object.slug %}">Sleep Pattern</a>
<a class="dropdown-item" href="{% url 'reports:report-sleep-totals-child' object.slug %}">Sleep Totals</a>
<a class="dropdown-item" href="{% url 'reports:report-timeline-child' object.slug %}">Timeline</a>
</div>
</div>
{% if perms.core.change_child %}
<a class="btn btn-warning"
href="{% url 'child-update' object.slug %}"
role="button"><i class="icon icon-update" aria-hidden="true"></i></a>
{% endif %}
{% if perms.core.delete_child %}
<a class="btn btn-danger"
href="{% url 'child-delete' object.slug %}"
role="button"><i class="icon icon-delete" aria-hidden="true"></i></a>
{% endif %}
</div>
{% include 'dashboard/child_button_group.html' %}
</div>
{% endblock %}

View File

View File

@ -0,0 +1,37 @@
<div class="child-actions btn-group btn-group-lg center-block" role="group" aria-label="Child actions">
{% if perms.core.view_child %}
<a href="{% url 'dashboard-child' object.slug %}" class="btn btn-success">
<i class="icon icon-dashboard" aria-hidden="true"></i>
</a>
{% endif %}
<div class="btn-group" role="group">
<button id="reports-dropdown"
class="btn btn-primary dropdown-toggle"
type="button"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"><i class="icon icon-graph" aria-hidden="true"></i></button>
<div class="dropdown-menu" aria-labelledby="reports-dropdown">
<a class="dropdown-item" href="{% url 'reports:report-diaperchange-types-child' object.slug %}">Diaper Change Types</a>
<a class="dropdown-item" href="{% url 'reports:report-diaperchange-lifetimes-child' object.slug %}">Diaper Lifetimes</a>
<a class="dropdown-item" href="{% url 'reports:report-sleep-pattern-child' object.slug %}">Sleep Pattern</a>
<a class="dropdown-item" href="{% url 'reports:report-sleep-totals-child' object.slug %}">Sleep Totals</a>
<a class="dropdown-item" href="{% url 'reports:report-timeline-child' object.slug %}">Timeline</a>
</div>
</div>
{% if perms.core.change_child %}
<a class="btn btn-warning"
href="{% url 'child-update' object.slug %}"
role="button"><i class="icon icon-update" aria-hidden="true"></i></a>
{% endif %}
{% if perms.core.delete_child %}
<a class="btn btn-danger"
href="{% url 'child-delete' object.slug %}"
role="button"><i class="icon icon-delete" aria-hidden="true"></i></a>
{% endif %}
</div>

View File

@ -1,27 +1,31 @@
{% extends 'babybuddy/page.html' %}
{% load static %}
{% block title %}Welcome!{% endblock %}
{% block title %}Dashboard{% endblock %}
{% block breadcrumbs %}
<li class="breadcrumb-item font-weight-bold">Dashboard</li>
{% endblock %}
{% block content %}
<div class="card-group">
{% for child in objects %}
<div class="card">
<img class="card-img-top" style="height: 180px; width: 100%; display: block;" src="data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%22259%22%20height%3D%22180%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20259%20180%22%20preserveAspectRatio%3D%22none%22%3E%3Cdefs%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%23holder_15e152b1929%20text%20%7B%20fill%3Argba(255%2C255%2C255%2C.75)%3Bfont-weight%3Anormal%3Bfont-family%3AHelvetica%2C%20monospace%3Bfont-size%3A13pt%20%7D%20%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%20id%3D%22holder_15e152b1929%22%3E%3Crect%20width%3D%22259%22%20height%3D%22180%22%20fill%3D%22%23777%22%3E%3C%2Frect%3E%3Cg%3E%3Ctext%20x%3D%2296.26666641235352%22%20y%3D%2296%22%3E259x180%3C%2Ftext%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E" data-holder-rendered="true">
<div class="card-body">
<h4 class="card-title">
{{ child.name }}
<small class="text-muted">{{ child.birth_date }}</small>
</h4>
<p class="card-text">
{% if perms.core.view_child %}
<a href="{% url 'dashboard-child' child.slug %}" class="btn btn-success">
<i class="icon icon-dashboard" aria-hidden="true"></i>
</a>
{% endif %}
</p>
</div>
<div class="card-footer">
<small class="text-muted">...</small>
<div class="row">
{% for object in objects %}
<div class="col-xl-2 col-lg-3 col-md-4 col-sm-6 col-xs-2 mb-4">
<div class="card">
<a href="{% url 'child' object.slug %}">
<img src="{% static 'babybuddy/img/core/child-placeholder.png' %}"
class="child-photo img-fluid" />
</a>
<div class="card-body text-center">
<h4 class="card-title">{{ object }}</h4>
<div class="card-text">
<p class="lead">
Born <span class="text-secondary">{{ object.birth_date }}</span><br/>
Age <span class="text-secondary">{{ object.birth_date|timesince }}</span>
</p>
{% include 'dashboard/child_button_group.html' %}
</div>
</div>
</div>
</div>
{% endfor %}

View File

@ -31,17 +31,20 @@ class ViewsTestCase(TestCase):
cls.c.login(**cls.credentials)
def test_dashboard_views(self):
page = self.c.get('/dashboard/')
self.assertEqual(page.status_code, 200)
""" Dashboard handles the root URL and redirects based on zero, one, or
"""Dashboard handles the root URL and redirects based on zero, one, or
more than one child is in the database."""
page = self.c.get('/')
self.assertEqual(page.url, '/dashboard/')
page = self.c.get('/dashboard/')
self.assertEqual(page.url, '/children/add/')
call_command('fake', verbosity=0, children=1)
call_command('fake', verbosity=0, children=1, days=1)
child = Child.objects.first()
page = self.c.get('/')
page = self.c.get('/dashboard/')
self.assertEqual(
page.url, '/children/{}/dashboard/'.format(child.slug))
page = self.c.get('/dashboard/')
self.assertEqual(
page.url, '/children/{}/dashboard/'.format(child.slug))
# Test the actual child dashboard (including cards).
@ -54,5 +57,5 @@ class ViewsTestCase(TestCase):
last_name='Child',
birth_date='2000-01-01'
)
page = self.c.get('/')
self.assertEqual(page.url, '/dashboard/')
page = self.c.get('/dashboard/')
self.assertEqual(page.status_code, 200)

View File

@ -3,6 +3,7 @@ from __future__ import unicode_literals
from django.contrib.auth.mixins import (LoginRequiredMixin,
PermissionRequiredMixin)
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.views.generic.base import TemplateView, RedirectView
from django.views.generic.detail import DetailView
@ -11,22 +12,23 @@ from core.models import Child
class DashboardRedirect(LoginRequiredMixin, RedirectView):
url = '/dashboard/'
class Dashboard(LoginRequiredMixin, TemplateView):
# TODO: Use .card-deck in this template once BS4 is finalized.
template_name = 'dashboard/dashboard.html'
# Show the overall dashboard or a child dashboard if one Child instance.
def get(self, request, *args, **kwargs):
children = Child.objects.count()
if children == 0:
# TODO: Create some sort of welcome page.
self.url = reverse('child-add')
return HttpResponseRedirect(reverse('child-add'))
elif children == 1:
child_instance = Child.objects.first()
self.url = reverse('dashboard-child', args={child_instance.slug})
else:
self.url = reverse('dashboard')
return super(DashboardRedirect, self).get(request, *args, **kwargs)
class Dashboard(LoginRequiredMixin, TemplateView):
template_name = 'dashboard/dashboard.html'
return HttpResponseRedirect(
reverse('dashboard-child', args={Child.objects.first().slug}))
return super(Dashboard, self).get(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = super(Dashboard, self).get_context_data(**kwargs)

View File

@ -15,6 +15,10 @@ module.exports = {
dest: basePath + 'fonts/',
files: 'node_modules/font-awesome/fonts/*'
},
images: {
dest: basePath + 'img/',
files: '**/static_src/img/**/*'
},
root: {
dest: basePath + 'root/',
files: 'babybuddy/static_src/root/*'

View File

@ -1,11 +1,12 @@
var gulp = require('gulp');
var flatten = require('gulp-flatten');
var pump = require('pump');
var extrasConfig = require('../config.js').extrasConfig;
gulp.task('extras', ['extras:fonts', 'extras:root']);
gulp.task('extras', ['extras:fonts', 'extras:images', 'extras:root']);
gulp.task('extras:fonts', function(cb) {
pump([
@ -14,6 +15,14 @@ gulp.task('extras:fonts', function(cb) {
], cb);
});
gulp.task('extras:images', function(cb) {
pump([
gulp.src(extrasConfig.images.files),
flatten({ subPath: 3 }),
gulp.dest(extrasConfig.images.dest)
], cb);
});
gulp.task('extras:root', function(cb) {
pump([
gulp.src(extrasConfig.root.files),

9
package-lock.json generated
View File

@ -4000,6 +4000,15 @@
"vinyl-sourcemaps-apply": "0.2.1"
}
},
"gulp-flatten": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/gulp-flatten/-/gulp-flatten-0.3.1.tgz",
"integrity": "sha1-Uef+wTozxARXjRjBWJ0bW8Rf4dY=",
"requires": {
"gulp-util": "3.0.8",
"through2": "2.0.3"
}
},
"gulp-sass": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/gulp-sass/-/gulp-sass-3.1.0.tgz",

View File

@ -24,6 +24,7 @@
"gulp": "^3.9.1",
"gulp-concat": "^2.6.1",
"gulp-csso": "^3.0.0",
"gulp-flatten": "^0.3.1",
"gulp-sass": "^3.1.0",
"gulp-sass-glob": "^1.0.8",
"gulp-sass-lint": "^1.3.4",