zmiany css i js

This commit is contained in:
Mateusz Gruszczyński
2025-07-09 23:09:41 +02:00
parent c96a0763a7
commit 40fa601bbe
13 changed files with 162 additions and 140 deletions

9
app.py
View File

@@ -37,15 +37,16 @@ AUTHORIZED_COOKIE_VALUE = app.config.get('AUTHORIZED_COOKIE_VALUE', '80d31cdfe63
PROTECTED_JS_FILES = {
"live.js",
"list_share.js",
"hide_list.js",
"socket_reconnect.js",
"notes.js",
"sockets.js",
"product_suggestion.js",
"expenses.js",
"toggle_button.js",
"user_management.js",
"mass_add.js",
"functions.js"
"functions.js",
"clickable_row.js",
"receipt_section.js"
}
os.makedirs(UPLOAD_FOLDER, exist_ok=True)

View File

@@ -237,3 +237,16 @@ input.form-control {
.add-btn {
margin-left: 10px;
}
.quantity-controls {
min-width: 120px;
display: flex;
align-items: center;
justify-content: flex-end;
gap: 4px;
}
.list-group-item {
display: flex;
align-items: center;
justify-content: space-between;
}

View File

@@ -1,31 +1,6 @@
let currentItemId = null;
function openNoteModal(event, itemId) {
event.stopPropagation();
currentItemId = itemId;
// Pobierz notatkę z HTML-a, jeśli chcesz pokazywać aktualną (opcjonalnie)
const noteEl = document.querySelector(`#item-${itemId} small`);
document.getElementById('noteText').value = noteEl ? noteEl.innerText : "";
const modal = new bootstrap.Modal(document.getElementById('noteModal'));
modal.show();
}
function submitNote(e) {
e.preventDefault();
const text = document.getElementById('noteText').value;
if (currentItemId !== null) {
socket.emit('update_note', { item_id: currentItemId, note: text });
const modal = bootstrap.Modal.getInstance(document.getElementById('noteModal'));
modal.hide();
}
}
document.addEventListener("DOMContentLoaded", () => {
document.querySelectorAll('.clickable-item').forEach(item => {
item.addEventListener('click', function(e) {
// Jeśli klik w button (np. Notatka), nie zaznaczaj
if (!e.target.closest('button') && e.target.tagName.toLowerCase() !== 'input') {
const checkbox = this.querySelector('input[type="checkbox"]');

View File

@@ -103,6 +103,33 @@ function copyLink(link) {
}
}
/* function shareLink(link) {
if (navigator.share) {
navigator.share({
title: 'Udostępnij moją listę',
text: 'Zobacz tę listę!',
url: link
})
.catch((error) => {
console.error('Błąd podczas udostępniania', error);
alert('Nie udało się udostępnić linka');
});
} else {
copyLink(link);
}
}
function fallbackCopy(link) {
navigator.clipboard.writeText(link).then(() => {
alert('Link skopiowany do schowka!');
});
}
*/
function openList(link) {
window.open(link, '_blank');
}
function fallbackCopyText(text) {
const textarea = document.createElement('textarea');
textarea.value = text;
@@ -129,6 +156,30 @@ function fallbackCopyText(text) {
document.body.removeChild(textarea);
}
function toggleVisibility(listId) {
fetch('/toggle_visibility/' + listId, {method: 'POST'})
.then(response => response.json())
.then(data => {
const shareHeader = document.getElementById('share-header');
const shareUrlSpan = document.getElementById('share-url');
const copyBtn = document.getElementById('copyBtn');
const toggleBtn = document.getElementById('toggleVisibilityBtn');
if (data.is_public) {
shareHeader.textContent = '🔗 Udostępnij link:';
shareUrlSpan.style.display = 'inline';
shareUrlSpan.textContent = data.share_url;
copyBtn.disabled = false;
toggleBtn.innerHTML = '🙈 Ukryj listę';
} else {
shareHeader.textContent = '🙈 Lista jest ukryta przed gośćmi';
shareUrlSpan.style.display = 'none';
copyBtn.disabled = true;
toggleBtn.innerHTML = '👁️ Udostępnij ponownie';
}
});
}
function showToast(message, type = 'primary') {
const toastContainer = document.getElementById('toast-container');
const toast = document.createElement('div');
@@ -172,14 +223,12 @@ function updateListSmoothly(newItems) {
}
if (li) {
// Checkbox
const checkbox = li.querySelector('input[type="checkbox"]');
if (checkbox) {
checkbox.checked = item.purchased;
checkbox.disabled = false; // Zdejmij disabled jeśli było
checkbox.disabled = false;
}
// Klasy
li.classList.remove('bg-success', 'text-white', 'item-not-checked', 'opacity-50');
if (item.purchased) {
li.classList.add('bg-success', 'text-white');
@@ -187,14 +236,12 @@ function updateListSmoothly(newItems) {
li.classList.add('item-not-checked');
}
// Nazwa
const nameSpan = li.querySelector(`#name-${item.id}`);
const expectedName = `${item.name} ${quantityBadge}`.trim();
if (nameSpan && nameSpan.innerHTML.trim() !== expectedName) {
nameSpan.innerHTML = expectedName;
}
// Notatka
let noteEl = li.querySelector('small');
if (item.note) {
if (!noteEl) {
@@ -209,12 +256,10 @@ function updateListSmoothly(newItems) {
noteEl.remove();
}
// Usuń spinner jeśli był
const sp = li.querySelector('.spinner-border');
if (sp) sp.remove();
} else {
// Twórz nowy element
li = document.createElement('li');
li.className = `list-group-item d-flex justify-content-between align-items-center flex-wrap ${item.purchased ? 'bg-success text-white' : 'item-not-checked'}`;
li.id = `item-${item.id}`;
@@ -232,7 +277,6 @@ function updateListSmoothly(newItems) {
fragment.appendChild(li);
});
// Wyczyść i wstaw nowy porządek
itemsContainer.innerHTML = '';
itemsContainer.appendChild(fragment);

View File

@@ -1,64 +0,0 @@
function toggleVisibility(listId) {
fetch('/toggle_visibility/' + listId, {method: 'POST'})
.then(response => response.json())
.then(data => {
const shareHeader = document.getElementById('share-header');
const shareUrlSpan = document.getElementById('share-url');
const copyBtn = document.getElementById('copyBtn');
const toggleBtn = document.getElementById('toggleVisibilityBtn');
if (data.is_public) {
shareHeader.textContent = '🔗 Udostępnij link:';
shareUrlSpan.style.display = 'inline';
shareUrlSpan.textContent = data.share_url;
copyBtn.disabled = false;
toggleBtn.innerHTML = '🙈 Ukryj listę';
} else {
shareHeader.textContent = '🙈 Lista jest ukryta przed gośćmi';
shareUrlSpan.style.display = 'none';
copyBtn.disabled = true;
toggleBtn.innerHTML = '👁️ Udostępnij ponownie';
}
});
}
function copyLink(link) {
if (navigator.share) {
navigator.share({
title: 'Udostępnij moją listę',
text: 'Zobacz tę listę!',
url: link
}).catch((error) => {
console.error('Błąd podczas udostępniania', error);
fallbackCopy(link);
});
} else {
fallbackCopy(link);
}
}
function shareLink(link) {
if (navigator.share) {
navigator.share({
title: 'Udostępnij moją listę',
text: 'Zobacz tę listę!',
url: link
})
.catch((error) => {
console.error('Błąd podczas udostępniania', error);
alert('Nie udało się udostępnić linka');
});
} else {
copyLink(link);
}
}
function fallbackCopy(link) {
navigator.clipboard.writeText(link).then(() => {
alert('Link skopiowany do schowka!');
});
}
function openList(link) {
window.open(link, '_blank');
}

View File

@@ -202,33 +202,5 @@ function setupList(listId, username) {
window.LIST_ID = listId;
window.usernameForReconnect = username;
socket.on('user_joined', function(data) {
showToast(`${data.username} dołączył do listy`, 'info');
});
socket.on('user_left', function(data) {
showToast(`${data.username} opuścił listę`, 'warning');
});
socket.on('user_list', function(data) {
if (data.users.length > 0) {
const userList = data.users.join(', ');
showToast(`Obecni: ${userList}`, 'info');
}
});
socket.on('full_list', function(data) {
const itemsContainer = document.getElementById('items');
const oldItems = Array.from(itemsContainer.querySelectorAll('li'));
if (isListDifferent(oldItems, data.items)) {
updateListSmoothly(data.items);
showToast('Lista została zaktualizowana', 'info');
} else {
updateListSmoothly(data.items);
}
});
}

View File

@@ -20,19 +20,28 @@ document.addEventListener('DOMContentLoaded', function () {
allproducts.forEach(name => {
const li = document.createElement('li');
li.className = 'list-group-item d-flex justify-content-between align-items-center bg-dark text-light';
li.textContent = name;
if (addedProducts.has(name.toLowerCase())) {
// Produkt już dodany — oznacz jako nieaktywny
const nameSpan = document.createElement('span');
nameSpan.textContent = name;
li.appendChild(nameSpan);
li.classList.add('opacity-50');
const badge = document.createElement('span');
badge.className = 'badge bg-success ms-auto';
badge.textContent = 'Dodano';
li.appendChild(badge);
} else {
// Nazwa produktu
const nameSpan = document.createElement('span');
nameSpan.textContent = name;
nameSpan.style.flex = '1 1 auto';
li.appendChild(nameSpan);
// Kontener na minus, pole i plus
const qtyWrapper = document.createElement('div');
qtyWrapper.className = 'd-flex align-items-center ms-2';
qtyWrapper.className = 'd-flex align-items-center ms-2 quantity-controls';
// Minus
const minusBtn = document.createElement('button');
@@ -51,7 +60,6 @@ document.addEventListener('DOMContentLoaded', function () {
qty.className = 'form-control text-center p-1';
qty.classList.add('rounded');
qty.style.width = '50px';
qty.style.flex = '0 0 auto';
qty.style.margin = '0 2px';
qty.title = 'Ilość';
@@ -64,26 +72,29 @@ document.addEventListener('DOMContentLoaded', function () {
qty.value = parseInt(qty.value) + 1;
};
// Dodajemy przyciski i input do wrappera
qtyWrapper.appendChild(minusBtn);
qtyWrapper.appendChild(qty);
qtyWrapper.appendChild(plusBtn);
// Przycisk dodania
const btn = document.createElement('button');
btn.className = 'btn btn-sm btn-primary ms-2';
btn.className = 'btn btn-sm btn-primary ms-4';
btn.textContent = '+';
btn.onclick = () => {
const quantity = parseInt(qty.value) || 1;
socket.emit('add_item', { list_id: LIST_ID, name: name, quantity: quantity });
};
li.textContent = name;
li.appendChild(qtyWrapper);
li.appendChild(btn);
}
productList.appendChild(li);
});
} catch (err) {
productList.innerHTML = '<li class="list-group-item text-danger bg-dark">Błąd ładowania danych</li>';
}

22
static/js/notes.js Normal file
View File

@@ -0,0 +1,22 @@
let currentItemId = null;
function openNoteModal(event, itemId) {
event.stopPropagation();
currentItemId = itemId;
const noteEl = document.querySelector(`#item-${itemId} small`);
document.getElementById('noteText').value = noteEl ? noteEl.innerText : "";
const modal = new bootstrap.Modal(document.getElementById('noteModal'));
modal.show();
}
function submitNote(e) {
e.preventDefault();
const text = document.getElementById('noteText').value;
if (currentItemId !== null) {
socket.emit('update_note', { item_id: currentItemId, note: text });
const modal = bootstrap.Modal.getInstance(document.getElementById('noteModal'));
modal.hide();
}
}

View File

@@ -0,0 +1,18 @@
document.addEventListener("DOMContentLoaded", function() {
const receiptSection = document.getElementById("receiptSection");
const toggleBtn = document.querySelector('[data-bs-target="#receiptSection"]');
if (!receiptSection || !toggleBtn) return;
if (localStorage.getItem("receiptSectionOpen") === "true") {
new bootstrap.Collapse(receiptSection, { toggle: true });
}
receiptSection.addEventListener('shown.bs.collapse', function () {
localStorage.setItem("receiptSectionOpen", "true");
});
receiptSection.addEventListener('hidden.bs.collapse', function () {
localStorage.setItem("receiptSectionOpen", "false");
});
});

View File

@@ -32,7 +32,7 @@ let wasReconnected = false; // flaga do kontrolowania toasta
socket.on('connect', function() {
if (!firstConnect) {
showToast('Połączono z serwerem! 🔄', 'info');
//showToast('Połączono z serwerem!', 'info');
disableCheckboxes(true);
wasReconnected = true;
@@ -59,3 +59,30 @@ socket.on('joined_confirmation', function(data) {
}
});
socket.on('user_joined', function(data) {
showToast(`${data.username} dołączył do listy`, 'info');
});
socket.on('user_left', function(data) {
showToast(`${data.username} opuścił listę`, 'warning');
});
socket.on('user_list', function(data) {
if (data.users.length > 0) {
const userList = data.users.join(', ');
showToast(`Obecni: ${userList}`, 'info');
}
});
socket.on('full_list', function(data) {
const itemsContainer = document.getElementById('items');
const oldItems = Array.from(itemsContainer.querySelectorAll('li'));
if (isListDifferent(oldItems, data.items)) {
updateListSmoothly(data.items);
showToast('Lista została zaktualizowana', 'info');
} else {
updateListSmoothly(data.items);
}
});

View File

@@ -33,7 +33,9 @@
</div>
{% if not image_files %}
<p class="text-muted mt-3">Brak wgranych zdjęć.</p>
<div class="alert alert-info" role="alert">
Nie wgrano paragonów.
</div>
{% endif %}
{% endblock %}

View File

@@ -74,8 +74,7 @@
{% if request.endpoint != 'system_auth' %}
<script src="{{ url_for('static_bp.serve_js', filename='functions.js') }}"></script>
<script src="{{ url_for('static_bp.serve_js', filename='live.js') }}"></script>
<script src="{{ url_for('static_bp.serve_js', filename='hide_list.js') }}"></script>
<script src="{{ url_for('static_bp.serve_js', filename='socket_reconnect.js') }}"></script>
<script src="{{ url_for('static_bp.serve_js', filename='sockets.js') }}"></script>
{% endif %}
<script src="{{ url_for('static_bp.serve_js', filename='toasts.js') }}"></script>
{% block scripts %}{% endblock %}

View File

@@ -113,7 +113,9 @@
</div>
{% block scripts %}
<script src="{{ url_for('static_bp.serve_js', filename='list_share.js') }}"></script>
<script src="{{ url_for('static_bp.serve_js', filename='notes.js') }}"></script>
<script src="{{ url_for('static_bp.serve_js', filename='clickable_row.js') }}"></script>
<script src="{{ url_for('static_bp.serve_js', filename='receipt_section.js') }}"></script>
<script>
setupList({{ list.id }}, '{{ current_user.username if current_user.is_authenticated else 'Gość' }}');
</script>