duzo zmian ux

This commit is contained in:
Mateusz Gruszczyński
2025-07-07 12:59:18 +02:00
parent 8854d5b558
commit 86bf3e1a86
10 changed files with 521 additions and 62 deletions

View File

@@ -25,6 +25,9 @@
<li class="nav-item">
<a class="nav-link" href="/admin/receipts">📸 Wszystkie paragony</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/admin/products">🛍️ Produkty</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
@@ -38,7 +41,6 @@
</div>
</nav>
<div class="row g-3 mb-4">
<div class="col-md-4">
<div class="card bg-dark text-white h-100">
@@ -70,16 +72,17 @@
<div class="card bg-dark text-white h-100">
<div class="card-body">
<h5>💸 Podsumowanie wydatków:</h5>
<ul class="mb-0">
<ul class="mb-3">
<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>
<button type="button" class="btn btn-outline-primary w-100 mt-3" data-bs-toggle="modal" data-bs-target="#expensesChartModal" id="loadExpensesBtn">
📊 Pokaż wykres wydatków
</button>
</div>
</div>
</div>
</div>
<h3 class="mt-4">📄 Wszystkie listy zakupowe</h3>
@@ -140,7 +143,7 @@
{% 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 liste</a>
<a href="{{ url_for('edit_list', list_id=l.id) }}" class="btn btn-sm btn-outline-primary">✏️ Edytuj</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>
@@ -153,14 +156,50 @@
<button type="submit" class="btn btn-danger mt-2">🗑️ Usuń zaznaczone listy</button>
</form>
<div class="modal fade" id="expensesChartModal" tabindex="-1" aria-labelledby="expensesChartModalLabel" aria-hidden="true">
<div class="modal-dialog modal-xl modal-dialog-centered">
<div class="modal-content bg-dark text-white rounded">
<div class="modal-header border-0">
<div>
<h5 class="modal-title m-0" id="expensesChartModalLabel">📊 Wydatki</h5>
<small id="chartRangeLabel" class="text-muted">Widok: miesięczne</small>
</div>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Zamknij"></button>
</div>
<div class="modal-body pt-0">
<div class="d-flex flex-wrap gap-2 mb-3">
<button class="btn btn-outline-light btn-sm range-btn active" data-range="monthly">📅 Miesięczne</button>
<button class="btn btn-outline-light btn-sm range-btn" data-range="quarterly">📊 Kwartalne</button>
<button class="btn btn-outline-light btn-sm range-btn" data-range="halfyearly">🗓️ Półroczne</button>
<button class="btn btn-outline-light btn-sm range-btn" data-range="yearly">📆 Roczne</button>
</div>
<div class="input-group input-group-sm mb-3 w-100" style="max-width: 570px;">
<span class="input-group-text bg-secondary text-white border-secondary">Od</span>
<input type="date" class="form-control bg-dark text-white border-secondary flex-grow-1" id="startDate">
<span class="input-group-text bg-secondary text-white border-secondary">Do</span>
<input type="date" class="form-control bg-dark text-white border-secondary flex-grow-1" id="endDate">
<button class="btn btn-outline-success" id="customRangeBtn">Pokaż dane z zakresu 📅</button>
</div>
<div class="bg-dark rounded p-2">
<canvas id="expensesChart" height="100"></canvas>
</div>
</div>
</div>
</div>
</div>
{% block scripts %}
<script src="{{ url_for('static_bp.serve_js_lib', filename='chart.js') }}"></script>
<script>
document.getElementById('select-all').addEventListener('click', function(){
const checkboxes = document.querySelectorAll('input[name="list_ids"]');
checkboxes.forEach(cb => cb.checked = this.checked);
});
</script>
<script src="{{ url_for('static_bp.serve_js', filename='expenses.js') }}"></script>
{% endblock %}
{% endblock %}

View File

@@ -0,0 +1,62 @@
{% extends 'base.html' %}
{% block title %}Produkty i sugestie{% endblock %}
{% block content %}
<div class="d-flex justify-content-between align-items-center flex-wrap mb-4">
<h2 class="mb-2">🛍️ Produkty i sugestie</h2>
<a href="/admin" class="btn btn-outline-secondary">← Powrót do panelu</a>
</div>
<div class="card bg-dark text-white">
<div class="card-header d-flex justify-content-between align-items-center">
<h4 class="m-0">📦 Produkty (z synchronizacją sugestii)</h4>
<span class="badge bg-secondary">{{ items|length }} produktów</span>
</div>
<div class="card-body p-0">
<table class="table table-dark table-striped align-middle m-0">
<thead>
<tr>
<th>ID</th>
<th>Nazwa</th>
<th>Dodana przez</th>
<th>Sugestia</th>
<th>Akcje</th>
</tr>
</thead>
<tbody>
{% for item in items %}
<tr>
<td>{{ item.id }}</td>
<td class="fw-bold">{{ item.name }}</td>
<td>
{% if item.added_by %}
{{ users_dict.get(item.added_by, 'Nieznany') }}
{% else %}
Gość
{% endif %}
</td>
<td>
{% set suggestion = suggestions_dict.get(item.name.lower()) %}
{% if suggestion %}
✅ Istnieje (ID: {{ suggestion.id }})
<a href="/admin/delete_suggestion/{{ suggestion.id }}" class="btn btn-sm btn-outline-danger ms-1">🗑️ Usuń</a>
{% else %}
<a href="/admin/sync_suggestion/{{ item.name }}" class="btn btn-sm btn-outline-primary">🔄 Synchronizuj</a>
{% endif %}
</td>
<td>
<a href="/list/{{ item.list_id }}" class="btn btn-sm btn-outline-light mb-1">📄 Zobacz listę</a>
</td>
</tr>
{% endfor %}
{% if items|length == 0 %}
<tr>
<td colspan="5" class="text-center text-muted">Brak produktów do wyświetlenia.</td>
</tr>
{% endif %}
</tbody>
</table>
</div>
</div>
{% endblock %}

View File

@@ -12,32 +12,32 @@ Lista: <strong>{{ list.title }}</strong>
<a href="/" class="btn btn-outline-secondary">← Powrót do list</a>
</div>
<a href="{{ request.url_root }}share/{{ list.share_token }}"
class="btn btn-primary btn-sm w-100 mb-3"
{% if not list.is_public %}disabled{% endif %}>
✅ Otwórz tryb zakupowy / odznaczania produktów
</a>
<div id="share-card" class="card bg-dark text-white mb-4">
<div class="card-body d-flex flex-column flex-md-row justify-content-between align-items-start align-items-md-center gap-2">
<div>
<div class="card-body">
<div class="mb-2">
<strong id="share-header">
{% if list.is_public %}
🔗 Udostępnij link:
{% else %}
🙈 Lista jest ukryta przed gośćmi
{% endif %}
</strong><br>
</strong>
<span id="share-url" class="badge bg-secondary text-wrap" style="font-size: 0.7rem; {% if not list.is_public %}display: none;{% endif %}">
{{ request.url_root }}share/{{ list.share_token }}
</span>
</div>
<div class="d-flex flex-column flex-md-row gap-2 mt-2 mt-md-0">
<button id="copyBtn" class="btn btn-success btn-sm"
<div class="d-flex flex-column flex-md-row gap-2">
<button id="copyBtn" class="btn btn-success btn-sm flex-fill"
onclick="copyLink('{{ request.url_root }}share/{{ list.share_token }}')"
{% if not list.is_public %}disabled{% endif %}>
📋 Skopiuj / Udostępnij
</button>
<button id="openBtn" class="btn btn-primary btn-sm"
onclick="openList('{{ request.url_root }}share/{{ list.share_token }}')"
{% if not list.is_public %}disabled{% endif %}>
✅ Otwórz do odznaczania
</button>
<button id="toggleVisibilityBtn" class="btn btn-outline-secondary btn-sm" onclick="toggleVisibility({{ list.id }})">
<button id="toggleVisibilityBtn" class="btn btn-outline-light btn-sm flex-fill" onclick="toggleVisibility({{ list.id }})">
{% if list.is_public %}
🙈 Ukryj listę
{% else %}
@@ -103,11 +103,10 @@ Lista: <strong>{{ list.title }}</strong>
{% if not list.is_archived %}
<div class="input-group mb-3">
<input type="text" id="newItem" name="name" class="form-control" placeholder="Dodaj produkt" required>
<input type="text" id="newItem" name="name" class="form-control" placeholder="Dodaj produkt i ilość" required>
<input type="number" id="newQuantity" name="quantity" class="form-control" placeholder="Ilość" min="1" value="1" style="max-width: 80px;">
<button type="button" class="btn btn-success rounded" onclick="addItem({{ list.id }})"> Dodaj</button>
<button type="button" class="btn btn-success rounded-end" onclick="addItem({{ list.id }})"> Dodaj</button>
</div>
{% endif %}
{% set receipt_pattern = 'list_' ~ list.id %}

View File

@@ -45,7 +45,7 @@
<div class="input-group mb-2">
<input id="newItem" class="form-control" placeholder="Dodaj produkt i ilość">
<input id="newQuantity" type="number" class="form-control" placeholder="Ilość" min="1" value="1" style="max-width: 90px;">
<button onclick="addItem({{ list.id }})" class="btn btn-success rounded"> Dodaj</button>
<button onclick="addItem({{ list.id }})" class="btn btn-success rounded-end"> Dodaj</button>
</div>
{% endif %}
@@ -54,7 +54,7 @@
<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({{ list.id }})" class="btn btn-success rounded">💾 Zapisz</button>
<button onclick="submitExpense({{ list.id }})" class="btn btn-success rounded-end">💾 Zapisz</button>
</div>
{% endif %}
<p id="total-expense2"><b>💸 Łącznie wydano:</b> {{ '%.2f'|format(total_expense) }} PLN</p>
@@ -67,7 +67,7 @@
{% for file in receipt_files %}
<div class="col-6 col-md-4 col-lg-3 text-center">
<a href="{{ url_for('uploaded_file', filename=file) }}" data-lightbox="receipt" data-title="Paragon">
<img src="{{ url_for('uploaded_file', filename=file) }}" class="img-fluid rounded shadow-sm border border-secondary" style="max-height: 200px; object-fit: cover;">
<img src="{{ url_for('uploaded_file', filename=file) }}" class="img-fluid rounded-end shadow-sm border border-secondary" style="max-height: 200px; object-fit: cover;">
</a>
</div>
{% endfor %}
@@ -83,7 +83,7 @@
<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 rounded"> Wgraj</button>
<button type="submit" class="btn btn-success rounded-end"> Wgraj</button>
</div>
</form>
{% endif %}

View File

@@ -9,28 +9,40 @@
{% endif %}
{% if current_user.is_authenticated %}
<div class="d-flex justify-content-between align-items-center flex-wrap mb-4">
<h2 class="mb-2">Stwórz nową listę</h2>
</div>
<div class="d-flex justify-content-between align-items-center flex-wrap mb-4">
<h2 class="mb-2">Stwórz nową listę</h2>
</div>
<div class="card bg-dark text-white mb-4">
<div class="card-body">
<form action="/create" method="post">
<div class="input-group mb-3">
<input type="text" name="title" id="title" placeholder="Wprowadź nazwę nowej listy" required class="form-control">
<div class="input-group-text">
<input type="checkbox" name="temporary" class="form-check-input m-0" id="tempCheck">
<label for="tempCheck" class="ms-2 mb-0">Tymczasowa (7 dni)</label>
</div>
</div>
<button type="submit" class="btn btn-success w-100"> Utwórz nową listę</button>
</form>
</div>
<div class="card bg-dark text-white mb-4">
<div class="card-body">
<form action="/create" method="post">
<div class="input-group mb-3">
<input type="text" name="title" id="title" placeholder="Wprowadź nazwę nowej listy" required class="form-control">
<button
type="button"
class="btn btn-outline-secondary rounded-end"
id="tempToggle"
data-active="0"
data-bs-toggle="tooltip"
data-bs-placement="top"
title="Po włączeniu lista będzie ważna tylko 7 dni">
Tymczasowa
</button>
<input type="hidden" name="temporary" id="temporaryHidden" value="0">
</div>
<button type="submit" class="btn btn-success w-100"> Utwórz nową listę</button>
</form>
</div>
</div>
{% endif %}
{% if current_user.is_authenticated %}
<h3 class="mt-4">Twoje listy</h3>
<h3 class="mt-4 d-flex justify-content-between align-items-center flex-wrap">
Twoje listy
<button type="button" class="btn btn-sm btn-outline-light ms-2" data-bs-toggle="modal" data-bs-target="#archivedModal">
📁 Zarchiwizowane
</button>
</h3>
{% if user_lists %}
<ul class="list-group mb-4">
{% for l in user_lists %}
@@ -40,17 +52,18 @@
<li class="list-group-item bg-dark text-white">
<div class="d-flex justify-content-between align-items-center flex-wrap w-100">
<span class="fw-bold">{{ l.title }} (Autor: Ty)</span>
<div class="mt-2 mt-md-0">
<a href="/list/{{ l.id }}" class="btn btn-sm btn-outline-light me-1">📄 Otwórz</a>
<a href="/copy/{{ l.id }}" class="btn btn-sm btn-outline-secondary me-1">📋 Kopiuj</a>
<a href="/edit_my_list/{{ l.id }}" class="btn btn-sm btn-outline-warning me-1">✏️ Edytuj</a>
<a href="/archive_my_list/{{ l.id }}" class="btn btn-sm btn-outline-danger me-1">🗄 Archiwizuj</a>
{% if l.is_public %}
<a href="/toggle_visibility/{{ l.id }}" class="btn btn-sm btn-outline-secondary">🙈 Ukryj</a>
{% else %}
<a href="/toggle_visibility/{{ l.id }}" class="btn btn-sm btn-outline-success">👁️ Udostępnij</a>
{% endif %}
</div>
<div class="d-flex flex-wrap mt-2 mt-md-0">
<a href="/list/{{ l.id }}" class="btn btn-sm btn-outline-light me-1 mb-1">📄 Otwórz</a>
<a href="/copy/{{ l.id }}" class="btn btn-sm btn-outline-light me-1 mb-1">📋 Kopiuj</a>
<a href="/edit_my_list/{{ l.id }}" class="btn btn-sm btn-outline-light me-1 mb-1"> Edytuj</a>
<a href="/toggle_archive_list/{{ l.id }}?archive=true" class="btn btn-sm btn-outline-light me-1 mb-1">🗄️ Archiwizuj</a>
{% if l.is_public %}
<a href="/toggle_visibility/{{ l.id }}" class="btn btn-sm btn-outline-light me-1 mb-1">🙈 Ukryj</a>
{% else %}
<a href="/toggle_visibility/{{ l.id }}" class="btn btn-sm btn-outline-light me-1 mb-1">👁️ Udostępnij</a>
{% endif %}
</div>
</div>
<div class="progress mt-2" style="height: 20px;">
<div class="progress-bar bg-warning text-dark fw-bold" role="progressbar" style="width: {{ percent }}%" aria-valuenow="{{ percent }}" aria-valuemin="0" aria-valuemax="100">
@@ -95,4 +108,37 @@
<p><span class="badge bg-secondary">Brak dostępnych list publicznych do wyświetlenia.</span></p>
{% endif %}
<div class="modal fade" id="archivedModal" tabindex="-1" aria-labelledby="archivedModalLabel" 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="archivedModalLabel">Zarchiwizowane listy</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Zamknij"></button>
</div>
<div class="modal-body">
{% if archived_lists %}
<ul class="list-group">
{% for l in archived_lists %}
<li class="list-group-item bg-dark text-white d-flex justify-content-between align-items-center flex-wrap">
<span>{{ l.title }}</span>
<a href="/toggle_archive_list/{{ l.id }}?archive=false" class="btn btn-sm btn-outline-success">♻️ Przywróć</a>
</li>
{% endfor %}
</ul>
{% else %}
<p><span class="badge bg-secondary">Nie masz żadnych zarchiwizowanych list.</span></p>
{% endif %}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-light" data-bs-dismiss="modal">Zamknij</button>
</div>
</div>
</div>
</div>
{% block scripts %}
<script src="{{ url_for('static_bp.serve_js', filename='toggle_button.js') }}"></script>
{% endblock %}
{% endblock %}