2
0
Fork 0

Add basic public dashboard

This commit is contained in:
Luca 2023-05-16 03:29:05 +02:00
parent 2f9adbb11c
commit 4fb345b3bb
7 changed files with 129 additions and 46 deletions

View File

@ -24,14 +24,17 @@ phonenumbers==8.12.47
prompt-toolkit==3.0.29 prompt-toolkit==3.0.29
psycopg2-binary==2.9.3 psycopg2-binary==2.9.3
pyparsing==3.0.8 pyparsing==3.0.8
pypng==0.20220715.0
python-dateutil==2.8.2 python-dateutil==2.8.2
pytz==2022.1 pytz==2022.1
qrcode==7.4.2
redis==4.2.2 redis==4.2.2
requests==2.27.1 requests==2.27.1
sentry-sdk==1.5.10 sentry-sdk==1.5.10
six==1.16.0 six==1.16.0
soupsieve==2.4.1 soupsieve==2.4.1
sqlparse==0.4.2 sqlparse==0.4.2
typing_extensions==4.5.0
urllib3==1.26.9 urllib3==1.26.9
vine==5.0.0 vine==5.0.0
wcwidth==0.2.5 wcwidth==0.2.5

View File

@ -0,0 +1,44 @@
{% extends "base.html" %}
{% block head %}
<script>
window.addEventListener('load', () => {
const max = document.body.scrollHeight - window.innerHeight;
let current = 0;
let interval;
let interacted = false;
window.addEventListener('click', () => interacted = true);
window.addEventListener('touchstart', () => interacted = true);
setTimeout(() => {
window.scrollTo({top: 0});
}, 10);
if (max > 0) {
setTimeout(() => {
if (interacted) return;
interval = setInterval(() => {
if (interacted) return;
current += 1;
window.scrollTo({top: current});
if (window.scrollY >= max) {
if (interacted) return;
clearInterval(interval);
setTimeout(() => {
window.location.reload();
}, 5000)
}
}, 20);
}, 5000)
}
setTimeout(() => {
if (interacted) return;
window.location.reload();
}, 120 * 1000)
});
</script>
{% endblock %}

View File

@ -1,4 +1,50 @@
{% extends "base.html" %} {% extends "autoscroll.html" %}
{% load qrcode %}
{% block everything %} {% block everything %}
<section class="hero">
<div class="hero-body">
<div class="container has-text-centered">
<h2 class="title is-2">kontakt &ndash; das Kulturfestival</h2>
<h1 class="title is-1">sucht dich!</h1>
<h3 class="title">Schnapp dir deine Helfer*innenschicht auf https://helfen.kntkt.de</h3>
</div>
</div>
</section>
<section class="hero is-link is-small">
<div class="hero-body">
<div class="container">
<div class="level">
{% for description, value in facts %}
<div class="level-item has-text-centered">
<div>
<p class="heading">{{ description }}</p>
<p class="title">{{ value }}</p>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
</section>
<section class="section">
<div class="container">
<h3 class="title">Nächste freie Schichten</h3>
<div class="columns">
{% for shift in next_free_shifts %}
<div class="column has-text-centered is-quarter">
<div class="box">
<div class="content">
<p class="is-size-4">{{ shift.start_at }}</p>
{% url 'shift' shift.pk as shift_url %}
{% qrcode "https://helfen.kntkt.de"|add:shift_url %}
<p class="is-size-4 mt-4">{{ shift.room.name }}</p>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
</section>
{% endblock %} {% endblock %}

View File

@ -1,47 +1,4 @@
{% extends "base.html" %} {% extends "autoscroll.html" %}
{% block head %}
<script>
window.addEventListener('load', () => {
const max = document.body.scrollHeight - window.innerHeight;
let current = 0;
let interval;
let interacted = false;
window.addEventListener('click', () => interacted = true);
window.addEventListener('touchstart', () => interacted = true);
setTimeout(() => {
window.scrollTo({top: 0});
}, 10);
if (max > 0) {
setTimeout(() => {
if (interacted) return;
interval = setInterval(() => {
if (interacted) return;
current += 1;
window.scrollTo({top: current});
if (window.scrollY >= max) {
if (interacted) return;
clearInterval(interval);
setTimeout(() => {
window.location.reload();
}, 5000)
}
}, 20);
}, 5000)
}
setTimeout(() => {
if (interacted) return;
window.location.reload();
}, 120 * 1000)
});
</script>
{% endblock %}
{% block body %} {% block body %}
<section class="section"> <section class="section">

View File

@ -0,0 +1,10 @@
from django import template
from django.utils.safestring import mark_safe
from qrcode import make
from qrcode.image.svg import SvgPathFillImage
register = template.Library()
@register.simple_tag
def qrcode(data):
return mark_safe(make(data, image_factory=SvgPathFillImage).to_string().decode('utf-8'))

View File

@ -1,4 +1,27 @@
from django.db.models import F, Q, Sum
from django.shortcuts import render from django.shortcuts import render
from django.utils import timezone
from .models import Helper, Shift, ShiftRegistration
def public_dashboard(request): def public_dashboard(request):
return render(request, "public_dashboard.html", {}) facts = []
num_helpers = Helper.objects.count()
if num_helpers > 0:
facts.append(("Registrierte Helfer*innen", num_helpers))
help_wanted = Q(required_helpers__gt=F("reg_count")) | Q(required_helpers=0) & Q(room__required_helpers__gt=F("reg_count"))
total_work_duration = ShiftRegistration.objects.filter(state=ShiftRegistration.RegState.CHECKED_IN).aggregate(sum=Sum("shift__duration"))["sum"]
if total_work_duration:
total_work_duration = round(total_work_duration.total_seconds() / 60.0)
facts.append(("Geleistete Personenstunden", f"{total_work_duration//60}h {total_work_duration%60}min"))
num_free_shifts = Shift.with_reg_count().filter(help_wanted, deleted=False, start_at__gte=timezone.now()).count()
if num_free_shifts > 0:
facts.append(("Zu übernehmende Schichten", num_free_shifts))
next_free_shifts = Shift.with_reg_count().filter(help_wanted, start_at__gt=timezone.now(), deleted=False).order_by("start_at")[:4]
context = {"facts": facts, "next_free_shifts": next_free_shifts}
return render(request, "public_dashboard.html", context)