Add basic public dashboard
This commit is contained in:
parent
2f9adbb11c
commit
4fb345b3bb
|
@ -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
|
||||||
|
|
|
@ -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 %}
|
|
@ -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 – 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 %}
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -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'))
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue