jedna kategoria dla listy
This commit is contained in:
20
app.py
20
app.py
@@ -2971,6 +2971,26 @@ def admin_mass_edit_categories():
|
||||
"admin/mass_edit_categories.html", lists=lists, categories=categories
|
||||
)
|
||||
|
||||
@app.route("/admin/list_items/<int:list_id>")
|
||||
@login_required
|
||||
@admin_required
|
||||
def admin_list_items_json(list_id):
|
||||
l = db.session.get(ShoppingList, list_id)
|
||||
if not l:
|
||||
return jsonify({"error": "Lista nie istnieje"}), 404
|
||||
|
||||
items = [
|
||||
{
|
||||
"name": item.name,
|
||||
"quantity": item.quantity,
|
||||
"purchased": item.purchased,
|
||||
"not_purchased": item.not_purchased,
|
||||
}
|
||||
for item in l.items
|
||||
]
|
||||
|
||||
return jsonify({"title": l.title, "items": items})
|
||||
|
||||
|
||||
@app.route("/healthcheck")
|
||||
def healthcheck():
|
||||
|
@@ -1,4 +1,5 @@
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
// Inicjalizacja Tom Select dla wszystkich select[multiple]
|
||||
document.querySelectorAll('select[multiple]').forEach(function (el) {
|
||||
new TomSelect(el, {
|
||||
plugins: ['remove_button'],
|
||||
@@ -8,4 +9,76 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
dropdownParent: 'body'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Obsługa przycisków podglądu produktów
|
||||
document.querySelectorAll(".preview-btn").forEach((btn) => {
|
||||
btn.addEventListener("click", async () => {
|
||||
const listId = btn.dataset.listId;
|
||||
const modalTitle = document.getElementById("previewModalLabel");
|
||||
const productList = document.getElementById("product-list");
|
||||
|
||||
modalTitle.textContent = "Ładowanie...";
|
||||
productList.innerHTML = '<li class="list-group-item bg-dark text-white">⏳ Ładowanie produktów...</li>';
|
||||
|
||||
const modal = new bootstrap.Modal(document.getElementById("productPreviewModal"));
|
||||
modal.show();
|
||||
|
||||
try {
|
||||
const res = await fetch(`/admin/list_items/${listId}`);
|
||||
const data = await res.json();
|
||||
|
||||
modalTitle.textContent = `🛒 ${data.title}`;
|
||||
productList.innerHTML = "";
|
||||
|
||||
const purchasedList = document.createElement("ul");
|
||||
purchasedList.className = "list-group list-group-flush mb-3";
|
||||
|
||||
const notPurchasedList = document.createElement("ul");
|
||||
notPurchasedList.className = "list-group list-group-flush";
|
||||
|
||||
let hasPurchased = false;
|
||||
let hasUnpurchased = false;
|
||||
|
||||
data.items.forEach(item => {
|
||||
const li = document.createElement("li");
|
||||
li.className = "list-group-item bg-dark text-white d-flex justify-content-between";
|
||||
li.innerHTML = `
|
||||
<span>${item.name}</span>
|
||||
<span class="badge ${item.purchased ? 'bg-success' : item.not_purchased ? 'bg-warning text-dark' : 'bg-secondary'}">
|
||||
x${item.quantity}
|
||||
</span>`;
|
||||
|
||||
if (item.purchased) {
|
||||
purchasedList.appendChild(li);
|
||||
hasPurchased = true;
|
||||
} else {
|
||||
notPurchasedList.appendChild(li);
|
||||
hasUnpurchased = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (hasPurchased) {
|
||||
const h5 = document.createElement("h6");
|
||||
h5.textContent = "✔️ Kupione";
|
||||
productList.appendChild(h5);
|
||||
productList.appendChild(purchasedList);
|
||||
}
|
||||
|
||||
if (hasUnpurchased) {
|
||||
const h5 = document.createElement("h6");
|
||||
h5.textContent = "🚫 Niekupione / Nieoznaczone";
|
||||
productList.appendChild(h5);
|
||||
productList.appendChild(notPurchasedList);
|
||||
}
|
||||
|
||||
if (!hasPurchased && !hasUnpurchased) {
|
||||
productList.innerHTML = '<li class="list-group-item bg-dark text-muted fst-italic">Brak produktów</li>';
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
modalTitle.textContent = "Błąd";
|
||||
productList.innerHTML = '<li class="list-group-item bg-dark text-danger">❌ Błąd podczas ładowania</li>';
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
45
static/js/list_items_on_list.js
Normal file
45
static/js/list_items_on_list.js
Normal file
@@ -0,0 +1,45 @@
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
// Tom Select jak był
|
||||
|
||||
// Obsługa kliknięcia "Podgląd"
|
||||
document.querySelectorAll(".preview-btn").forEach((btn) => {
|
||||
btn.addEventListener("click", async () => {
|
||||
const listId = btn.dataset.listId;
|
||||
const modalTitle = document.getElementById("previewModalLabel");
|
||||
const productList = document.getElementById("product-list");
|
||||
|
||||
modalTitle.textContent = "Ładowanie...";
|
||||
productList.innerHTML = '<li class="list-group-item bg-dark text-white">⏳ Ładowanie produktów...</li>';
|
||||
|
||||
const modal = new bootstrap.Modal(document.getElementById("productPreviewModal"));
|
||||
modal.show();
|
||||
|
||||
try {
|
||||
const res = await fetch(`/admin/list_items/${listId}`);
|
||||
const data = await res.json();
|
||||
|
||||
modalTitle.textContent = `🛒 ${data.title}`;
|
||||
productList.innerHTML = "";
|
||||
|
||||
if (data.items.length === 0) {
|
||||
productList.innerHTML = '<li class="list-group-item bg-dark text-muted fst-italic">Brak produktów</li>';
|
||||
} else {
|
||||
data.items.forEach(item => {
|
||||
const li = document.createElement("li");
|
||||
li.className = "list-group-item bg-dark text-white d-flex justify-content-between";
|
||||
li.innerHTML = `
|
||||
<span>${item.name}</span>
|
||||
<span class="badge ${item.purchased ? 'bg-success' : item.not_purchased ? 'bg-warning text-dark' : 'bg-secondary'}">
|
||||
x${item.quantity}
|
||||
</span>`;
|
||||
productList.appendChild(li);
|
||||
});
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
modalTitle.textContent = "Błąd";
|
||||
productList.innerHTML = '<li class="list-group-item bg-dark text-danger">❌ Błąd podczas ładowania</li>';
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
@@ -32,8 +32,10 @@
|
||||
<td>{{ lst.owner.username if lst.owner else "?" }}</td>
|
||||
<td>{{ lst.created_at.strftime('%Y-%m-%d') }}</td>
|
||||
<td>
|
||||
<a href="{{ url_for('view_list', list_id=lst.id) }}" target="_blank"
|
||||
class="btn btn-sm btn-outline-light">🔗 Otwórz</a>
|
||||
<button type="button" class="btn btn-sm btn-outline-info preview-btn"
|
||||
data-list-id="{{ lst.id }}">
|
||||
🔍 Podgląd
|
||||
</button>
|
||||
</td>
|
||||
<td style="min-width: 220px;">
|
||||
<select name="categories_{{ lst.id }}" multiple
|
||||
@@ -58,6 +60,22 @@
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Modal podglądu produktów -->
|
||||
<div class="modal fade" id="productPreviewModal" tabindex="-1" aria-labelledby="previewModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg modal-dialog-scrollable">
|
||||
<div class="modal-content bg-dark text-white">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="previewModalLabel">Podgląd produktów</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"
|
||||
aria-label="Zamknij"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<ul id="product-list" class="list-group list-group-flush"></ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
{% block scripts %}
|
||||
<script src="https://cdn.jsdelivr.net/npm/tom-select/dist/js/tom-select.complete.min.js"></script>
|
||||
|
Reference in New Issue
Block a user