|
@@ -1,5 +1,6 @@
|
|
|
import datetime
|
|
|
from django.utils.translation import gettext as _
|
|
|
+from django.utils.html import escape
|
|
|
|
|
|
from .models import Participant, Date, Event
|
|
|
|
|
@@ -38,18 +39,10 @@ def get_slot_count( event ) -> int :
|
|
|
slots_per_day = int(timespan.total_seconds() // event.slot_interval.total_seconds())
|
|
|
return days * slots_per_day
|
|
|
|
|
|
-def slots2grid( event : Event, participants : list[Participant]) -> dict :
|
|
|
+def slots2grid( event : Event, participants : list[Participant], is_input : bool) -> dict :
|
|
|
""" Convert the slots of an event to data for the grid. """
|
|
|
-
|
|
|
# Get the number of slots in the event
|
|
|
n_slots = get_slot_count(event)
|
|
|
-
|
|
|
- data = {
|
|
|
- 'rows': [],
|
|
|
- 'days': [],
|
|
|
- 'colors': [],
|
|
|
- 'n_days': event.date_set.count(),
|
|
|
- }
|
|
|
# Get the timespan of the event
|
|
|
start_time = datetime.datetime.combine(datetime.date.today(), event.start_time)
|
|
|
end_time = datetime.datetime.combine(datetime.date.today(), event.end_time)
|
|
@@ -62,57 +55,72 @@ def slots2grid( event : Event, participants : list[Participant]) -> dict :
|
|
|
|
|
|
# Get the slots of each day
|
|
|
participant_slot_strings = [slots2string(participant, n_slots) for participant in participants]
|
|
|
- max_occupancy = 1
|
|
|
-
|
|
|
- for n, date in enumerate(event.date_set.all()):
|
|
|
- # Get participants for each slot
|
|
|
- slot_participants = [[] for i in range(slots_per_day)]
|
|
|
- for i, participant in enumerate(participants):
|
|
|
+ if is_input:
|
|
|
+ html = []
|
|
|
+ for n, date in reversed(list(enumerate(event.date_set.all()))):
|
|
|
+ day_offset = n * slots_per_day
|
|
|
+ dt = datetime.datetime.combine(date.date, datetime.time())
|
|
|
+ html += f'<div class="slot-column"><div class="day">{ dt.strftime("%b %d") }</div>'
|
|
|
+ slots = []
|
|
|
+
|
|
|
+ # Fill the slots of the day
|
|
|
+ for j in range(slots_per_day):
|
|
|
+ slot_begin = (start_time + j * event.slot_interval).strftime('%H:%M')
|
|
|
+ slot_end = (start_time + (j+1) * event.slot_interval).strftime('%H:%M')
|
|
|
+ current_time = start_time + j * event.slot_interval
|
|
|
+ if current_time.minute == 0:
|
|
|
+ time_label = f'<div class=\"time-label\">{current_time.strftime("%H:%M")}</div>'
|
|
|
+ classes = " full-hour"
|
|
|
+ elif current_time.minute == 30:
|
|
|
+ time_label = ""
|
|
|
+ classes = " half-hour"
|
|
|
+ else:
|
|
|
+ time_label = ""
|
|
|
+ classes = ""
|
|
|
+ checked = ""
|
|
|
+ for i in range(len(participant_slot_strings)):
|
|
|
+ if participant_slot_strings[i][day_offset + j] == '1':
|
|
|
+ checked = 'checked'
|
|
|
+ break
|
|
|
+
|
|
|
+ slots.append(
|
|
|
+ f'<div class="slot{classes}" title="{slot_begin} - {slot_end}">{ time_label }<input class="checkable" type="checkbox" id="slot_picker_{ day_offset + j }" name="slot_{day_offset + j}" { checked } /><label class="checkable" for="slot_picker_{day_offset + j}"></label></div>')
|
|
|
+ html.append(''.join(slots))
|
|
|
+ html.append('</div>')
|
|
|
+ return "".join(html)
|
|
|
+ else:
|
|
|
+ max_occupancy = 1
|
|
|
+ html = []
|
|
|
+ for n, date in reversed(list(enumerate(event.date_set.all()))):
|
|
|
+ day_offset = n * slots_per_day
|
|
|
+ dt = datetime.datetime.combine(date.date, datetime.time())
|
|
|
+ html.append(f'<div class="slot-column"><div class="day">{ dt.strftime("%b %d") }</div>')
|
|
|
+ slots = []
|
|
|
+ # Get participants for each slot
|
|
|
+ slot_participants = [[] for i in range(slots_per_day)]
|
|
|
for j in range(slots_per_day):
|
|
|
- if participant_slot_strings[i][n*slots_per_day + j] == '1':
|
|
|
- slot_participants[j].append(participant)
|
|
|
- # Fill the slots of the day
|
|
|
- slots = []
|
|
|
- last_hour = None
|
|
|
- last_half_hour = None
|
|
|
- for j, ps in enumerate(slot_participants):
|
|
|
- slot_begin = (start_time + j * event.slot_interval).strftime('%H:%M')
|
|
|
- slot_end = (start_time + (j+1) * event.slot_interval).strftime('%H:%M')
|
|
|
- current_time = start_time + j * event.slot_interval
|
|
|
- slots.append({
|
|
|
- 'tooltip': f"{slot_begin} - {slot_end} \n{', '.join([p.user.username for p in ps])}",
|
|
|
- 'offset': n*slots_per_day + j,
|
|
|
- 'date': date.date,
|
|
|
- 'time': current_time,
|
|
|
- 'color': len(ps),
|
|
|
- 'checked': 'checked="checked"' if len(ps) > 0 else '',
|
|
|
- 'is_full_hour': current_time.hour != last_hour,
|
|
|
- 'is_half_hour': current_time.minute // 30 != last_half_hour,
|
|
|
- })
|
|
|
- max_occupancy = max(max_occupancy, len(ps))
|
|
|
- last_hour = current_time.hour
|
|
|
- last_half_hour = current_time.minute // 30
|
|
|
-
|
|
|
- day = {
|
|
|
- 'date': date.date,
|
|
|
- 'slots': slots,
|
|
|
- }
|
|
|
- data['days'].append(day)
|
|
|
- data['days'] = reversed(data['days'])
|
|
|
- # Fill the rows of the grid
|
|
|
- last_hour = None
|
|
|
- for i in range(slots_per_day):
|
|
|
- current_time = start_time + i * event.slot_interval
|
|
|
- data['rows'].append({
|
|
|
- 'time': current_time,
|
|
|
- 'is_full_hour': current_time.hour != last_hour,
|
|
|
- })
|
|
|
- last_hour = current_time.hour
|
|
|
-
|
|
|
- data['rows'].append({
|
|
|
- 'time': end_time,
|
|
|
- 'is_full_hour': True,
|
|
|
- })
|
|
|
-
|
|
|
- data['colors'] = max_occupancy
|
|
|
- return data
|
|
|
+ for i in range(len(participant_slot_strings)):
|
|
|
+ if participant_slot_strings[i][day_offset + j] == '1':
|
|
|
+ slot_participants[j].append(i)
|
|
|
+
|
|
|
+ # Fill the slots of the day
|
|
|
+ for j, ps in enumerate(slot_participants):
|
|
|
+ slot_begin = (start_time + j * event.slot_interval).strftime('%H:%M')
|
|
|
+ slot_end = (start_time + (j+1) * event.slot_interval).strftime('%H:%M')
|
|
|
+ current_time = start_time + j * event.slot_interval
|
|
|
+ if current_time.minute == 0:
|
|
|
+ time_label = f'<div class=\"time-label\">{current_time.strftime("%H:%M")}</div>'
|
|
|
+ classes = " full-hour"
|
|
|
+ elif current_time.minute == 30:
|
|
|
+ time_label = ""
|
|
|
+ classes = " half-hour"
|
|
|
+ else:
|
|
|
+ time_label = ""
|
|
|
+ classes = ""
|
|
|
+
|
|
|
+ slots.append(
|
|
|
+ f'<div class="slot{classes}" id="grid_slot_{ day_offset + j }" title="{slot_begin} - {slot_end} \n{escape(", ".join([participants[p].user.username for p in ps]))}" style="--color-index:{ len(ps) }">{ time_label }</div>')
|
|
|
+ max_occupancy = max(max_occupancy, len(ps))
|
|
|
+ html.append(''.join(slots))
|
|
|
+ html.append('</div>')
|
|
|
+ return f'<div class="occupancy-grid" style="--color-count:{ max_occupancy }">{"".join(html)}</div>'
|