diff --git a/static/css/style.css b/static/css/style.css
index 878f7e0..0e32abb 100644
--- a/static/css/style.css
+++ b/static/css/style.css
@@ -3,6 +3,7 @@
width: 1.5em;
height: 1.5em;
}
+
.clickable-item {
cursor: pointer;
}
@@ -38,7 +39,8 @@
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
- pointer-events: none; /* klikalne przyciski obok paska nie ucierpią */
+ pointer-events: none;
+ /* klikalne przyciski obok paska nie ucierpią */
white-space: nowrap;
}
@@ -53,7 +55,7 @@
/* --- Styl przycisku wyboru pliku --- */
input[type="file"]::file-selector-button {
- background-color: #225d36;
+ background-color: #225d36;
color: #fff;
border: none;
padding: 0.5em 1em;
@@ -69,16 +71,19 @@ input[type="file"]::file-selector-button {
color: #eaffea !important;
border-color: #174428 !important;
}
+
.alert-danger {
background-color: #7a1f23 !important;
color: #ffeaea !important;
border-color: #531417 !important;
}
+
.alert-info {
background-color: #1d3a4d !important;
color: #eaf6ff !important;
border-color: #152837 !important;
}
+
.alert-warning {
background-color: #665c1e !important;
color: #fffbe5 !important;
@@ -86,35 +91,50 @@ input[type="file"]::file-selector-button {
}
/* Badge - kolory pasujące do ciemnych alertów */
-.badge.bg-success, .badge.text-bg-success {
+.badge.bg-success,
+.badge.text-bg-success {
background-color: #225d36 !important;
color: #eaffea !important;
}
-.badge.bg-danger, .badge.text-bg-danger {
+
+.badge.bg-danger,
+.badge.text-bg-danger {
background-color: #7a1f23 !important;
color: #ffeaea !important;
}
-.badge.bg-info, .badge.text-bg-info {
+
+.badge.bg-info,
+.badge.text-bg-info {
background-color: #1d3a4d !important;
color: #eaf6ff !important;
}
-.badge.bg-warning, .badge.text-bg-warning {
+
+.badge.bg-warning,
+.badge.text-bg-warning {
background-color: #665c1e !important;
color: #fffbe5 !important;
}
-.badge.bg-secondary, .badge.text-bg-secondary {
+
+.badge.bg-secondary,
+.badge.text-bg-secondary {
background-color: #343a40 !important;
color: #e2e3e5 !important;
}
-.badge.bg-primary, .badge.text-bg-primary {
+
+.badge.bg-primary,
+.badge.text-bg-primary {
background-color: #184076 !important;
color: #e6f0ff !important;
}
-.badge.bg-light, .badge.text-bg-light {
+
+.badge.bg-light,
+.badge.text-bg-light {
background-color: #444950 !important;
color: #f8f9fa !important;
}
-.badge.bg-dark, .badge.text-bg-dark {
+
+.badge.bg-dark,
+.badge.text-bg-dark {
background-color: #181a1b !important;
color: #f8f9fa !important;
}
@@ -157,6 +177,7 @@ input[type="checkbox"].large-checkbox:disabled::before {
opacity: 0.5;
cursor: not-allowed;
}
+
input[type="checkbox"].large-checkbox:disabled {
cursor: not-allowed;
}
@@ -223,6 +244,7 @@ input.form-control {
opacity: 0;
transform: translateY(20px);
}
+
to {
opacity: 1;
transform: translateY(0);
@@ -232,11 +254,13 @@ input.form-control {
#mass-add-list li.active {
background: #198754 !important;
color: #fff !important;
- border: 1px solid #000000 !important;
+ border: 1px solid #000000 !important;
}
+
#mass-add-list li {
transition: background 0.2s;
}
+
.quantity-input {
width: 60px;
background: #343a40;
@@ -245,6 +269,7 @@ input.form-control {
border-radius: 4px;
text-align: center;
}
+
.add-btn {
margin-left: 10px;
}
@@ -256,6 +281,7 @@ input.form-control {
justify-content: flex-end;
gap: 4px;
}
+
.list-group-item {
display: flex;
align-items: center;
diff --git a/static/js/clickable_row.js b/static/js/clickable_row.js
index a928fa5..955c80c 100644
--- a/static/js/clickable_row.js
+++ b/static/js/clickable_row.js
@@ -1,6 +1,6 @@
document.addEventListener("DOMContentLoaded", () => {
document.querySelectorAll('.clickable-item').forEach(item => {
- item.addEventListener('click', function(e) {
+ item.addEventListener('click', function (e) {
if (!e.target.closest('button') && e.target.tagName.toLowerCase() !== 'input') {
const checkbox = this.querySelector('input[type="checkbox"]');
diff --git a/static/js/expenses.js b/static/js/expenses.js
index 7b6b569..9c4b338 100644
--- a/static/js/expenses.js
+++ b/static/js/expenses.js
@@ -1,4 +1,4 @@
-document.addEventListener("DOMContentLoaded", function() {
+document.addEventListener("DOMContentLoaded", function () {
let expensesChart = null;
const rangeLabel = document.getElementById("chartRangeLabel");
@@ -8,57 +8,57 @@ document.addEventListener("DOMContentLoaded", function() {
url += `&start_date=${startDate}&end_date=${endDate}`;
}
- fetch(url, {cache: "no-store"})
- .then(response => response.json())
- .then(data => {
- const ctx = document.getElementById('expensesChart').getContext('2d');
+ fetch(url, { cache: "no-store" })
+ .then(response => response.json())
+ .then(data => {
+ const ctx = document.getElementById('expensesChart').getContext('2d');
- if (expensesChart) {
- expensesChart.destroy();
- }
+ if (expensesChart) {
+ expensesChart.destroy();
+ }
- expensesChart = new Chart(ctx, {
- type: 'bar',
- data: {
- labels: data.labels,
- datasets: [{
- label: 'Suma wydatków [PLN]',
- data: data.expenses,
- backgroundColor: '#0d6efd'
- }]
- },
- options: {
- scales: {
- y: {
- beginAtZero: true
+ expensesChart = new Chart(ctx, {
+ type: 'bar',
+ data: {
+ labels: data.labels,
+ datasets: [{
+ label: 'Suma wydatków [PLN]',
+ data: data.expenses,
+ backgroundColor: '#0d6efd'
+ }]
+ },
+ options: {
+ scales: {
+ y: {
+ beginAtZero: true
+ }
}
}
+ });
+
+ if (startDate && endDate) {
+ rangeLabel.textContent = `Widok: własny zakres (${startDate} → ${endDate})`;
+ } else {
+ let labelText = "";
+ if (range === "monthly") labelText = "Widok: miesięczne";
+ else if (range === "quarterly") labelText = "Widok: kwartalne";
+ else if (range === "halfyearly") labelText = "Widok: półroczne";
+ else if (range === "yearly") labelText = "Widok: roczne";
+ rangeLabel.textContent = labelText;
}
+
+ })
+ .catch(error => {
+ console.error("Błąd pobierania danych:", error);
});
-
- if (startDate && endDate) {
- rangeLabel.textContent = `Widok: własny zakres (${startDate} → ${endDate})`;
- } else {
- let labelText = "";
- if (range === "monthly") labelText = "Widok: miesięczne";
- else if (range === "quarterly") labelText = "Widok: kwartalne";
- else if (range === "halfyearly") labelText = "Widok: półroczne";
- else if (range === "yearly") labelText = "Widok: roczne";
- rangeLabel.textContent = labelText;
- }
-
- })
- .catch(error => {
- console.error("Błąd pobierania danych:", error);
- });
}
- document.getElementById('loadExpensesBtn').addEventListener('click', function() {
+ document.getElementById('loadExpensesBtn').addEventListener('click', function () {
loadExpenses();
});
document.querySelectorAll('.range-btn').forEach(btn => {
- btn.addEventListener('click', function() {
+ btn.addEventListener('click', function () {
document.querySelectorAll('.range-btn').forEach(b => b.classList.remove('active'));
this.classList.add('active');
const range = this.getAttribute('data-range');
@@ -66,7 +66,7 @@ document.addEventListener("DOMContentLoaded", function() {
});
});
- document.getElementById('customRangeBtn').addEventListener('click', function() {
+ document.getElementById('customRangeBtn').addEventListener('click', function () {
const startDate = document.getElementById('startDate').value;
const endDate = document.getElementById('endDate').value;
if (startDate && endDate) {
@@ -78,7 +78,7 @@ document.addEventListener("DOMContentLoaded", function() {
});
});
-document.addEventListener("DOMContentLoaded", function() {
+document.addEventListener("DOMContentLoaded", function () {
const startDateInput = document.getElementById("startDate");
const endDateInput = document.getElementById("endDate");
diff --git a/static/js/functions.js b/static/js/functions.js
index 8e57518..533a179 100644
--- a/static/js/functions.js
+++ b/static/js/functions.js
@@ -19,20 +19,6 @@ function updateItemState(itemId, isChecked) {
applyHidePurchased();
}
-/* function updateProgressBar() {
- const items = document.querySelectorAll('#items li');
- const total = items.length;
- const purchased = Array.from(items).filter(li => li.classList.contains('bg-success')).length;
- const percent = total > 0 ? Math.round((purchased / total) * 100) : 0;
-
- const progressBar = document.getElementById('progress-bar');
- if (progressBar) {
- progressBar.style.width = `${percent}%`;
- progressBar.setAttribute('aria-valuenow', percent);
- progressBar.textContent = `${percent}%`;
- }
-} */
-
function updateProgressBar() {
const items = document.querySelectorAll('#items li');
const total = items.length;
@@ -286,87 +272,6 @@ function isListDifferent(oldItems, newItems) {
return false;
}
-/* function updateListSmoothly(newItems) {
- const itemsContainer = document.getElementById('items');
- const existingItemsMap = new Map();
-
- Array.from(itemsContainer.querySelectorAll('li')).forEach(li => {
- const id = parseInt(li.id.replace('item-', ''), 10);
- existingItemsMap.set(id, li);
- });
-
- const fragment = document.createDocumentFragment();
-
- newItems.forEach(item => {
- let li = existingItemsMap.get(item.id);
- let quantityBadge = '';
- if (item.quantity && item.quantity > 1) {
- quantityBadge = `x${item.quantity}`;
- }
-
- if (li) {
- const checkbox = li.querySelector('input[type="checkbox"]');
- if (checkbox) {
- checkbox.checked = item.purchased;
- checkbox.disabled = false;
- }
-
- li.classList.remove('bg-success', 'text-white', 'item-not-checked', 'opacity-50');
- if (item.purchased) {
- li.classList.add('bg-success', 'text-white');
- } else {
- li.classList.add('item-not-checked');
- }
-
- const nameSpan = li.querySelector(`#name-${item.id}`);
- const expectedName = `${item.name} ${quantityBadge}`.trim();
- if (nameSpan && nameSpan.innerHTML.trim() !== expectedName) {
- nameSpan.innerHTML = expectedName;
- }
-
- let noteEl = li.querySelector('small');
- if (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 (noteEl) {
- noteEl.remove();
- }
-
- const sp = li.querySelector('.spinner-border');
- if (sp) sp.remove();
-
- } else {
- 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}`;
-
- li.innerHTML = `
-
-
- ${item.name} ${quantityBadge}
- ${item.note ? `[ ${item.note} ]` : ''}
-
-
- `;
- }
-
- fragment.appendChild(li);
- });
-
- itemsContainer.innerHTML = '';
- itemsContainer.appendChild(fragment);
-
- updateProgressBar();
- toggleEmptyPlaceholder();
- applyHidePurchased();
-} */
-
function updateListSmoothly(newItems) {
const itemsContainer = document.getElementById('items');
const existingItemsMap = new Map();
diff --git a/static/js/live.js b/static/js/live.js
index 4bae47b..d48ae68 100644
--- a/static/js/live.js
+++ b/static/js/live.js
@@ -7,11 +7,11 @@ function toggleEmptyPlaceholder() {
// prawdziwe to te z data‑name lub id="item‑…"
const hasRealItems = list.querySelector('li[data-name], li[id^="item-"]') !== null;
- const placeholder = document.getElementById('empty-placeholder');
+ const placeholder = document.getElementById('empty-placeholder');
if (!hasRealItems && !placeholder) {
- const li = document.createElement('li');
- li.id = 'empty-placeholder';
+ const li = document.createElement('li');
+ li.id = 'empty-placeholder';
li.className = 'list-group-item bg-dark text-secondary text-center w-100';
li.textContent = 'Brak produktów w tej liście.';
list.appendChild(li);
@@ -132,30 +132,30 @@ function setupList(listId, username) {
const li = document.createElement('li');
li.className = 'list-group-item d-flex justify-content-between align-items-center flex-wrap item-not-checked';
li.id = `item-${data.id}`;
-
+
let quantityBadge = '';
if (data.quantity && data.quantity > 1) {
quantityBadge = `x${data.quantity}`;
}
li.innerHTML = `
-
-
- ${data.name} ${quantityBadge}
-
-
-
-
-
- `;
+
+
+ ${data.name} ${quantityBadge}
+
+
+
+
+
+ `;
-// #### WERSJA Z NAPISAMI ####
-//
-//
-
- document.getElementById('items').appendChild(li);
- updateProgressBar();
- toggleEmptyPlaceholder();
+ document.getElementById('items').prepend(li);
});
socket.on('item_deleted', data => {
@@ -168,7 +168,7 @@ function setupList(listId, username) {
toggleEmptyPlaceholder();
});
- socket.on('progress_updated', function(data) {
+ socket.on('progress_updated', function (data) {
const progressBar = document.getElementById('progress-bar');
if (progressBar) {
progressBar.style.width = data.percent + '%';
diff --git a/static/js/notes.js b/static/js/notes.js
index 5899c09..ed6a4c2 100644
--- a/static/js/notes.js
+++ b/static/js/notes.js
@@ -20,3 +20,4 @@ function submitNote(e) {
modal.hide();
}
}
+
diff --git a/static/js/product_suggestion.js b/static/js/product_suggestion.js
index b6bec5f..cde7cf7 100644
--- a/static/js/product_suggestion.js
+++ b/static/js/product_suggestion.js
@@ -1,4 +1,4 @@
-document.addEventListener("DOMContentLoaded", function() {
+document.addEventListener("DOMContentLoaded", function () {
// Odśwież eventy
document.querySelectorAll('.sync-btn').forEach(btn => {
btn.replaceWith(btn.cloneNode(true));
@@ -9,7 +9,7 @@ document.addEventListener("DOMContentLoaded", function() {
// Synchronizacja sugestii
document.querySelectorAll('.sync-btn').forEach(btn => {
- btn.addEventListener('click', function(e) {
+ btn.addEventListener('click', function (e) {
e.preventDefault();
const itemId = this.getAttribute('data-item-id');
@@ -22,28 +22,28 @@ document.addEventListener("DOMContentLoaded", function() {
'X-Requested-With': 'XMLHttpRequest'
}
})
- .then(response => response.json())
- .then(data => {
- showToast(data.message, data.success ? 'success' : 'danger');
+ .then(response => response.json())
+ .then(data => {
+ showToast(data.message, data.success ? 'success' : 'danger');
- if (data.success) {
- button.innerText = '✅ Zsynchronizowano';
- button.classList.remove('btn-outline-primary');
- button.classList.add('btn-success');
- } else {
+ if (data.success) {
+ button.innerText = '✅ Zsynchronizowano';
+ button.classList.remove('btn-outline-primary');
+ button.classList.add('btn-success');
+ } else {
+ button.disabled = false;
+ }
+ })
+ .catch(() => {
+ showToast('Błąd synchronizacji', 'danger');
button.disabled = false;
- }
- })
- .catch(() => {
- showToast('Błąd synchronizacji', 'danger');
- button.disabled = false;
- });
+ });
});
});
// Usuwanie sugestii
document.querySelectorAll('.delete-suggestion-btn').forEach(btn => {
- btn.addEventListener('click', function(e) {
+ btn.addEventListener('click', function (e) {
e.preventDefault();
const suggestionId = this.getAttribute('data-suggestion-id');
@@ -56,21 +56,21 @@ document.addEventListener("DOMContentLoaded", function() {
'X-Requested-With': 'XMLHttpRequest'
}
})
- .then(response => response.json())
- .then(data => {
- showToast(data.message, data.success ? 'success' : 'danger');
+ .then(response => response.json())
+ .then(data => {
+ showToast(data.message, data.success ? 'success' : 'danger');
- if (data.success) {
- const row = button.closest('tr');
- if (row) row.remove();
- } else {
+ if (data.success) {
+ const row = button.closest('tr');
+ if (row) row.remove();
+ } else {
+ button.disabled = false;
+ }
+ })
+ .catch(() => {
+ showToast('Błąd usuwania sugestii', 'danger');
button.disabled = false;
- }
- })
- .catch(() => {
- showToast('Błąd usuwania sugestii', 'danger');
- button.disabled = false;
- });
+ });
});
});
});
diff --git a/static/js/receipt_section.js b/static/js/receipt_section.js
index 6681440..9f474e9 100644
--- a/static/js/receipt_section.js
+++ b/static/js/receipt_section.js
@@ -1,4 +1,4 @@
-document.addEventListener("DOMContentLoaded", function() {
+document.addEventListener("DOMContentLoaded", function () {
const receiptSection = document.getElementById("receiptSection");
const toggleBtn = document.querySelector('[data-bs-target="#receiptSection"]');
diff --git a/static/js/sockets.js b/static/js/sockets.js
index 18f418d..2a8f9a7 100644
--- a/static/js/sockets.js
+++ b/static/js/sockets.js
@@ -2,83 +2,83 @@ let didReceiveFirstFullList = false;
// --- Automatyczny reconnect po powrocie do karty/przywróceniu internetu ---
function reconnectIfNeeded() {
- if (!socket.connected) {
- socket.connect();
- }
+ if (!socket.connected) {
+ socket.connect();
+ }
}
-document.addEventListener("visibilitychange", function() {
- if (!document.hidden) {
- reconnectIfNeeded();
- }
+document.addEventListener("visibilitychange", function () {
+ if (!document.hidden) {
+ reconnectIfNeeded();
+ }
});
-window.addEventListener("focus", function() {
- reconnectIfNeeded();
+window.addEventListener("focus", function () {
+ reconnectIfNeeded();
});
-window.addEventListener("online", function() {
- reconnectIfNeeded();
+window.addEventListener("online", function () {
+ reconnectIfNeeded();
});
// --- Blokowanie checkboxów na czas reconnect ---
function disableCheckboxes(disable) {
- document.querySelectorAll('#items input[type="checkbox"]').forEach(cb => {
- cb.disabled = disable;
- });
+ document.querySelectorAll('#items input[type="checkbox"]').forEach(cb => {
+ cb.disabled = disable;
+ });
}
// --- Toasty przy rozłączeniu i połączeniu ---
let firstConnect = true;
let wasReconnected = false; // flaga do kontrolowania toasta
-socket.on('connect', function() {
- if (!firstConnect) {
- //showToast('Połączono z serwerem!', 'info');
- disableCheckboxes(true);
- wasReconnected = true;
+socket.on('connect', function () {
+ if (!firstConnect) {
+ //showToast('Połączono z serwerem!', 'info');
+ disableCheckboxes(true);
+ wasReconnected = true;
- if (window.LIST_ID && window.usernameForReconnect) {
- socket.emit('join_list', { room: window.LIST_ID, username: window.usernameForReconnect });
- }
+ if (window.LIST_ID && window.usernameForReconnect) {
+ socket.emit('join_list', { room: window.LIST_ID, username: window.usernameForReconnect });
}
- firstConnect = false;
+ }
+ firstConnect = false;
});
-socket.on('disconnect', function(reason) {
- showToast('Utracono połączenie z serwerem...', 'warning');
- disableCheckboxes(true);
+socket.on('disconnect', function (reason) {
+ showToast('Utracono połączenie z serwerem...', 'warning');
+ disableCheckboxes(true);
});
socket.off('joined_confirmation');
-socket.on('joined_confirmation', function(data) {
- if (wasReconnected) {
- showToast(`Lista: ${data.list_title} – ponownie dołączono.`, 'info');
- wasReconnected = false;
- }
- if (window.LIST_ID) {
- socket.emit('request_full_list', { list_id: window.LIST_ID });
- }
+socket.on('joined_confirmation', function (data) {
+ if (wasReconnected) {
+ showToast(`Lista: ${data.list_title} – ponownie dołączono.`, 'info');
+ wasReconnected = false;
+ }
+ if (window.LIST_ID) {
+ socket.emit('request_full_list', { list_id: window.LIST_ID });
+ }
});
-socket.on('user_joined', function(data) {
- showToast(`${data.username} dołączył do listy`, 'info');
+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_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('user_list', function (data) {
+ if (data.users.length > 0) {
+ const userList = data.users.join(', ');
+ showToast(`Obecni: ${userList}`, 'info');
+ }
});
socket.on('receipt_added', function (data) {
-
+
const gallery = document.getElementById("receiptGallery");
if (!gallery) return;
diff --git a/static/js/toggle_button.js b/static/js/toggle_button.js
index 5216365..d441f64 100644
--- a/static/js/toggle_button.js
+++ b/static/js/toggle_button.js
@@ -1,4 +1,4 @@
-document.addEventListener("DOMContentLoaded", function() {
+document.addEventListener("DOMContentLoaded", function () {
const toggleBtn = document.getElementById("tempToggle");
const hiddenInput = document.getElementById("temporaryHidden");
@@ -23,7 +23,7 @@ document.addEventListener("DOMContentLoaded", function() {
updateToggle(active);
// Obsługa kliknięcia
- toggleBtn.addEventListener("click", function() {
+ toggleBtn.addEventListener("click", function () {
active = !active;
toggleBtn.setAttribute("data-active", active ? "1" : "0");
hiddenInput.value = active ? "1" : "0";
diff --git a/static/js/user_management.js b/static/js/user_management.js
index 8327c93..eee0339 100644
--- a/static/js/user_management.js
+++ b/static/js/user_management.js
@@ -1,4 +1,4 @@
-document.addEventListener('DOMContentLoaded', function() {
+document.addEventListener('DOMContentLoaded', function () {
var resetPasswordModal = document.getElementById('resetPasswordModal');
resetPasswordModal.addEventListener('show.bs.modal', function (event) {
var button = event.relatedTarget;
diff --git a/templates/admin/admin_panel.html b/templates/admin/admin_panel.html
index 44624a7..3d85102 100644
--- a/templates/admin/admin_panel.html
+++ b/templates/admin/admin_panel.html
@@ -10,7 +10,8 @@