duzo zmian, funkcji

This commit is contained in:
Mateusz Gruszczyński
2025-07-04 11:07:23 +02:00
parent 4e2bc0434f
commit 4de8a9cac1
8 changed files with 390 additions and 96 deletions

View File

@ -7,35 +7,81 @@
<a href="/" class="btn btn-outline-secondary">← Powrót do strony głównej</a>
</div>
<div class="d-flex flex-wrap gap-2 mb-4">
<a href="/admin/add_user" class="btn btn-success"> Dodaj użytkownika</a>
<a href="/admin/users" class="btn btn-outline-light">👥 Lista użytkowników</a>
<a href="/admin/receipts" class="btn btn-outline-light">📸 Wszystkie paragony</a>
<a href="/admin/delete_all_lists" class="btn btn-danger">🗑️ Usuń wszystkie listy</a>
<a href="/admin/delete_all_items" class="btn btn-danger">❌ Usuń wszystkie produkty</a>
</div>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark rounded mb-4">
<div class="container-fluid p-0">
<a class="navbar-brand" href="#">Admin</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#adminNavbar" aria-controls="adminNavbar" aria-expanded="false" aria-label="Przełącz nawigację">
<span class="navbar-toggler-icon"></span>
</button>
<div class="card bg-dark text-white mb-4">
<div class="card-body">
<p><strong>👤 Liczba użytkowników:</strong> {{ user_count }}</p>
<p><strong>📝 Liczba list zakupowych:</strong> {{ list_count }}</p>
<p><strong>🛒 Liczba produktów:</strong> {{ item_count }}</p>
<p><strong>✅ Zakupionych produktów:</strong> {{ purchased_items_count }}</p>
<div class="collapse navbar-collapse" id="adminNavbar">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link" href="/admin/add_user"> Dodaj użytkownika</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/admin/users">👥 Lista użytkowników</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/admin/receipts">📸 Wszystkie paragony</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle text-danger" href="#" id="clearDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
🗑️ Czyszczenie
</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item text-danger" href="/admin/delete_all_lists">Usuń wszystkie listy</a></li>
<li><a class="dropdown-item text-danger" href="/admin/delete_all_items">Usuń wszystkie produkty</a></li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
<div class="row g-3 mb-4">
<div class="col-md-4">
<div class="card bg-dark text-white h-100">
<div class="card-body">
<p><strong>👤 Liczba użytkowników:</strong> {{ user_count }}</p>
<p><strong>📝 Liczba list zakupowych:</strong> {{ list_count }}</p>
<p><strong>🛒 Liczba produktów:</strong> {{ item_count }}</p>
<p><strong>✅ Zakupionych produktów:</strong> {{ purchased_items_count }}</p>
</div>
</div>
</div>
{% if top_products %}
<div class="col-md-4">
<div class="card bg-dark text-white h-100">
<div class="card-body">
<h5>🔥 Najczęściej kupowane produkty:</h5>
<ul class="mb-0">
{% for name, count in top_products %}
<li>{{ name }} — {{ count }}×</li>
{% endfor %}
</ul>
</div>
</div>
</div>
{% endif %}
<div class="col-md-4">
<div class="card bg-dark text-white h-100">
<div class="card-body">
<h5>💸 Podsumowanie wydatków:</h5>
<ul class="mb-0">
<li><strong>Obecny miesiąc:</strong> {{ '%.2f'|format(month_expense_sum) }} PLN</li>
<li><strong>Obecny rok:</strong> {{ '%.2f'|format(year_expense_sum) }} PLN</li>
<li><strong>Całkowite:</strong> {{ '%.2f'|format(total_expense_sum) }} PLN</li>
</ul>
</div>
</div>
</div>
</div>
{% if top_products %}
<div class="card bg-dark text-white mb-4">
<div class="card-body">
<h5>🔥 Najczęściej kupowane produkty:</h5>
<ul class="mb-0">
{% for name, count in top_products %}
<li>{{ name }} — {{ count }}×</li>
{% endfor %}
</ul>
</div>
</div>
{% endif %}
<h3 class="mt-4">📄 Wszystkie listy zakupowe</h3>
<form method="post" action="{{ url_for('delete_selected_lists') }}">
@ -52,6 +98,7 @@
<th>Wypełnienie</th>
<th>Komentarze</th>
<th>Paragony</th>
<th>Wydatki</th>
<th>Akcje</th>
</tr>
</thead>
@ -76,14 +123,22 @@
<td>{{ e.purchased_count }}/{{ e.total_count }} ({{ e.percent }}%)</td>
<td>{{ e.comments_count }}</td>
<td>{{ e.receipts_count }}</td>
<td>
{% if e.total_expense > 0 %}
{{ '%.2f'|format(e.total_expense) }} PLN
{% else %}
-
{% endif %}
</td>
<td class="d-flex flex-wrap gap-1">
<a href="{{ url_for('edit_list', list_id=l.id) }}" class="btn btn-sm btn-outline-primary">✏️ Edytuj</a>
<a href="{{ url_for('edit_list', list_id=l.id) }}" class="btn btn-sm btn-outline-primary">✏️ Edytuj liste</a>
<a href="{{ url_for('archive_list', list_id=l.id) }}" class="btn btn-sm btn-outline-secondary">📥 Archiwizuj</a>
<a href="{{ url_for('delete_list', list_id=l.id) }}" class="btn btn-sm btn-outline-danger">🗑️ Usuń</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<button type="submit" class="btn btn-danger mt-2">🗑️ Usuń zaznaczone listy</button>

View File

@ -3,7 +3,7 @@
{% block content %}
<div class="d-flex justify-content-between align-items-center flex-wrap mb-4">
<h2 class="mb-2">✏️ Edytuj tytuł listy</h2>
<h2 class="mb-2">✏️ Edytuj listę #{{ list.id }}</h2>
<a href="{{ url_for('admin_panel') }}" class="btn btn-outline-secondary">← Powrót</a>
</div>
@ -12,7 +12,22 @@
<label for="title" class="form-label">Nowy tytuł</label>
<input type="text" class="form-control" id="title" name="title" value="{{ list.title }}" required>
</div>
<div class="mb-3">
<label for="amount" class="form-label">Nowa kwota wydatku (PLN)</label>
<input type="number" step="0.01" min="0" class="form-control" id="amount" name="amount" value="{{ '%.2f'|format(total_expense) }}">
<small class="form-text text-muted">Jeśli nie chcesz zmieniać kwoty, zostaw to pole bez zmian.</small>
</div>
<div class="form-check mb-3">
<input class="form-check-input" type="checkbox" id="archived" name="archived" {% if list.is_archived %}checked{% endif %}>
<label class="form-check-label" for="archived">
Archiwalna
</label>
</div>
<button type="submit" class="btn btn-success">💾 Zapisz</button>
<a href="{{ url_for('admin_panel') }}" class="btn btn-secondary">Anuluj</a>
</form>
{% endblock %}

View File

@ -44,7 +44,12 @@
</div>
</div>
<div class="progress mt-2" style="height: 20px;">
<div class="progress-bar bg-warning" role="progressbar" style="width: {{ percent }}%" aria-valuenow="{{ percent }}" aria-valuemin="0" aria-valuemax="100">Produkty: {{ purchased_count }}/{{ total_count }} ({{ percent|round(0) }}%)</div>
<div class="progress-bar bg-warning text-dark fw-bold" role="progressbar" style="width: {{ percent }}%" aria-valuenow="{{ percent }}" aria-valuemin="0" aria-valuemax="100">
Produkty: {{ purchased_count }}/{{ total_count }} ({{ percent|round(0) }}%)
{% if l.total_expense > 0 %}
— 💸 {{ '%.2f'|format(l.total_expense) }} PLN
{% endif %}
</div>
</div>
</li>
{% endfor %}

View File

@ -3,7 +3,16 @@
{% block content %}
<div class="d-flex justify-content-between align-items-center mb-3 flex-wrap">
<h2 class="mb-2">Lista: <strong>{{ list.title }}</strong></h2>
<h2 class="mb-2">
Lista: <strong>{{ list.title }}</strong>
{% if list.is_archived %}
<span class="badge bg-secondary ms-2">(Archiwalna)</span>
{% endif %}
</h2>
<a href="/" class="btn btn-outline-secondary">← Powrót do list</a>
</div>
@ -15,9 +24,15 @@
{{ request.url_root }}share/{{ list.share_token }}
</span>
</div>
<button class="btn btn-success btn-sm mt-2 mt-md-0" onclick="copyLink('{{ request.url_root }}share/{{ list.share_token }}')">
📋 udostępnij link
</button>
{% if not list.is_archived %}
<button class="btn btn-success btn-sm mt-2 mt-md-0" onclick="copyLink('{{ request.url_root }}share/{{ list.share_token }}')">
📋 Udostępnij link
</button>
{% else %}
<button class="btn btn-secondary btn-sm mt-2 mt-md-0" disabled>
📋 Udostępnianie wyłączone (Archiwalna)
</button>
{% endif %}
</div>
</div>
@ -25,7 +40,8 @@
<h5 id="progress-title" class="mb-2">
📊 Postęp listy — {{ purchased_count }}/{{ total_count }} kupionych ({{ percent|round(0) }}%)
</h5>
<div class="progress mb-3" style="height: 25px;">
<div class="progress mb-2" style="height: 25px;">
<div id="progress-bar" class="progress-bar bg-warning" role="progressbar"
style="width: {{ percent }}%;" aria-valuenow="{{ percent }}"
aria-valuemin="0" aria-valuemax="100">
@ -33,30 +49,49 @@
</div>
</div>
{% if total_expense > 0 %}
<div id="total-expense2" class="text-success fw-bold mb-3">
💸 Łącznie wydano: {{ '%.2f'|format(total_expense) }} PLN
</div>
{% else %}
<div id="total-expense2" class="text-success fw-bold mb-3" style="display: none;">
💸 Łącznie wydano: 0.00 PLN
</div>
{% endif %}
<ul id="items" class="list-group mb-3">
{% for item in items %}
<li class="list-group-item d-flex justify-content-between align-items-center flex-wrap {% if item.purchased %}bg-success text-white{% else %}bg-light text-white{% endif %}" id="item-{{ item.id }}">
<div class="d-flex align-items-center flex-wrap gap-2 flex-grow-1">
<input type="checkbox" {% if item.purchased %}checked{% endif %}>
<input type="checkbox" {% if item.purchased %}checked{% endif %} {% if list.is_archived %}disabled{% endif %}>
<span id="name-{{ item.id }}" class="{% if item.purchased %}text-white{% else %}text-white{% endif %}">{{ item.name }}</span>
{% if item.note %}
<small class="text-danger">[ Notatka: <b>{{ item.note }}</b> ] </small>
{% endif %}
</div>
<div class="mt-2 mt-md-0 d-flex gap-1">
<button class="btn btn-sm btn-outline-warning" onclick="editItem({{ item.id }}, '{{ item.name }}')">✏️ Edytuj</button>
<button class="btn btn-sm btn-outline-danger" onclick="deleteItem({{ item.id }})">🗑️ Usuń</button>
<button class="btn btn-sm btn-outline-warning"
{% if list.is_archived %}disabled{% else %}onclick="editItem({{ item.id }}, '{{ item.name }}')"{% endif %}>
✏️ Edytuj
</button>
<button class="btn btn-sm btn-outline-danger"
{% if list.is_archived %}disabled{% else %}onclick="deleteItem({{ item.id }})"{% endif %}>
🗑️ Usuń
</button>
</div>
</li>
{% endfor %}
</ul>
<div class="input-group mb-2 position-relative">
<input id="newItem" class="form-control" placeholder="Nowy produkt">
<button onclick="addItem({{ list.id }})" class="btn btn-success"> Dodaj</button>
</div>
{% if not list.is_archived %}
<div class="input-group mb-2 position-relative">
<input id="newItem" class="form-control" placeholder="Nowy produkt">
<button onclick="addItem({{ list.id }})" class="btn btn-success"> Dodaj</button>
</div>
{% endif %}
{% set receipt_pattern = 'list_' ~ list.id %}
{% if receipt_files %}

View File

@ -2,31 +2,58 @@
{% block title %}Lista: {{ list.title }}{% endblock %}
{% block content %}
<div class="d-flex justify-content-between align-items-center flex-wrap mb-3">
<h2 class="mb-2">🛍️ {{ list.title }} <small class="text-muted">(Gość)</small></h2>
</div>
<h2 class="mb-2">
🛍️ {{ list.title }}
{% if list.is_archived %}
<span class="badge bg-secondary ms-2">(Archiwalna)</span>
{% endif %}
{% if total_expense > 0 %}
<span id="total-expense1" class="badge bg-success ms-2">
💸 {{ '%.2f'|format(total_expense) }} PLN
</span>
{% else %}
<span id="total-expense" class="badge bg-secondary ms-2" style="display: none;">
💸 0.00 PLN
</span>
{% endif %}
</h2>
<ul id="items" class="list-group mb-3">
{% for item in items %}
<li class="list-group-item d-flex justify-content-between align-items-center flex-wrap clickable-item {% if item.purchased %}bg-success text-white{% else %}bg-light text-white{% endif %}" id="item-{{ item.id }}">
<div class="d-flex align-items-center gap-3 flex-grow-1">
<input type="checkbox" class="form-check-input large-checkbox" {% if item.purchased %}checked{% endif %}>
<input type="checkbox" class="form-check-input large-checkbox" {% if item.purchased %}checked{% endif %} {% if list.is_archived %}disabled{% endif %}>
<span id="name-{{ item.id }}" class="{% if item.purchased %}text-white{% else %}text-white{% endif %}">{{ item.name }}</span>
{% if item.note %}
<small class="text-danger ms-4">[ Notatka: <b>{{ item.note }}</b> ]</small>
{% endif %}
</div>
<button type="button" class="btn btn-sm btn-outline-info" onclick="openNoteModal(event, {{ item.id }})">📝 Notatka</button>
<button type="button" class="btn btn-sm btn-outline-info"
{% if list.is_archived %}disabled{% else %}onclick="openNoteModal(event, {{ item.id }})"{% endif %}>
📝 Notatka
</button>
</li>
{% endfor %}
</ul>
<div class="input-group mb-2">
<input id="newItem" class="form-control" placeholder="Nowy produkt">
<button onclick="addItem({{ list.id }})" class="btn btn-success"> Dodaj</button>
</div>
{% if not list.is_archived %}
<div class="input-group mb-2">
<input id="newItem" class="form-control" placeholder="Nowy produkt">
<button onclick="addItem({{ list.id }})" class="btn btn-success"> Dodaj</button>
</div>
{% endif %}
{% if not list.is_archived %}
<hr>
<h5>💰 Dodaj wydatek</h5>
<div class="input-group mb-2">
<input id="expenseAmount" type="number" step="0.01" min="0" class="form-control" placeholder="Kwota (PLN)">
<button onclick="submitExpense()" class="btn btn-success">💾 Zapisz</button>
</div>
<p id="total-expense2"><b>💸 Łącznie wydano:</b> {{ '%.2f'|format(total_expense) }} PLN</p>
{% endif %}
<div id="toast-container" class="toast-container position-fixed bottom-0 end-0 p-3"></div>
{% set receipt_pattern = 'list_' ~ list.id %}
{% if receipt_files %}
@ -46,14 +73,16 @@
<p><span class="badge bg-secondary">Brak wgranych paragonów do tej listy.</span></p>
{% endif %}
<hr>
<h5>📤 Dodaj zdjęcie paragonu</h5>
<form action="{{ url_for('upload_receipt', list_id=list.id) }}" method="post" enctype="multipart/form-data">
<div class="input-group mb-2">
<input type="file" name="receipt" accept="image/*" capture="environment" class="form-control custom-file-input" id="receiptInput">
<button type="submit" class="btn btn-success"> Wgraj</button>
</div>
</form>
{% if not list.is_archived %}
<hr>
<h5>📤 Dodaj zdjęcie paragonu</h5>
<form action="{{ url_for('upload_receipt', list_id=list.id) }}" method="post" enctype="multipart/form-data">
<div class="input-group mb-2">
<input type="file" name="receipt" accept="image/*" capture="environment" class="form-control custom-file-input" id="receiptInput">
<button type="submit" class="btn btn-success"> Wgraj</button>
</div>
</form>
{% endif %}
<!-- Modal notatki -->
<div class="modal fade" id="noteModal" tabindex="-1" aria-hidden="true">
@ -76,6 +105,8 @@
</div>
</div>
<div id="toast-container" class="toast-container position-fixed bottom-0 end-0 p-3"></div>
<script>
const LIST_ID = {{ list.id }};
setupList(LIST_ID, 'Gość');