Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

event registration history #3251

Open
wants to merge 1 commit into
base: fixtures
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions apps/events/dashboard/views.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import json
from collections import OrderedDict
from datetime import datetime, time, timedelta

from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.contrib.contenttypes.models import ContentType
from django.core import serializers
from django.core.exceptions import PermissionDenied
from django.forms.models import modelformset_factory
from django.http import HttpResponse, JsonResponse
Expand All @@ -29,6 +31,7 @@
Attendee,
CompanyEvent,
Event,
EventUserAction,
Reservation,
Reservee,
)
Expand Down Expand Up @@ -324,6 +327,16 @@
context["active_tab"] = active_tab
context["form"] = dashboard_forms.CreateEventForm(instance=event, user=request.user)

# History of event for analytics pane
registration_history = EventUserAction.objects.filter(event=event)
print(registration_history)
context["registration_history"] = registration_history
context["registration_history_json"] = json.dumps(

Check warning on line 334 in apps/events/dashboard/views.py

View check run for this annotation

Codecov / codecov/patch

apps/events/dashboard/views.py#L331-L334

Added lines #L331 - L334 were not covered by tests
serializers.serialize("json", registration_history)
)
context["event_registration_start"] = event.attendance_event.registration_start
context["event_registration_end"] = event.attendance_event.registration_end

Check warning on line 338 in apps/events/dashboard/views.py

View check run for this annotation

Codecov / codecov/patch

apps/events/dashboard/views.py#L337-L338

Added lines #L337 - L338 were not covered by tests

extras = {}
if event.is_attendance_event() and event.attendance_event.extras:
for extra in event.attendance_event.extras.all():
Expand Down
26 changes: 13 additions & 13 deletions apps/events/signals.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
# from django.db.models.signals import post_delete, post_save
# from django.dispatch import receiver
from django.db.models.signals import post_delete, post_save
from django.dispatch import receiver

# from .models import Attendee, EventUserAction
from .models import Attendee, EventUserAction


# @receiver(signal=post_save, sender=Attendee)
# def handle_payment_relation_status_change(sender, instance: Attendee, **kwargs):
# EventUserAction.objects.create(
# user=instance.user, event=instance.event.event, type="register"
# )
@receiver(signal=post_save, sender=Attendee)
def handle_attendee_creation(sender, instance: Attendee, **kwargs):
EventUserAction.objects.create(
user=instance.user, event=instance.event.event, type="register"
)


# @receiver(signal=post_delete, sender=Attendee)
# def handle_payment_transaction_status_change(sender, instance: Attendee, **kwargs):
# EventUserAction.objects.create(
# user=instance.user, event=instance.event.event, type="unregister"
# )
@receiver(signal=post_delete, sender=Attendee)
def handle_attendee_deletion(sender, instance: Attendee, **kwargs):
EventUserAction.objects.create(
user=instance.user, event=instance.event.event, type="unregister"
)
6 changes: 6 additions & 0 deletions templates/events/dashboard/details.html
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ <h3>{{ event }}</h3>
<li role="presentation">
<a href="#company" aria-controls="company" role="tab" data-toggle="tab">Bedrifter</a>
</li>
<li role="presentation">
<a href="#registration-history" aria-controls="registration-history" role="tab" data-toggle="tab">Påmeldingshistorikk</a>
</li>
</ul>
</div>
</div>
Expand Down Expand Up @@ -145,6 +148,9 @@ <h4 class="panel-title">
{% include "events/dashboard/details/company.html" %}
<div id="add-company-view"></div>
</div>
<div role="tabpanel" class="tab-pane" id="registration-history">
{% include "events/dashboard/details/registration-history.html" %}
</div>
</div>

{% endblock content %}
Expand Down
127 changes: 127 additions & 0 deletions templates/events/dashboard/details/registration-history.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
<div class="row">
<div class="col-lg-12" style="position: relative; height:40vh; width:80vw">
<canvas id="attendeesChart"></canvas>
</div>
</div>


{% block js %}
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/chart.umd.min.js"></script>
<script>
const registrationHistoryRaw = "{{ registration_history_json|escapejs }}";
const registrationHistory = JSON.parse(JSON.parse(registrationHistoryRaw));

// history type:
/*
[{
"model": "events.eventuseraction",
"pk": 1,
"fields": {
"timestamp": "2024-08-20T13:52:55.391Z",
"type": "register",
"user": 1
}
}, ...]
*/

const eventRegistrationStart = new Date("{{ event_registration_start|safe }}");
const eventRegistrationEnd = new Date("{{ event_registration_end|safe }}");

const daysWithTotal = (raw) => {
const base = [{timestamp: eventRegistrationStart, total: 0}];
const end = new Date(Math.min(new Date(), eventRegistrationEnd));
const days = Math.floor((end - eventRegistrationStart) / (1000 * 60 * 60 * 24));

const daysWithTotal = [];
for (let i = 0; i <= days; i++) {
let totalForDay = 0;
const day = new Date(eventRegistrationStart);
day.setDate(day.getDate() + i);

// set time to 23:59:59
day.setHours(23, 59, 59);

for (let j = 0; j < raw.length; j++) {
const actionDate = new Date(raw[j].fields.timestamp);
if (actionDate <= day) {
totalForDay += raw[j].fields.type === 'register' ? 1 : -1;
}
}

daysWithTotal.push({ timestamp: day, total: totalForDay });
}

return daysWithTotal;
}

const totalRegistrationsPerDay = daysWithTotal(registrationHistory);

// plot total registrations over time using chart.js
const ctx = document.getElementById('attendeesChart').getContext('2d');
const chart = new Chart(ctx, {
type: 'line',
data: {
// extract day from timestamp
labels: totalRegistrationsPerDay.map((action, i) => action.timestamp.toLocaleDateString().split('T')[0]),
datasets: [{
label: 'Registrations',
data: totalRegistrationsPerDay.map(action => action.total),
backgroundColor: 'rgba(54, 162, 235, 0.2)',
borderColor: 'rgba(54, 162, 235, 1)',
borderWidth: 1
}]
},
options: {
// responsive: false,
plugins: {
tooltip: {
callbacks: {
label: function(context) {
const index = context.dataIndex;
const action = totalRegistrationsPerDay[index];
return `Total: ${action.total}, Timestamp: ${action.timestamp.toLocaleString()}`;
}
}
}
}
}
});

// render
chart.render();
</script>
{% endblock %}

<div class="row">
<div class="col-lg-12">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Historikk</h3>
</div>
<div class="panel-body">
<div id="attendees-content">
<table class="table table-striped table-condensed tablesorter attendees" id="attendees-table">
<thead>
<tr>
<th>#</th>
<th>Tidspunkt</th>
<th>Registrert årstall for bruker</th>
<th>Handling</th>
</tr>
</thead>
<tbody id="attendeelist">
{% for registration in registration_history reversed %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ registration.timestamp }}</td>
<td>{{ registration.user.year }}</td>
<td>{{ registration.type }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>