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)
|
||||
modified = models.DateTimeField(auto_now=True)
|
||||
|
||||
# def duration(self):
|
||||
# duration = self.clocked_out - self.clocked_in
|
||||
# duration_in_s = duration.total_seconds()
|
||||
# return divmod(duration_in_s, 3600)[0]
|
||||
@property
|
||||
def p_duration(self):
|
||||
return round((self.clocked_out - self.clocked_in).seconds / 3600, 2)
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('period-detail', kwargs={'pk': self.pk})
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
{% extends 'application.html' %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Scan code to clock-in/out</h1>
|
||||
|
||||
<section>
|
||||
<form method="post" action="{% url 'attendance-update' %}">
|
||||
<section class="clockin panel">
|
||||
<h1>Scan code to clock-in/out</h1>
|
||||
<form class="clockin__form" method="post" action="{% url 'attendance-update' %}">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
<section>
|
||||
<header>
|
||||
<h1>{{ user.instructor.department.name }}</h1>
|
||||
{% load timedelta_filter %}
|
||||
<article class="instructor">
|
||||
<section class="instructor__header panel">
|
||||
<h1 class="instructor__department">{{ user.instructor.department.name }}</h1>
|
||||
<p>
|
||||
<a href="">Generate Reports</a>
|
||||
<a class="instructor__generate-reports" href="">Generate Reports</a>
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<h3>Active sessions</h3>
|
||||
<div class="instructor__active_periods">
|
||||
<h3>Students clocked-in</h3>
|
||||
<p>
|
||||
<a class="action-button" href="{% url 'period-create' %}">+ Add new session</a>
|
||||
</p>
|
||||
@ -40,8 +41,9 @@
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
<article>
|
||||
</div>
|
||||
</section>
|
||||
<section class="instructor__attendance_log">
|
||||
<div>
|
||||
<h3>Attendance log</h3>
|
||||
<table>
|
||||
@ -76,8 +78,8 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</article>
|
||||
<article>
|
||||
</section>
|
||||
<section class="instructor__total_hours">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
@ -89,11 +91,12 @@
|
||||
{% for student in student_list %}
|
||||
<tr>
|
||||
<td>{{ student.user.first_name }} {{ student.user.last_name }}</td>
|
||||
<td>{{ student.total_hours }}</td>
|
||||
<td>{{ student.total_hours|dimedelta_format }}</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr><td colspan="2">No periods yet.</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
</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>
|
||||
{% if user.student.is_clocked_in %}
|
||||
<div class="student__statusbar status">
|
||||
<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>
|
||||
Current sesson: <strong>{{ current_period.clocked_in|timesince }}</strong>
|
||||
</p>
|
||||
@ -13,10 +15,11 @@
|
||||
<div class="status__clocked"></div>You are not clocked in.</p>
|
||||
{% include 'attendance/_student_code.html' with clocked_in=False %}
|
||||
{% endif %}
|
||||
</section>
|
||||
<section class="attendance">
|
||||
</section>
|
||||
<section class="student__attendance attendance">
|
||||
<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>
|
||||
{% include 'attendance/_student_periods.html' %}
|
||||
</section>
|
||||
</section>
|
||||
</article>
|
||||
|
||||
@ -2,11 +2,10 @@
|
||||
{% load qr_code %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Clock in</h1>
|
||||
|
||||
<section class="code_detail">
|
||||
<p><em>Scan code at clock-in station</em></p>
|
||||
<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 class="code-detail panel">
|
||||
<h1>Clock in</h1>
|
||||
<p class="code-detail__instructions"><em>Scan code at clock-in station</em></p>
|
||||
<span class="code-detail__qrcode">{% qr_from_text code.qr_code_str size=24 version=2 %}</span>
|
||||
<span class="code-detail__done"><a class="action-button" href="{% url 'attendance-overview' %}">Done</a></span>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
{% extends 'application.html' %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Generate code</h1>
|
||||
|
||||
<section>
|
||||
<form method="post" action="{% url 'code-create' %}">
|
||||
<section class="code-update panel">
|
||||
<h1>Generate code</h1>
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{{ 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):
|
||||
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'):
|
||||
context['student_list'] = Student.objects.filter(
|
||||
department=self.request.user.instructor.department
|
||||
@ -36,18 +36,18 @@ class AttendanceOverview(LoginRequiredMixin, TemplateView):
|
||||
elif hasattr(self.request.user, 'student'):
|
||||
student = self.request.user.student
|
||||
# sum all duration fields for student
|
||||
periods_duration_sum = Period.objects.filter(
|
||||
context['period_total'] = Period.objects.filter(
|
||||
student = student
|
||||
).filter(
|
||||
clocked_in__year=timezone.now().year
|
||||
).filter(
|
||||
clocked_in__month=timezone.now().month
|
||||
).aggregate(total_duration=Sum('duration'))
|
||||
).aggregate(total=Sum('duration'))
|
||||
|
||||
hours = 0
|
||||
# Convert to hours floating point
|
||||
if periods_duration_sum['total_duration'] != None:
|
||||
hours = round((periods_duration_sum['total_duration'].total_seconds() / 3600), 2)
|
||||
# hours = 0
|
||||
# # Convert to hours floating point
|
||||
# if periods_duration_sum['total_duration'] != None:
|
||||
# hours = round((periods_duration_sum['total_duration'].total_seconds() / 3600), 2)
|
||||
|
||||
context['period_list'] = Period.objects.filter(
|
||||
student=student
|
||||
@ -56,7 +56,6 @@ class AttendanceOverview(LoginRequiredMixin, TemplateView):
|
||||
).filter(
|
||||
clocked_in__month=timezone.now().month
|
||||
).order_by('-clocked_in')
|
||||
context['period_total'] = hours
|
||||
if student.current_period_id != None:
|
||||
context['current_period'] = Period.objects.get(pk=student.current_period_id)
|
||||
return context
|
||||
@ -141,7 +140,7 @@ class CodeDetailView(LoginRequiredMixin, DetailView):
|
||||
class CodeUpdateView(LoginRequiredMixin, UpdateView):
|
||||
model = Code
|
||||
fields = ['station_number']
|
||||
template_name = 'attendance/code_update_form.html'
|
||||
template_name = 'attendance/code_form.html'
|
||||
|
||||
def get_success_url(self):
|
||||
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;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
border-radius: 3.75rem;
|
||||
}
|
||||
|
||||
input:focus,
|
||||
|
||||
@ -51,7 +51,7 @@ hr {
|
||||
}
|
||||
|
||||
// BLOCK ELEMENTS
|
||||
main {
|
||||
main, aside {
|
||||
max-width: 58rem;
|
||||
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 {
|
||||
|
||||
&__header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: baseline;
|
||||
|
||||
}
|
||||
|
||||
&__department {
|
||||
|
||||
@ -3,9 +3,11 @@
|
||||
@import "helpers";
|
||||
@import "forms";
|
||||
@import "nav";
|
||||
@import "messages";
|
||||
@import "registration";
|
||||
@import "students";
|
||||
@import "instructors";
|
||||
@import "attendance";
|
||||
@import "periods";
|
||||
@import "codes";
|
||||
|
||||
|
||||
@ -32,7 +32,7 @@
|
||||
|
||||
<aside>
|
||||
{% if messages %}
|
||||
<div class="messages">
|
||||
<div class="messages panel">
|
||||
{% for message in messages %}
|
||||
<span {% if message.tags %} class="{{ message.tags }} messages__message"{% endif %}>{{ message }}</span>
|
||||
{% endfor %}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user