Add custom timedelta filter and styles
This commit is contained in:
parent
ec573cafdc
commit
2065c6d1ee
@ -29,10 +29,9 @@ class Period(models.Model):
|
|||||||
created = models.DateTimeField(auto_now_add=True)
|
created = models.DateTimeField(auto_now_add=True)
|
||||||
modified = models.DateTimeField(auto_now=True)
|
modified = models.DateTimeField(auto_now=True)
|
||||||
|
|
||||||
# def duration(self):
|
@property
|
||||||
# duration = self.clocked_out - self.clocked_in
|
def p_duration(self):
|
||||||
# duration_in_s = duration.total_seconds()
|
return round((self.clocked_out - self.clocked_in).seconds / 3600, 2)
|
||||||
# return divmod(duration_in_s, 3600)[0]
|
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('period-detail', kwargs={'pk': self.pk})
|
return reverse('period-detail', kwargs={'pk': self.pk})
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
{% extends 'application.html' %}
|
{% extends 'application.html' %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
<section class="clockin panel">
|
||||||
<h1>Scan code to clock-in/out</h1>
|
<h1>Scan code to clock-in/out</h1>
|
||||||
|
<form class="clockin__form" method="post" action="{% url 'attendance-update' %}">
|
||||||
<section>
|
|
||||||
<form method="post" action="{% url 'attendance-update' %}">
|
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{ form.as_p }}
|
{{ form.as_p }}
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,13 @@
|
|||||||
<section>
|
{% load timedelta_filter %}
|
||||||
<header>
|
<article class="instructor">
|
||||||
<h1>{{ user.instructor.department.name }}</h1>
|
<section class="instructor__header panel">
|
||||||
|
<h1 class="instructor__department">{{ user.instructor.department.name }}</h1>
|
||||||
<p>
|
<p>
|
||||||
<a href="">Generate Reports</a>
|
<a class="instructor__generate-reports" href="">Generate Reports</a>
|
||||||
</p>
|
</p>
|
||||||
</header>
|
</header>
|
||||||
|
<div class="instructor__active_periods">
|
||||||
<h3>Active sessions</h3>
|
<h3>Students clocked-in</h3>
|
||||||
<p>
|
<p>
|
||||||
<a class="action-button" href="{% url 'period-create' %}">+ Add new session</a>
|
<a class="action-button" href="{% url 'period-create' %}">+ Add new session</a>
|
||||||
</p>
|
</p>
|
||||||
@ -40,8 +41,9 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<article>
|
<section class="instructor__attendance_log">
|
||||||
<div>
|
<div>
|
||||||
<h3>Attendance log</h3>
|
<h3>Attendance log</h3>
|
||||||
<table>
|
<table>
|
||||||
@ -76,8 +78,8 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</section>
|
||||||
<article>
|
<section class="instructor__total_hours">
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@ -89,11 +91,12 @@
|
|||||||
{% for student in student_list %}
|
{% for student in student_list %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ student.user.first_name }} {{ student.user.last_name }}</td>
|
<td>{{ student.user.first_name }} {{ student.user.last_name }}</td>
|
||||||
<td>{{ student.total_hours }}</td>
|
<td>{{ student.total_hours|dimedelta_format }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<tr><td colspan="2">No periods yet.</td></tr>
|
<tr><td colspan="2">No periods yet.</td></tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
</section>
|
||||||
</article>
|
</article>
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
<section class="student panel">
|
{% load timedelta_filter %}
|
||||||
|
<article class="student">
|
||||||
|
<section class="student__header panel">
|
||||||
<h1 class="student__department">{{ user.student.department.name }}</h1>
|
<h1 class="student__department">{{ user.student.department.name }}</h1>
|
||||||
{% if user.student.is_clocked_in %}
|
{% if user.student.is_clocked_in %}
|
||||||
<div class="student__statusbar status">
|
<div class="student__statusbar status">
|
||||||
<p><span class="status__clocked--clocked-in">You are currently clocked in.</span></p>
|
<p><span class="status__clocked--clocked-in">You are currently clocked in.</span></p>
|
||||||
<p>
|
<p class="status__clocked-info">
|
||||||
Clocked in at: <strong>{{ current_period.clocked_in|date:"P" }}</strong><br>
|
Clocked in at: <strong>{{ current_period.clocked_in|date:"P" }}</strong><br>
|
||||||
Current sesson: <strong>{{ current_period.clocked_in|timesince }}</strong>
|
Current sesson: <strong>{{ current_period.clocked_in|timesince }}</strong>
|
||||||
</p>
|
</p>
|
||||||
@ -14,9 +16,10 @@
|
|||||||
{% include 'attendance/_student_code.html' with clocked_in=False %}
|
{% include 'attendance/_student_code.html' with clocked_in=False %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</section>
|
</section>
|
||||||
<section class="attendance">
|
<section class="student__attendance attendance">
|
||||||
<h2 class="attendance__title">Attendance log</h2>
|
<h2 class="attendance__title">Attendance log</h2>
|
||||||
<p class="attendance__total">Total hours for the month: <strong>{{period_total}}</strong><br>
|
<p class="attendance__total">Total hours for the month: <strong>{{ period_total.total|dimedelta_format:2 }}</strong><br>
|
||||||
<small>(Does not include current session.)</small></p>
|
<small>(Does not include current session.)</small></p>
|
||||||
{% include 'attendance/_student_periods.html' %}
|
{% include 'attendance/_student_periods.html' %}
|
||||||
</section>
|
</section>
|
||||||
|
</article>
|
||||||
|
|||||||
@ -2,11 +2,10 @@
|
|||||||
{% load qr_code %}
|
{% load qr_code %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
<section class="code-detail panel">
|
||||||
<h1>Clock in</h1>
|
<h1>Clock in</h1>
|
||||||
|
<p class="code-detail__instructions"><em>Scan code at clock-in station</em></p>
|
||||||
<section class="code_detail">
|
<span class="code-detail__qrcode">{% qr_from_text code.qr_code_str size=24 version=2 %}</span>
|
||||||
<p><em>Scan code at clock-in station</em></p>
|
<span class="code-detail__done"><a class="action-button" href="{% url 'attendance-overview' %}">Done</a></span>
|
||||||
<span>{% qr_from_text code.qr_code_str size=24 version=2 %}</span>
|
|
||||||
<span><a class="action-button" href="{% url 'attendance-overview' %}">Done</a></span>
|
|
||||||
</section>
|
</section>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
{% extends 'application.html' %}
|
{% extends 'application.html' %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>Generate code</h1>
|
|
||||||
|
|
||||||
<section>
|
<section class="code-update panel">
|
||||||
<form method="post" action="{% url 'code-create' %}">
|
<h1>Generate code</h1>
|
||||||
|
<form method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{ form.as_p }}
|
{{ form.as_p }}
|
||||||
|
|
||||||
|
|||||||
0
attendance/templatetags/__init__.py
Normal file
0
attendance/templatetags/__init__.py
Normal file
8
attendance/templatetags/timedelta_filter.py
Normal file
8
attendance/templatetags/timedelta_filter.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
from django import template
|
||||||
|
|
||||||
|
register = template.Library()
|
||||||
|
|
||||||
|
@register.filter()
|
||||||
|
def dimedelta_format(value, arg=2):
|
||||||
|
"""Format timedelta"""
|
||||||
|
return round((value).seconds / 3600, arg)
|
||||||
@ -27,7 +27,7 @@ class AttendanceOverview(LoginRequiredMixin, TemplateView):
|
|||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
context['user'] = User.objects.get(pk=self.request.user.id)
|
context['user'] = self.request.user
|
||||||
if hasattr(self.request.user, 'instructor'):
|
if hasattr(self.request.user, 'instructor'):
|
||||||
context['student_list'] = Student.objects.filter(
|
context['student_list'] = Student.objects.filter(
|
||||||
department=self.request.user.instructor.department
|
department=self.request.user.instructor.department
|
||||||
@ -36,18 +36,18 @@ class AttendanceOverview(LoginRequiredMixin, TemplateView):
|
|||||||
elif hasattr(self.request.user, 'student'):
|
elif hasattr(self.request.user, 'student'):
|
||||||
student = self.request.user.student
|
student = self.request.user.student
|
||||||
# sum all duration fields for student
|
# sum all duration fields for student
|
||||||
periods_duration_sum = Period.objects.filter(
|
context['period_total'] = Period.objects.filter(
|
||||||
student = student
|
student = student
|
||||||
).filter(
|
).filter(
|
||||||
clocked_in__year=timezone.now().year
|
clocked_in__year=timezone.now().year
|
||||||
).filter(
|
).filter(
|
||||||
clocked_in__month=timezone.now().month
|
clocked_in__month=timezone.now().month
|
||||||
).aggregate(total_duration=Sum('duration'))
|
).aggregate(total=Sum('duration'))
|
||||||
|
|
||||||
hours = 0
|
# hours = 0
|
||||||
# Convert to hours floating point
|
# # Convert to hours floating point
|
||||||
if periods_duration_sum['total_duration'] != None:
|
# if periods_duration_sum['total_duration'] != None:
|
||||||
hours = round((periods_duration_sum['total_duration'].total_seconds() / 3600), 2)
|
# hours = round((periods_duration_sum['total_duration'].total_seconds() / 3600), 2)
|
||||||
|
|
||||||
context['period_list'] = Period.objects.filter(
|
context['period_list'] = Period.objects.filter(
|
||||||
student=student
|
student=student
|
||||||
@ -56,7 +56,6 @@ class AttendanceOverview(LoginRequiredMixin, TemplateView):
|
|||||||
).filter(
|
).filter(
|
||||||
clocked_in__month=timezone.now().month
|
clocked_in__month=timezone.now().month
|
||||||
).order_by('-clocked_in')
|
).order_by('-clocked_in')
|
||||||
context['period_total'] = hours
|
|
||||||
if student.current_period_id != None:
|
if student.current_period_id != None:
|
||||||
context['current_period'] = Period.objects.get(pk=student.current_period_id)
|
context['current_period'] = Period.objects.get(pk=student.current_period_id)
|
||||||
return context
|
return context
|
||||||
@ -141,7 +140,7 @@ class CodeDetailView(LoginRequiredMixin, DetailView):
|
|||||||
class CodeUpdateView(LoginRequiredMixin, UpdateView):
|
class CodeUpdateView(LoginRequiredMixin, UpdateView):
|
||||||
model = Code
|
model = Code
|
||||||
fields = ['station_number']
|
fields = ['station_number']
|
||||||
template_name = 'attendance/code_update_form.html'
|
template_name = 'attendance/code_form.html'
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
pk = self.kwargs["pk"]
|
pk = self.kwargs["pk"]
|
||||||
|
|||||||
0
static/scss/_attendance.scss
Normal file
0
static/scss/_attendance.scss
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
.code-detail {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&__instructions {
|
||||||
|
|
||||||
|
}
|
||||||
|
&__qrcode {
|
||||||
|
|
||||||
|
}
|
||||||
|
&__done {
|
||||||
|
margin: 1rem 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -51,6 +51,7 @@ input[type=submit],
|
|||||||
color: white;
|
color: white;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
border-radius: 3.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
input:focus,
|
input:focus,
|
||||||
|
|||||||
@ -51,7 +51,7 @@ hr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// BLOCK ELEMENTS
|
// BLOCK ELEMENTS
|
||||||
main {
|
main, aside {
|
||||||
max-width: 58rem;
|
max-width: 58rem;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,14 @@
|
|||||||
|
.instructor {
|
||||||
|
&__active_periods {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
&__attendance_log {
|
||||||
|
margin: 0 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__total_hours {
|
||||||
|
margin: 0 1rem;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
3
static/scss/_messages.scss
Normal file
3
static/scss/_messages.scss
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.messages {
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,9 +1,7 @@
|
|||||||
.student {
|
.student {
|
||||||
|
|
||||||
&__header {
|
&__header {
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: baseline;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__department {
|
&__department {
|
||||||
|
|||||||
@ -3,9 +3,11 @@
|
|||||||
@import "helpers";
|
@import "helpers";
|
||||||
@import "forms";
|
@import "forms";
|
||||||
@import "nav";
|
@import "nav";
|
||||||
|
@import "messages";
|
||||||
@import "registration";
|
@import "registration";
|
||||||
@import "students";
|
@import "students";
|
||||||
@import "instructors";
|
@import "instructors";
|
||||||
|
@import "attendance";
|
||||||
@import "periods";
|
@import "periods";
|
||||||
@import "codes";
|
@import "codes";
|
||||||
|
|
||||||
|
|||||||
@ -32,7 +32,7 @@
|
|||||||
|
|
||||||
<aside>
|
<aside>
|
||||||
{% if messages %}
|
{% if messages %}
|
||||||
<div class="messages">
|
<div class="messages panel">
|
||||||
{% for message in messages %}
|
{% for message in messages %}
|
||||||
<span {% if message.tags %} class="{{ message.tags }} messages__message"{% endif %}>{{ message }}</span>
|
<span {% if message.tags %} class="{{ message.tags }} messages__message"{% endif %}>{{ message }}</span>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user