From 41373dfcfa1020d67cb761531bcaf5c13e856957 Mon Sep 17 00:00:00 2001 From: Andrea Date: Thu, 16 May 2024 23:52:09 +0200 Subject: [PATCH] wip5 - Users room re-arrangement + config fix [+] Added the Drag'n'Drop mechanism in the wizard page, allowing to move orders between rooms, plus a 'placeholder' space to temporarily keep orders to move others [minor fix] Item category maps might be filled twice with the same IDs --- admin.py | 11 +++- res/scripts/wizardManager.js | 103 +++++++++++++++++++++++++++++++++++ res/styles/wizard.css | 23 ++++++++ tpl/wizard.html | 48 ++++++++++++++-- utils.py | 2 +- 5 files changed, 178 insertions(+), 9 deletions(-) create mode 100644 res/scripts/wizardManager.js create mode 100644 res/styles/wizard.css diff --git a/admin.py b/admin.py index f23d220..248d6cd 100644 --- a/admin.py +++ b/admin.py @@ -108,8 +108,8 @@ async def room_wizard(request, order:Order): await clear_cache(request, order) #Separate orders which have incomplete rooms and which have no rooms - orders = request.app.ctx.om.cache.items() - orders = {key:value for key,value in sorted(orders, key=lambda x: x[1].ans('fursona_name')) if value.status not in ['c', 'e'] and not value.room_confirmed} + 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']} + 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} # Roomless furs @@ -124,6 +124,7 @@ async def room_wizard(request, order:Order): 'B':{ 'type': 'new', 'room_type': 5, + 'room_name': 'generated 1', 'to_add': ['B', 'a', 'c'] } } @@ -154,6 +155,8 @@ async def room_wizard(request, order:Order): 'type': 'add_existing', 'to_add': to_add } + + generated_counter = 0 # Create additional rooms while len(roomless_orders.items()) > 0: room = list(roomless_orders.items())[0][1] @@ -174,14 +177,16 @@ async def room_wizard(request, order:Order): code_to_add = list(compatible_roomates.keys())[0] to_add.append(code_to_add) del roomless_orders[code_to_add] + generated_counter += 1 result_map[room.code] = { 'type': 'new', + 'room_name': f'Generated Room {generated_counter}', 'room_type': room.bed_in_room, 'to_add': to_add } tpl = request.app.ctx.tpl.get_template('wizard.html') - return html(tpl.render(order=order, orders=orders, data=result_map)) + return html(tpl.render(order=order, all_orders=all_orders, unconfirmed_orders=orders, data=result_map)) @bp.get('/propic/remind') async def propic_remind_missing(request, order:Order): diff --git a/res/scripts/wizardManager.js b/res/scripts/wizardManager.js new file mode 100644 index 0000000..883e07b --- /dev/null +++ b/res/scripts/wizardManager.js @@ -0,0 +1,103 @@ +function initObjects (){ + draggables = document.querySelectorAll("div.grid.people div.edit-drag"); + rooms = document.querySelectorAll("main.container>div.room"); + Array.from(draggables).forEach(element => { + element.addEventListener('dragstart', dragStart); + element.addEventListener('dragend', dragEnd); + }); + Array.from(rooms).forEach(room => { + room.addEventListener('dragenter', dragEnter) + room.addEventListener('dragover', dragOver); + room.addEventListener('dragleave', dragLeave); + room.addEventListener('drop', drop); + }); +} + +function dragStart(e) { + element = e.target; + room = element.closest('div.room') + dataToSave = { + id: element.id, + type: element.getAttribute('room-type'), + parentId: room.id + } + e.dataTransfer.setData('application/json', JSON.stringify(dataToSave)); + toggleRoomSelection(true); +} + +function dragEnd(e) { + toggleRoomSelection(false); + e.stopPropagation(); +} + +function dragEnter(e) { + e.preventDefault(); + e.target.classList.add('drag-over'); + checkDragLocation (decodeData(e), e.target); + e.stopPropagation(); +} + +function dragOver(e) { + e.preventDefault(); + e.target.classList.add('drag-over'); + checkDragLocation (decodeData(e), e.target); + e.stopPropagation(); +} + +/** + * @param {DragEvent} e + * @returns + */ +function decodeData (e) { + const raw = e.dataTransfer.getData('application/json'); + console.log(raw); + return JSON.parse(raw); +} + +/** + * + * @param {Element} target + */ +function checkDragLocation (data, target) { + let toReturn = true; + const isInfinite = target.getAttribute("infinite"); + const maxSizeReached = target.getAttribute("current-size") >= target.getAttribute("room-size"); + const roomTypeMismatch = data.type !== target.getAttribute("room-type"); + if (!isInfinite && (maxSizeReached || roomTypeMismatch)) { + target.classList.add('drag-forbidden'); + toReturn = false; + } + return toReturn; +} + +function dragLeave(e) { + e.target.classList.remove('drag-over'); + e.target.classList.remove('drag-forbidden'); +} + +function drop(e) { + e.target.classList.remove('drag-over'); + toggleRoomSelection(false); + if (checkDragLocation(decodeData(e), e.target) === true) { + console.log () + const data = decodeData (e); + let item = document.getElementById (data.id) + let oldParent = document.getElementById (data.parentId) + 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)) + } +} + +function toggleRoomSelection(newStatus) { + rooms = document.querySelectorAll("main.container>div.room"); + Array.from(rooms).forEach(room=>{ + room.classList.toggle('interactless', newStatus); + room.classList.remove('drag-over'); + room.classList.remove('drag-forbidden'); + }) +} + +initObjects (); \ No newline at end of file diff --git a/res/styles/wizard.css b/res/styles/wizard.css new file mode 100644 index 0000000..362ed2c --- /dev/null +++ b/res/styles/wizard.css @@ -0,0 +1,23 @@ +div.grid.people div.edit-disabled { + pointer-events: none; + filter: grayscale(1); + user-select: none; + cursor: not-allowed; +} + +div.grid.people div.edit-drag>div.propic-container { + pointer-events: none; +} + +div.drag-over { + border-radius: 1rem; + border: 0.2rem dashed white; +} + +div.drag-forbidden { + border-color: #c92121aa; +} + +div.interactless>*{ + pointer-events: none; +} \ No newline at end of file diff --git a/tpl/wizard.html b/tpl/wizard.html index 1c0b83b..26db1e5 100644 --- a/tpl/wizard.html +++ b/tpl/wizard.html @@ -1,8 +1,11 @@ {% extends "base.html" %} -{% block title %}Admin panel{% endblock %} +{% block title %}Room Wizard{% endblock %} +{% block head %} + +{% endblock %} {% block main %}
- +
@@ -10,15 +13,50 @@

Review rooms


{% for room in data.items() %} - {%with room_order = orders[room[0]] %} - + {%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 %} {% endfor %} +
+

Empty room

+
+
{% endblock %} diff --git a/utils.py b/utils.py index 0876148..cdd5e01 100644 --- a/utils.py +++ b/utils.py @@ -84,7 +84,7 @@ async def load_items() -> bool: ROOM_TYPE_NAMES[v['id']] = roomName # Adds itself to the category list categoryName = check_and_get_category ('item', q) - if not categoryName: continue + if not categoryName or q['id'] in CATEGORIES_LIST_MAP[categoryName]: continue CATEGORIES_LIST_MAP[categoryName].append(q['id']) if (EXTRA_PRINTS): logger.debug(f'Mapped Items: %s', ITEMS_ID_MAP)