diff --git a/app.py b/app.py index bf6d269..9a88a37 100644 --- a/app.py +++ b/app.py @@ -1141,7 +1141,7 @@ def handle_join(data): emit('user_joined', {'username': username}, to=room) emit('user_list', {'users': list(active_users[room])}, to=room) emit('joined_confirmation', {'room': room, 'list_title': list_title}) - + @socketio.on('disconnect') def handle_disconnect(sid): global active_users @@ -1220,6 +1220,23 @@ def handle_uncheck_item(data): 'percent': percent }, to=str(item.list_id)) +@socketio.on('request_full_list') +def handle_request_full_list(data): + list_id = data['list_id'] + items = Item.query.filter_by(list_id=list_id).all() + + items_data = [] + for item in items: + items_data.append({ + 'id': item.id, + 'name': item.name, + 'quantity': item.quantity, + 'purchased': item.purchased, + 'note': item.note or '' + }) + + emit('full_list', {'items': items_data}, to=request.sid) + @socketio.on('update_note') def handle_update_note(data): item_id = data['item_id'] diff --git a/static/js/live.js b/static/js/live.js index 3f04ad9..7f240ff 100644 --- a/static/js/live.js +++ b/static/js/live.js @@ -216,6 +216,11 @@ socket.on('user_list', function(data) { showToast(`Obecni: ${userList}`, 'info'); }); +socket.on('full_list', function(data) { + updateListSmoothly(data.items); + showToast('🔄 Lista została zaktualizowana', 'info'); +}); + } function updateItemState(itemId, isChecked) { @@ -333,3 +338,72 @@ function showToast(message, type = 'primary') { toastContainer.appendChild(toast); setTimeout(() => { toast.remove(); }, 1750); } + +function updateListSmoothly(newItems) { + const itemsContainer = document.getElementById('items'); + const existingItems = Array.from(itemsContainer.querySelectorAll('li')); + const existingIds = existingItems.map(li => parseInt(li.id.replace('item-', ''), 10)); + const newIds = newItems.map(item => item.id); + + // Usuń elementy, które nie istnieją w nowej liście + existingItems.forEach(li => { + const id = parseInt(li.id.replace('item-', ''), 10); + if (!newIds.includes(id)) { + li.remove(); + } + }); + + // Przejdź przez nowe elementy + newItems.forEach(item => { + const li = document.getElementById(`item-${item.id}`); + let quantityBadge = ''; + if (item.quantity && item.quantity > 1) { + quantityBadge = `x${item.quantity}`; + } + + if (li) { + // Jeśli istnieje — sprawdź i ewentualnie zaktualizuj nazwę, badge, notatkę + const nameSpan = li.querySelector(`#name-${item.id}`); + let newNameHtml = `${item.name} ${quantityBadge}`; + if (nameSpan && nameSpan.innerHTML.trim() !== newNameHtml.trim()) { + nameSpan.innerHTML = newNameHtml; + } + + const noteEl = li.querySelector('small'); + if (item.note && (!noteEl || noteEl.innerText !== `[ ${item.note} ]`)) { + if (!noteEl) { + const newNote = document.createElement('small'); + newNote.className = 'text-danger ms-4'; + newNote.innerHTML = `[ ${item.note} ]`; + nameSpan.insertAdjacentElement('afterend', newNote); + } else { + noteEl.innerHTML = `[ ${item.note} ]`; + } + } else if (!item.note && noteEl) { + noteEl.remove(); + } + + } else { + // Jeśli brak — dodaj nowy + const newLi = document.createElement('li'); + newLi.className = `list-group-item d-flex justify-content-between align-items-center flex-wrap ${item.purchased ? 'bg-success text-white' : 'item-not-checked'}`; + newLi.id = `item-${item.id}`; + + newLi.innerHTML = ` +