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
This commit is contained in:
Andrea 2024-05-16 23:52:09 +02:00
parent 13e5217601
commit 41373dfcfa
5 changed files with 178 additions and 9 deletions

View File

@ -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):

View File

@ -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 ();

23
res/styles/wizard.css Normal file
View File

@ -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;
}

View File

@ -1,8 +1,11 @@
{% extends "base.html" %}
{% block title %}Admin panel{% endblock %}
{% block title %}Room Wizard{% endblock %}
{% block head %}
<link rel="stylesheet" href="/res/styles/wizard.css">
{% endblock %}
{% block main %}
<main class="container">
<script src="/res/scripts/wizardManager.js"></script>
<script src="/res/scripts/wizardManager.js" type="text/javascript" defer="defer"></script>
<header>
<picture>
<source srcset="/res/furizon.png" media="(prefers-color-scheme:dark)">
@ -10,15 +13,50 @@
</picture>
</header>
<!--order = current order login
orders = all non confirmed rooms orders
unconfirmed_orders = all non confirmed rooms orders
all_orders = all orders
data = assigned rooms -->
<h2>Review rooms</h2>
<hr>
{% for room in data.items() %}
{%with room_order = orders[room[0]] %}
{%with room_order = unconfirmed_orders[room[0]] %}
<div class="room" id="room-{{room_order.code}}" room-type="{{room_order.bed_in_room}}" room-size="{{len(room[1]['to_add'])}}" current-size="{{len(room[1]['to_add'])}}">
<h4 style="margin-top:1em;">
<span>{{room_order.room_name if room_order.room_name else room[1]['room_name'] if room[1] and room[1]['room_name'] else ''}}</span>
</h4>
<div class="grid people" style="padding-bottom:1em;">
{% for m in room_order.room_members %}
{% if m in all_orders %}
{% with person = all_orders[m] %}
<div class="edit-disabled" style="margin-bottom: 1em;">
{% with current=None, order=person, imgSrc='/res/propic/' + (person.ans('propic') or 'default.png'), effects = false, flag = true %}
{% include 'blocks/propic.html' %}
{% endwith %}
<h5>{{person.ans('fursona_name')}}</h5>
</div>
{% endwith %}
{% endif %}
{% endfor %}
{% for m in room[1]['to_add'] %}
{% if m in unconfirmed_orders %}
{% with person = unconfirmed_orders[m] %}
<div class="edit-drag" id="{{person.code}}" room-type="{{person.bed_in_room}}" style="margin-bottom: 1em;" draggable="true">
{% with current=None, order=person, imgSrc='/res/propic/' + (person.ans('propic') or 'default.png'), effects = false, flag = true %}
{% include 'blocks/propic.html' %}
{% endwith %}
<h5>{{person.ans('fursona_name')}}</h5>
</div>
{% endwith %}
{% endif %}
{% endfor %}
</div>
</div>
{% endwith %}
{% endfor %}
<div class="room" infinite="true" id="room-infinite" room-size="999999999" current-size="0">
<h2>Empty room</h2>
<div class="grid people" style="padding-bottom:1em;"></div>
</div>
</main>
{% endblock %}

View File

@ -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)