From a0bcf3c0462be03b6bcf33f434c4290a99be296a Mon Sep 17 00:00:00 2001 From: Andrea Date: Sun, 19 May 2024 00:06:36 +0200 Subject: [PATCH] wip - UI Update + Client model management + wip new software requirement in the backend matching algorithm --- admin.py | 16 ++++++- res/scripts/roomManager.js | 24 ---------- res/scripts/wizardManager.js | 58 +++++++++++++++++++---- res/styles/wizard.css | 43 +++++++++++++++-- tpl/nosecount.html | 23 +-------- tpl/wizard.html | 90 +++++++++++++++++++++++------------- 6 files changed, 159 insertions(+), 95 deletions(-) diff --git a/admin.py b/admin.py index 248d6cd..cdd9c42 100644 --- a/admin.py +++ b/admin.py @@ -8,6 +8,8 @@ from io import StringIO from sanic.log import logger import csv import time +import json +import math bp = Blueprint("admin", url_prefix="/manage/admin") @@ -108,7 +110,7 @@ async def room_wizard(request, order:Order): await clear_cache(request, order) #Separate orders which have incomplete rooms and which have no rooms - all_orders = {key:value for key,value in sorted(request.app.ctx.om.cache.items(), key=lambda x: len(x[1].room_members), reverse=True) if value.status not in ['c', 'e']} + all_orders = {key:value for key,value in sorted(request.app.ctx.om.cache.items(), key=lambda x: len(x[1].room_members), reverse=True) if value.status not in ['c', 'e'] and not value.daily} orders = {key:value for key,value in sorted(all_orders.items(), key=lambda x: x[1].ans('fursona_name')) if not value.room_confirmed} # Orders with incomplete rooms incomplete_orders = {key:value for key,value in orders.items() if value.code == value.room_id and (value.room_person_no - len(value.room_members)) > 0} @@ -131,6 +133,15 @@ async def room_wizard(request, order:Order): result_map = {} + # Get room quotas + room_quota_map = {} + for key, value in ITEM_VARIATIONS_MAP['bed_in_room'].items(): + capacity = ROOM_CAPACITY_MAP[key] if key in ROOM_CAPACITY_MAP else 1 + room_quota_map[value] = math.ceil((len(list(filter(lambda y: y.bed_in_room == value, orders.values())))) / capacity) + + print('RMQ = ') + print(room_quota_map) + # Fill already existing rooms for room_order in incomplete_orders.items(): room = room_order[1] @@ -185,8 +196,9 @@ async def room_wizard(request, order:Order): 'to_add': to_add } + result_map["infinite"] = { 'to_add': [] } tpl = request.app.ctx.tpl.get_template('wizard.html') - return html(tpl.render(order=order, all_orders=all_orders, unconfirmed_orders=orders, data=result_map)) + return html(tpl.render(order=order, all_orders=all_orders, unconfirmed_orders=orders, data=result_map, jsondata=json.dumps(result_map, skipkeys=True, ensure_ascii=False))) @bp.get('/propic/remind') async def propic_remind_missing(request, order:Order): diff --git a/res/scripts/roomManager.js b/res/scripts/roomManager.js index 67ed197..a2ff674 100644 --- a/res/scripts/roomManager.js +++ b/res/scripts/roomManager.js @@ -28,28 +28,4 @@ function confirmAction (intent, sender) { break } document.getElementById('modalOrderEditDialog').setAttribute('open', 'true'); -} - -function setLoading (){ - document.getElementById('loadingIndicator').style.visibility = 'unset'; -} - -function setLoaded (){ - document.getElementById('loadingIndicator').style.visibility = 'hidden'; -} - -async function roomGuestEditAction (intent, sender) { - if (['new', 'fromOrder'].includes (intent) == false) return - setLoaded (); - document.getElementById('roomGuestEditorDialog').setAttribute('open', 'true'); -} - -async function retrieveUsers (type) { - setLoading(); - - setLoaded(); -} - -function adaptRoomFormat (){ - } \ No newline at end of file diff --git a/res/scripts/wizardManager.js b/res/scripts/wizardManager.js index ba0187f..a3396b2 100644 --- a/res/scripts/wizardManager.js +++ b/res/scripts/wizardManager.js @@ -82,15 +82,22 @@ function drop(e) { let item = document.getElementById (data.id) let oldParent = document.getElementById (data.parentRoomId) let newParent = e.target; - let newParentContainer = newParent.querySelector('div.grid.people') - newParentContainer.appendChild (item); - oldParent.setAttribute("current-size", parseInt(oldParent.getAttribute("current-size") - 1)) - newParent.setAttribute("current-size", parseInt(newParent.getAttribute("current-size") + 1)) + if (moveToRoom (data.id, data.parentRoomId.replace('room-',''), newParent.id.replace('room-','')) === true) { + let newParentContainer = newParent.querySelector('div.grid.people') + newParentContainer.appendChild (item); + let oldParentQty = parseInt(oldParent.getAttribute("current-size")) - 1; + let newParentQty = parseInt(newParent.getAttribute("current-size")) + 1; + let newParentCapacity = parseInt(newParent.getAttribute("room-size")); + oldParent.setAttribute("current-size", oldParentQty); + newParent.setAttribute("current-size", newParentQty); + oldParent.classList.remove('complete'); + if (newParentCapacity == newParentQty) newParent.classList.add('complete'); + } } } function toggleRoomSelection(newStatus) { - rooms = document.querySelectorAll("main.container>div.room"); + rooms = document.querySelectorAll("div.room"); Array.from(rooms).forEach(room=>{ room.classList.toggle('interactless', newStatus); room.classList.remove('drag-over'); @@ -104,12 +111,45 @@ function setData (id, roomType, parentRoomId) { draggingData.parentRoomId = parentRoomId; } -function resetData (){ - setData(0, 0, 0); +function resetData (){ setData(0, 0, 0); } + +function getData () { return draggingData; } + +// This default onbeforeunload event +window.onbeforeunload = function(){ + return "Any changes to the rooms will be discarded." } -function getData () { - return draggingData; +/* Model managing */ + +var model = saveData; + +const toAdd = "to_add"; + +function moveToRoom (order, from, to){ + if (!model) { console.error("Model is null", order, from, to); return false; } + if (!model[from]) { console.error("Parent is null", order, from, to); return false; } + if (!model[to]) { console.error("Destination is null", order, from, to); return false; } + if (!model[from][toAdd] || !model[from][toAdd].includes(order)) { console.error("Order is not in parent", order, from, to); return false; } + if (!model[to][toAdd]) model[to][toAdd] = []; + // Delete order from the original room + model[from][toAdd] = model[from][toAdd].filter (itm=> itm !== order) + // Add it to the destination room + model[to][toAdd].push (order); + return true; +} + +function onSave (){ + if (model['infinite'] && model['infinite'][toAdd] && model['infinite'][toAdd].length > 0) { + setTimeout(()=>{ + let roomItem = document.querySelector("#room-infinite"); + roomItem.scrollIntoView(); + roomItem.classList.add('drag-forbidden'); + setTimeout(()=>roomItem.classList.remove('drag-forbidden'), 3000); + }, 100); + } else { + document.getElementById('modalConfirmDialog').setAttribute('open', 'true'); + } } initObjects (); \ No newline at end of file diff --git a/res/styles/wizard.css b/res/styles/wizard.css index f0e5d98..318166e 100644 --- a/res/styles/wizard.css +++ b/res/styles/wizard.css @@ -10,30 +10,63 @@ div.grid.people div.edit-drag>div.propic-container { } div.drag-over { - border-radius: 1rem; - border: 0.2rem dashed #000; + border-color: #000; + border-style: dashed; } div.drag-forbidden { border-color: #c92121aa; } -div.interactless>*{ +div.interactless > * { pointer-events: none; } +div.room.complete { + border-color: #21c929aa; + border-style: solid; +} + +div.room { + border-radius: var(--border-radius); + border: 1px solid transparent; + margin-bottom: var(--spacing); +} + div.room > h4 { user-select: none; + margin-left: 1.6rem; +} + +div.room:nth-child(2n) { + background-color: #ffffff55; +} + +div.room:nth-child(2n) { + background-color: #cccccc55; +} + +.align-right { + float: right; } /* Dark theme */ @media only screen and (prefers-color-scheme: dark) { div.drag-over { - border-radius: 1rem; - border: 0.2rem dashed #fff; + border-color: #fff; + border-style: dashed; } div.drag-forbidden { border-color: #c92121aa; } + + div.room { + background-color: #16161655; + } + + div.room:nth-child(2n) { + background-color: #20202055; + } + } \ No newline at end of file diff --git a/tpl/nosecount.html b/tpl/nosecount.html index 7104f02..5aa9008 100644 --- a/tpl/nosecount.html +++ b/tpl/nosecount.html @@ -19,15 +19,8 @@ - - {% if order and order.isAdmin() %} -
- New room -
- - {% else %} +

Welcome to the nosecount page! Here you can see all of the available rooms at the convention, as well as the occupants currently staying in each room. Use this page to find your friends and plan your meet-ups.

- {% endif %} {% if filtered and order %} {% for person in filtered.values() %} @@ -56,7 +49,6 @@ {{o.room_name}} {% if order and order.isAdmin() %}
- Add members Rename Unconfirm Delete @@ -160,18 +152,5 @@ - -
- -
- -

Room editor

-
- -
- -
-
- {% endblock %} diff --git a/tpl/wizard.html b/tpl/wizard.html index 26db1e5..206ace7 100644 --- a/tpl/wizard.html +++ b/tpl/wizard.html @@ -19,44 +19,68 @@

Review rooms


{% for room in data.items() %} - {%with room_order = unconfirmed_orders[room[0]] %} -
-

- {{room_order.room_name if room_order.room_name else room[1]['room_name'] if room[1] and room[1]['room_name'] else ''}} -

-
- {% for m in room_order.room_members %} - {% if m in all_orders %} - {% with person = all_orders[m] %} -
- {% with current=None, order=person, imgSrc='/res/propic/' + (person.ans('propic') or 'default.png'), effects = false, flag = true %} - {% include 'blocks/propic.html' %} - {% endwith %} -
{{person.ans('fursona_name')}}
-
- {% endwith %} - {% endif %} - {% endfor %} - {% for m in room[1]['to_add'] %} - {% if m in unconfirmed_orders %} - {% with person = unconfirmed_orders[m] %} -
- {% with current=None, order=person, imgSrc='/res/propic/' + (person.ans('propic') or 'default.png'), effects = false, flag = true %} - {% include 'blocks/propic.html' %} - {% endwith %} -
{{person.ans('fursona_name')}}
-
- {% endwith %} - {% endif %} - {% endfor %} + {% if room[0] in all_orders %} + {%with room_order = unconfirmed_orders[room[0]] %} +
+

+ {{room_order.room_name if room_order.room_name else room[1]['room_name'] if room[1] and room[1]['room_name'] else ''}} +

+
+ {% for m in room_order.room_members %} + {% if m in all_orders %} + {% with person = all_orders[m] %} +
+ {% with current=None, order=person, imgSrc='/res/propic/' + (person.ans('propic') or 'default.png'), effects = false, flag = true %} + {% include 'blocks/propic.html' %} + {% endwith %} +
{{person.ans('fursona_name')}}
+
+ {% endwith %} + {% endif %} + {% endfor %} + {% for m in room[1]['to_add'] %} + {% if m in unconfirmed_orders %} + {% with person = unconfirmed_orders[m] %} +
+ {% with current=None, order=person, imgSrc='/res/propic/' + (person.ans('propic') or 'default.png'), effects = false, flag = true %} + {% include 'blocks/propic.html' %} + {% endwith %} +
{{person.ans('fursona_name')}}
+
+ {% endwith %} + {% endif %} + {% endfor %} +
-
- {% endwith %} + {% endwith %} + {% endif %} {% endfor %}
-

Empty room

+

Empty room ?

+
This is a placeholder room. Place users temporarily in order to free space and arrange rooms
+ Undo + Confirm changes + + +
+ +

Confirm arrangement?

+

+ Roomless guests will be moved around existing rooms and newly generated ones.
+ This will also confirm all rooms. +

+
+ +
+
+
+ + + {% endblock %}