statystyki i optymalizacje

This commit is contained in:
Mateusz Gruszczyński
2025-12-12 09:23:34 +01:00
parent 20910fa898
commit fe48f589f0
8 changed files with 1303 additions and 421 deletions

View File

@@ -6,32 +6,80 @@
<!-- Nagłówek + akcje globalne -->
<div class="d-flex flex-wrap align-items-center justify-content-between gap-2 mb-4">
<h2 class="mb-0">Panel Admina</h2>
<div>
<h2 class="mb-1">Panel Admina</h2>
<p class="text-muted mb-0">Zarządzaj zbiórkami i monitoruj finanse</p>
</div>
<div class="d-flex flex-wrap gap-2">
<a href="{{ url_for('admin_statystyki') }}" class="btn btn-info">
<i class="bi bi-graph-up"></i> Statystyki
</a>
<a href="{{ url_for('formularz_zbiorek') }}" class="btn btn-primary">
Dodaj zbiórkę
<i class="bi bi-plus-circle"></i> Dodaj zbiórkę
</a>
<a href="{{ url_for('lista_rezerwowych') }}" class="btn btn-outline-light">
Listy rezerwowe
<i class="bi bi-wallet2"></i> Listy rezerwowe
</a>
<a href="{{ url_for('admin_ustawienia') }}" class="btn btn-outline-light">
Ustawienia główne
<i class="bi bi-gear"></i> Ustawienia
</a>
</div>
</div>
<!-- Pigułki: Aktywne / Zrealizowane (zakładki w obrębie panelu) -->
<!-- Szybkie statystyki (cards) -->
<div class="row g-3 mb-4">
<div class="col-md-3">
<div class="card border-primary">
<div class="card-body text-center">
<i class="bi bi-list-check fs-1 text-primary mb-2"></i>
<h3 class="mb-0">{{ active_zbiorki|length }}</h3>
<small class="text-muted">Aktywnych zbiórek</small>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card border-success">
<div class="card-body text-center">
<i class="bi bi-check-circle fs-1 text-success mb-2"></i>
<h3 class="mb-0">{{ completed_zbiorki|length }}</h3>
<small class="text-muted">Zrealizowanych</small>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card border-info">
<div class="card-body text-center">
<i class="bi bi-bar-chart fs-1 text-info mb-2"></i>
<h3 class="mb-0">{{ active_zbiorki|length + completed_zbiorki|length }}</h3>
<small class="text-muted">Łącznie zbiórek</small>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card border-warning">
<div class="card-body text-center">
<a href="{{ url_for('admin_statystyki') }}" class="text-decoration-none">
<i class="bi bi-graph-up-arrow fs-1 text-warning mb-2"></i>
<h5 class="mb-0 text-white">Zobacz pełne</h5>
<small class="text-muted">statystyki</small>
</a>
</div>
</div>
</div>
</div>
<!-- Pigułki: Aktywne / Zrealizowane -->
<ul class="nav nav-pills mb-3" id="adminTabs" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="tab-aktywne" data-bs-toggle="tab" data-bs-target="#pane-aktywne"
type="button" role="tab" aria-controls="pane-aktywne" aria-selected="true">
Aktywne zbiórki
<i class="bi bi-lightning"></i> Aktywne zbiórki ({{ active_zbiorki|length }})
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="tab-zrealizowane" data-bs-toggle="tab" data-bs-target="#pane-zrealizowane"
type="button" role="tab" aria-controls="pane-zrealizowane" aria-selected="false">
Zrealizowane
<i class="bi bi-check-circle"></i> Zrealizowane ({{ completed_zbiorki|length }})
</button>
</li>
</ul>
@@ -59,12 +107,20 @@
<td class="text-muted">{{ z.id }}</td>
<td>
<div class="d-flex flex-column">
<span class="fw-semibold">{{ z.nazwa }}</span>
{# opcjonalnie: mini-meta z celem/stanem jeśli masz te pola #}
<a href="{{ url_for('zbiorka', zbiorka_id=z.id) }}" class="fw-semibold text-decoration-none">
{{ z.nazwa }}
</a>
{% if z.cel is defined or z.stan is defined %}
<small class="text-muted">
{% if z.cel is defined %} Cel: {{ z.cel|round(2) }} PLN {% endif %}
{% if z.stan is defined %} · Stan: {{ z.stan|round(2) }} PLN {% endif %}
{% if z.cel is defined and z.cel > 0 %}
Cel: {{ z.cel|round(2) }} PLN
{% endif %}
{% if z.stan is defined %}
· Stan: {{ z.stan|round(2) }} PLN
{% endif %}
{% if z.cel is defined and z.cel > 0 and z.stan is defined %}
· {{ ((z.stan / z.cel) * 100)|round(1) }}%
{% endif %}
</small>
{% endif %}
</div>
@@ -72,65 +128,82 @@
<td>
{% if z.ukryta %}
<span class="badge bg-secondary border"
style="border-color: var(--border);">Ukryta</span>
style="border-color: var(--border);"><i class="bi bi-eye-slash"></i> Ukryta</span>
{% else %}
<span class="badge bg-success">Widoczna</span>
<span class="badge bg-success"><i class="bi bi-eye"></i> Widoczna</span>
{% endif %}
</td>
<td class="text-end">
<!-- Grupa akcji: główne + rozwijane -->
<div class="btn-group">
<a href="{{ url_for('formularz_zbiorek', zbiorka_id=z.id) }}"
class="btn btn-sm btn-outline-light">Edytuj</a>
class="btn btn-sm btn-outline-light">
<i class="bi bi-pencil"></i> Edytuj
</a>
<button class="btn btn-sm btn-outline-light dropdown-toggle dropdown-toggle-split"
data-bs-toggle="dropdown" aria-expanded="false" aria-label="Więcej opcji">
<span class="visually-hidden">Więcej</span>
</button>
<ul class="dropdown-menu dropdown-menu-dark dropdown-menu-end shadow">
<li>
<a class="dropdown-item" href="{{ url_for('zbiorka', zbiorka_id=z.id) }}">
<i class="bi bi-eye"></i> Podgląd
</a>
</li>
<li><hr class="dropdown-divider"></li>
<li>
<a class="dropdown-item"
href="{{ url_for('dodaj_wplate', zbiorka_id=z.id) }}">Dodaj
wpłatę</a>
href="{{ url_for('dodaj_wplate', zbiorka_id=z.id) }}">
<i class="bi bi-plus-circle text-success"></i> Dodaj wpłatę
</a>
</li>
<li>
<a class="dropdown-item"
href="{{ url_for('dodaj_wydatek', zbiorka_id=z.id) }}">Dodaj
wydatek</a>
href="{{ url_for('dodaj_wydatek', zbiorka_id=z.id) }}">
<i class="bi bi-dash-circle text-danger"></i> Dodaj wydatek
</a>
</li>
<li>
<a class="dropdown-item"
href="{{ url_for('transakcje_zbiorki', zbiorka_id=z.id) }}">Transakcje</a>
href="{{ url_for('transakcje_zbiorki', zbiorka_id=z.id) }}">
<i class="bi bi-list-ul"></i> Transakcje
</a>
</li>
<li>
<a class="dropdown-item"
href="{{ url_for('edytuj_stan', zbiorka_id=z.id) }}">Edytuj stan</a>
</li>
<li>
<hr class="dropdown-divider">
href="{{ url_for('edytuj_stan', zbiorka_id=z.id) }}">
<i class="bi bi-currency-dollar"></i> Edytuj stan
</a>
</li>
<li><hr class="dropdown-divider"></li>
<li>
<form action="{{ url_for('oznacz_zrealizowana', zbiorka_id=z.id) }}"
method="post" class="m-0">
<button type="submit" class="dropdown-item">Oznacz jako
zrealizowaną</button>
<button type="submit" class="dropdown-item">
<i class="bi bi-check-circle text-success"></i> Oznacz jako zrealizowaną
</button>
</form>
</li>
<li>
<form action="{{ url_for('zmien_widzialnosc', zbiorka_id=z.id) }}"
method="post" class="m-0">
<button type="submit" class="dropdown-item">
{% if z.ukryta %}Pokaż{% else %}Ukryj{% endif %}
{% if z.ukryta %}
<i class="bi bi-eye"></i> Pokaż
{% else %}
<i class="bi bi-eye-slash"></i> Ukryj
{% endif %}
</button>
</form>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li><hr class="dropdown-divider"></li>
<li>
<form action="{{ url_for('usun_zbiorka', zbiorka_id=z.id) }}" method="post"
class="m-0"
onsubmit="return confirm('Czy na pewno chcesz usunąć tę zbiórkę?');">
<button type="submit" class="dropdown-item text-danger">Usuń</button>
<button type="submit" class="dropdown-item text-danger">
<i class="bi bi-trash"></i> Usuń
</button>
</form>
</li>
</ul>
@@ -145,9 +218,12 @@
<!-- Empty state -->
<div class="card">
<div class="card-body text-center py-5">
<i class="bi bi-inbox fs-1 text-muted mb-3"></i>
<h5 class="mb-2">Brak aktywnych zbiórek</h5>
<p class="text-muted mb-4">Wygląda na to, że teraz nic nie zbieramy.</p>
<a href="{{ url_for('formularz_zbiorek') }}" class="btn btn-primary">Utwórz nową zbiórkę</a>
<a href="{{ url_for('formularz_zbiorek') }}" class="btn btn-primary">
<i class="bi bi-plus-circle"></i> Utwórz nową zbiórkę
</a>
</div>
</div>
{% endif %}
@@ -174,7 +250,9 @@
<td class="text-muted">{{ z.id }}</td>
<td>
<div class="d-flex flex-column">
<span class="fw-semibold">{{ z.nazwa }}</span>
<a href="{{ url_for('zbiorka', zbiorka_id=z.id) }}" class="fw-semibold text-decoration-none">
{{ z.nazwa }}
</a>
{% if z.cel is defined or z.stan is defined %}
<small class="text-muted">
{% if z.cel is defined %} Cel: {{ z.cel|round(2) }} PLN {% endif %}
@@ -186,68 +264,87 @@
<td>
<div class="d-flex align-items-center gap-2 flex-wrap">
<span class="badge rounded-pill"
style="background: var(--accent); color:#111;">Zrealizowana</span>
style="background: var(--accent); color:#111;">
<i class="bi bi-check-circle"></i> Zrealizowana
</span>
{% if z.ukryta %}
<span class="badge bg-secondary border"
style="border-color: var(--border);">Ukryta</span>
style="border-color: var(--border);"><i class="bi bi-eye-slash"></i> Ukryta</span>
{% else %}
<span class="badge bg-success">Widoczna</span>
<span class="badge bg-success"><i class="bi bi-eye"></i> Widoczna</span>
{% endif %}
</div>
</td>
<td class="text-end">
<div class="btn-group">
<a href="{{ url_for('formularz_zbiorek', zbiorka_id=z.id) }}"
class="btn btn-sm btn-outline-light">Edytuj</a>
class="btn btn-sm btn-outline-light">
<i class="bi bi-pencil"></i> Edytuj
</a>
<button class="btn btn-sm btn-outline-light dropdown-toggle dropdown-toggle-split"
data-bs-toggle="dropdown" aria-expanded="false" aria-label="Więcej opcji">
<span class="visually-hidden">Więcej</span>
</button>
<ul class="dropdown-menu dropdown-menu-dark dropdown-menu-end shadow">
<li>
<a class="dropdown-item" href="{{ url_for('zbiorka', zbiorka_id=z.id) }}">
<i class="bi bi-eye"></i> Podgląd
</a>
</li>
<li><hr class="dropdown-divider"></li>
<li>
<a class="dropdown-item"
href="{{ url_for('dodaj_wplate', zbiorka_id=z.id) }}">Dodaj
wpłatę</a>
href="{{ url_for('dodaj_wplate', zbiorka_id=z.id) }}">
<i class="bi bi-plus-circle text-success"></i> Dodaj wpłatę
</a>
</li>
<li>
<a class="dropdown-item"
href="{{ url_for('dodaj_wydatek', zbiorka_id=z.id) }}">Dodaj
wydatek</a>
href="{{ url_for('dodaj_wydatek', zbiorka_id=z.id) }}">
<i class="bi bi-dash-circle text-danger"></i> Dodaj wydatek
</a>
</li>
<li>
<a class="dropdown-item"
href="{{ url_for('transakcje_zbiorki', zbiorka_id=z.id) }}">Transakcje</a>
href="{{ url_for('transakcje_zbiorki', zbiorka_id=z.id) }}">
<i class="bi bi-list-ul"></i> Transakcje
</a>
</li>
<li>
<a class="dropdown-item"
href="{{ url_for('edytuj_stan', zbiorka_id=z.id) }}">Edytuj stan</a>
</li>
<li>
<hr class="dropdown-divider">
href="{{ url_for('edytuj_stan', zbiorka_id=z.id) }}">
<i class="bi bi-currency-dollar"></i> Edytuj stan
</a>
</li>
<li><hr class="dropdown-divider"></li>
<li>
<form action="{{ url_for('oznacz_niezrealizowana', zbiorka_id=z.id) }}"
method="post" class="m-0">
<button type="submit" class="dropdown-item">Oznacz jako
niezrealizowaną</button>
<button type="submit" class="dropdown-item">
<i class="bi bi-arrow-counterclockwise"></i> Oznacz jako niezrealizowaną
</button>
</form>
</li>
<li>
<form action="{{ url_for('zmien_widzialnosc', zbiorka_id=z.id) }}"
method="post" class="m-0">
<button type="submit" class="dropdown-item">
{% if z.ukryta %}Pokaż{% else %}Ukryj{% endif %}
{% if z.ukryta %}
<i class="bi bi-eye"></i> Pokaż
{% else %}
<i class="bi bi-eye-slash"></i> Ukryj
{% endif %}
</button>
</form>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li><hr class="dropdown-divider"></li>
<li>
<form action="{{ url_for('usun_zbiorka', zbiorka_id=z.id) }}" method="post"
class="m-0"
onsubmit="return confirm('Czy na pewno chcesz usunąć tę zbiórkę?');">
<button type="submit" class="dropdown-item text-danger">Usuń</button>
<button type="submit" class="dropdown-item text-danger">
<i class="bi bi-trash"></i> Usuń
</button>
</form>
</li>
</ul>
@@ -261,14 +358,16 @@
{% else %}
<div class="card">
<div class="card-body text-center py-5">
<i class="bi bi-trophy fs-1 text-muted mb-3"></i>
<h5 class="mb-2">Brak zbiórek zrealizowanych</h5>
<p class="text-muted mb-3">Gdy jakaś zbiórka osiągnie 100%, pojawi się tutaj.</p>
<a href="{{ url_for('formularz_zbiorek') }}" class="btn btn-outline-light">Utwórz nową
zbiórkę</a>
<a href="{{ url_for('formularz_zbiorek') }}" class="btn btn-outline-light">
<i class="bi bi-plus-circle"></i> Utwórz nową zbiórkę
</a>
</div>
</div>
{% endif %}
</div>
</div>
</div>
{% endblock %}
{% endblock %}

View File

@@ -3,141 +3,194 @@
{% block content %}
<div class="container my-4">
<!-- Nagłówek + akcje globalne -->
<div class="d-flex flex-wrap align-items-center justify-content-between gap-2 mb-4">
<h2 class="mb-0">Listy rezerwowe</h2>
<div>
<h2 class="mb-1">Listy rezerwowe</h2>
<p class="text-muted mb-0">Zarządzaj środkami rezerwowymi i nadpłatami</p>
</div>
<div class="d-flex flex-wrap gap-2">
<a href="{{ url_for('dodaj_rezerwe') }}" class="btn btn-primary">
Dodaj listę rezerwową
<i class="bi bi-plus-circle"></i> Dodaj listę
</a>
<a href="{{ url_for('admin_dashboard') }}" class="btn btn-outline-light">
Panel Admina
<i class="bi bi-arrow-left"></i> Panel Admina
</a>
</div>
</div>
<!-- Szybkie statystyki dla rezerw -->
{% if rezerwy %}
<div class="row g-3 mb-4">
<div class="col-md-4">
<div class="card border-info">
<div class="card-body text-center">
<i class="bi bi-wallet2 fs-1 text-info mb-2"></i>
<h3 class="mb-0">{{ rezerwy|length }}</h3>
<small class="text-muted">Aktywnych list</small>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card border-success">
<div class="card-body text-center">
<i class="bi bi-piggy-bank fs-1 text-success mb-2"></i>
<h3 class="mb-0">{{ "%.2f"|format(rezerwy|sum(attribute='stan')) }} zł</h3>
<small class="text-muted">Łączna rezerwa</small>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card border-warning">
<div class="card-body text-center">
<i class="bi bi-eye fs-1 text-warning mb-2"></i>
<h3 class="mb-0">{{ rezerwy|selectattr('ukryta', 'equalto', False)|list|length }}</h3>
<small class="text-muted">Widocznych publicznie</small>
</div>
</div>
</div>
</div>
{% endif %}
{% if rezerwy %}
<div class="table-responsive mb-5">
<table class="table table-dark table-striped table-hover align-middle">
<thead>
<tr>
<th style="width:72px;">ID</th>
<th>Nazwa</th>
<th style="width:140px;">Widoczność</th>
<th style="width:1%;">Opcje</th>
</tr>
</thead>
<tbody>
{% for r in rezerwy %}
<tr>
<td class="text-muted">{{ r.id }}</td>
<td>
<div class="d-flex flex-column">
<span class="fw-semibold">
<i class="bi bi-wallet2"></i> {{ r.nazwa }}
</span>
<small class="text-muted">
Stan: {{ r.stan|round(2) }} PLN
{% if r.opis %}
· {{ r.opis[:50] }}{% if r.opis|length > 50 %}...{% endif %}
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-dark table-striped table-hover align-middle mb-0">
<thead>
<tr>
<th style="width:72px;">ID</th>
<th>Nazwa</th>
<th class="text-end" style="width:150px;">Stan</th>
<th style="width:140px;">Widoczność</th>
<th style="width:1%;">Opcje</th>
</tr>
</thead>
<tbody>
{% for r in rezerwy %}
<tr>
<td class="text-muted">{{ r.id }}</td>
<td>
<div class="d-flex flex-column">
<a href="{{ url_for('zbiorka', zbiorka_id=r.id) }}" class="fw-semibold text-decoration-none">
<i class="bi bi-wallet2"></i> {{ r.nazwa }}
</a>
{% if r.opis %}
<small class="text-muted">
{{ r.opis[:60] }}{% if r.opis|length > 60 %}...{% endif %}
</small>
{% endif %}
</div>
</td>
<td class="text-end">
<strong class="text-success">{{ "%.2f"|format(r.stan) }} zł</strong>
</td>
<td>
{% if r.ukryta %}
<span class="badge bg-secondary border" style="border-color: var(--border);">
<i class="bi bi-eye-slash"></i> Ukryta
</span>
{% else %}
<span class="badge bg-success">
<i class="bi bi-eye"></i> Widoczna
</span>
{% endif %}
</small>
</div>
</td>
<td>
{% if r.ukryta %}
<span class="badge bg-secondary border" style="border-color: var(--border);">Ukryta</span>
{% else %}
<span class="badge bg-success">Widoczna</span>
{% endif %}
</td>
<td class="text-end">
<!-- Grupa akcji: główne + rozwijane -->
<div class="btn-group">
<a href="{{ url_for('edytuj_rezerwe', rezerwa_id=r.id) }}"
class="btn btn-sm btn-outline-light">Edytuj</a>
<button class="btn btn-sm btn-outline-light dropdown-toggle dropdown-toggle-split"
data-bs-toggle="dropdown" aria-expanded="false" aria-label="Więcej opcji">
<span class="visually-hidden">Więcej</span>
</button>
<ul class="dropdown-menu dropdown-menu-dark dropdown-menu-end shadow">
<li>
<a class="dropdown-item"
href="{{ url_for('zbiorka', zbiorka_id=r.id) }}">
<i class="bi bi-eye"></i> Otwórz
</td>
<td class="text-end">
<!-- Grupa akcji: główne + rozwijane -->
<div class="btn-group">
<a href="{{ url_for('edytuj_rezerwe', rezerwa_id=r.id) }}"
class="btn btn-sm btn-outline-light">
<i class="bi bi-pencil"></i> Edytuj
</a>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li>
<a class="dropdown-item"
href="{{ url_for('dodaj_wplate', zbiorka_id=r.id, next=url_for('zbiorka', zbiorka_id=r.id)) }}">
<i class="bi bi-plus-circle"></i> Dodaj wpłatę
</a>
</li>
<li>
<a class="dropdown-item"
href="{{ url_for('dodaj_wydatek', zbiorka_id=r.id, next=url_for('zbiorka', zbiorka_id=r.id)) }}">
<i class="bi bi-dash-circle"></i> Dodaj wydatek
</a>
</li>
<li>
<a class="dropdown-item"
href="{{ url_for('dodaj_przesuniecie', zbiorka_id=r.id, next=url_for('zbiorka', zbiorka_id=r.id)) }}">
<i class="bi bi-arrow-left-right"></i> Przesuń środki
</a>
</li>
<li>
<a class="dropdown-item"
href="{{ url_for('transakcje_zbiorki', zbiorka_id=r.id) }}">
<i class="bi bi-list-ul"></i> Transakcje
</a>
</li>
<li>
<a class="dropdown-item"
href="{{ url_for('edytuj_stan', zbiorka_id=r.id) }}">
<i class="bi bi-pencil-square"></i> Edytuj stan
</a>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li>
<form action="{{ url_for('zmien_widzialnosc', zbiorka_id=r.id) }}"
method="post" class="m-0">
<button type="submit" class="dropdown-item">
<i class="bi bi-eye{% if r.ukryta %}-slash{% endif %}"></i>
{% if r.ukryta %}Pokaż{% else %}Ukryj{% endif %}
</button>
</form>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li>
<form action="{{ url_for('usun_rezerwe', rezerwa_id=r.id) }}" method="post"
class="m-0"
onsubmit="return confirm('Czy na pewno usunąć listę \'{{ r.nazwa }}\'?\n\nUWAGA: Zostaną usunięte wszystkie transakcje powiązane z tą listą!');">
<button type="submit" class="dropdown-item text-danger">
<i class="bi bi-trash"></i> Usuń
</button>
</form>
</li>
</ul>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<button class="btn btn-sm btn-outline-light dropdown-toggle dropdown-toggle-split"
data-bs-toggle="dropdown" aria-expanded="false" aria-label="Więcej opcji">
<span class="visually-hidden">Więcej</span>
</button>
<ul class="dropdown-menu dropdown-menu-dark dropdown-menu-end shadow">
<li>
<a class="dropdown-item"
href="{{ url_for('zbiorka', zbiorka_id=r.id) }}">
<i class="bi bi-eye"></i> Podgląd
</a>
</li>
<li><hr class="dropdown-divider"></li>
<li>
<a class="dropdown-item"
href="{{ url_for('dodaj_wplate', zbiorka_id=r.id, next=url_for('zbiorka', zbiorka_id=r.id)) }}">
<i class="bi bi-plus-circle text-success"></i> Dodaj wpłatę
</a>
</li>
<li>
<a class="dropdown-item"
href="{{ url_for('dodaj_wydatek', zbiorka_id=r.id, next=url_for('zbiorka', zbiorka_id=r.id)) }}">
<i class="bi bi-dash-circle text-danger"></i> Dodaj wydatek
</a>
</li>
<li>
<a class="dropdown-item"
href="{{ url_for('dodaj_przesuniecie', zbiorka_id=r.id, next=url_for('zbiorka', zbiorka_id=r.id)) }}">
<i class="bi bi-arrow-left-right text-info"></i> Przesuń środki
</a>
</li>
<li><hr class="dropdown-divider"></li>
<li>
<a class="dropdown-item"
href="{{ url_for('transakcje_zbiorki', zbiorka_id=r.id) }}">
<i class="bi bi-list-ul"></i> Transakcje
</a>
</li>
<li>
<a class="dropdown-item"
href="{{ url_for('edytuj_stan', zbiorka_id=r.id) }}">
<i class="bi bi-currency-dollar"></i> Edytuj stan
</a>
</li>
<li><hr class="dropdown-divider"></li>
<li>
<form action="{{ url_for('zmien_widzialnosc', zbiorka_id=r.id) }}"
method="post" class="m-0">
<button type="submit" class="dropdown-item">
{% if r.ukryta %}
<i class="bi bi-eye"></i> Pokaż
{% else %}
<i class="bi bi-eye-slash"></i> Ukryj
{% endif %}
</button>
</form>
</li>
<li><hr class="dropdown-divider"></li>
<li>
<form action="{{ url_for('usun_rezerwe', rezerwa_id=r.id) }}" method="post"
class="m-0"
onsubmit="return confirm('Czy na pewno usunąć listę \'{{ r.nazwa }}\'?\n\nUWAGA: Zostaną usunięte wszystkie transakcje powiązane z tą listą!');">
<button type="submit" class="dropdown-item text-danger">
<i class="bi bi-trash"></i> Usuń
</button>
</form>
</li>
</ul>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% else %}
<!-- Empty state -->
<div class="card">
<div class="card-body text-center py-5">
<i class="bi bi-wallet2 fs-1 text-muted mb-3"></i>
<h5 class="mb-2">Brak list rezerwowych</h5>
<p class="text-muted mb-4">Nie masz jeszcze żadnych list rezerwowych. Utwórz pierwszą, aby zarządzać nadpłatami i środkami rezerwowymi.</p>
<a href="{{ url_for('dodaj_rezerwe') }}" class="btn btn-primary">Dodaj listę rezerwową</a>
<p class="text-muted mb-4">
Nie masz jeszcze żadnych list rezerwowych.<br>
Utwórz pierwszą, aby zarządzać nadpłatami i środkami rezerwowymi.
</p>
<a href="{{ url_for('dodaj_rezerwe') }}" class="btn btn-primary">
<i class="bi bi-plus-circle"></i> Dodaj listę rezerwową
</a>
</div>
</div>
{% endif %}

View File

@@ -0,0 +1,461 @@
{% extends 'base.html' %}
{% block title %}Statystyki - Panel Admina{% endblock %}
{% block content %}
<div class="container my-4">
<!-- Nagłówek + akcje globalne -->
<div class="d-flex flex-wrap align-items-center justify-content-between gap-2 mb-4">
<h2 class="mb-0">Statystyki systemu</h2>
<div class="d-flex flex-wrap gap-2">
<a href="{{ url_for('admin_dashboard') }}" class="btn btn-outline-light">
← Powrót do panelu
</a>
<a href="{{ url_for('admin_ustawienia') }}" class="btn btn-outline-light">
Ustawienia główne
</a>
</div>
</div>
<!-- KARTY PODSUMOWANIA -->
<div class="row g-3 mb-4">
<div class="col-md-3">
<div class="card border-success">
<div class="card-body text-center">
<h6 class="text-success mb-2">Suma wpłat</h6>
<h3 class="mb-1">{{ "%.2f"|format(total_wplaty) }} zł</h3>
<small class="text-muted">{{ liczba_wplat }} wpłat</small>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card border-danger">
<div class="card-body text-center">
<h6 class="text-danger mb-2">Suma wydatków</h6>
<h3 class="mb-1">{{ "%.2f"|format(total_wydatki) }} zł</h3>
<small class="text-muted">{{ liczba_wydatkow }} wydatków</small>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card border-info">
<div class="card-body text-center">
<h6 class="text-info mb-2">Suma przesunięć</h6>
<h3 class="mb-1">{{ "%.2f"|format(total_przesuniec) }} zł</h3>
<small class="text-muted">{{ liczba_przesuniec }} operacji</small>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card {% if bilans >= 0 %}border-success{% else %}border-danger{% endif %}">
<div class="card-body text-center">
<h6 class="{% if bilans >= 0 %}text-success{% else %}text-danger{% endif %} mb-2">Bilans</h6>
<h3 class="mb-1 {% if bilans >= 0 %}text-success{% else %}text-danger{% endif %}">
{{ "%.2f"|format(bilans) }} zł
</h3>
<small class="text-muted">{{ liczba_zbiorek }} zbiórek</small>
</div>
</div>
</div>
</div>
<!-- Pigułki: Podsumowanie / Aktywność / Miesięczne / Roczne -->
<ul class="nav nav-pills mb-3" id="statsTabs" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="tab-podsumowanie" data-bs-toggle="tab" data-bs-target="#pane-podsumowanie"
type="button" role="tab" aria-controls="pane-podsumowanie" aria-selected="true">
Podsumowanie
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="tab-aktywnosc" data-bs-toggle="tab" data-bs-target="#pane-aktywnosc"
type="button" role="tab" aria-controls="pane-aktywnosc" aria-selected="false">
Aktywność 7/30 dni
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="tab-miesieczne" data-bs-toggle="tab" data-bs-target="#pane-miesieczne"
type="button" role="tab" aria-controls="pane-miesieczne" aria-selected="false">
Miesięczne
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="tab-roczne" data-bs-toggle="tab" data-bs-target="#pane-roczne"
type="button" role="tab" aria-controls="pane-roczne" aria-selected="false">
Roczne
</button>
</li>
</ul>
<div class="tab-content">
<!-- PANE: Podsumowanie -->
<div class="tab-pane fade show active" id="pane-podsumowanie" role="tabpanel" aria-labelledby="tab-podsumowanie" tabindex="0">
<!-- Rekordy -->
<div class="row g-3 mb-4">
<div class="col-md-4">
<div class="card">
<div class="card-header bg-success text-white">
<h6 class="mb-0">Najwyższa wpłata</h6>
</div>
<div class="card-body">
{% if najwyzsza_wplata %}
<h4 class="mb-2">{{ "%.2f"|format(najwyzsza_wplata.kwota) }} zł</h4>
<p class="mb-1"><strong>Opis:</strong> {{ najwyzsza_wplata.opis or "Brak opisu" }}</p>
<p class="mb-1"><strong>Data:</strong> {{ najwyzsza_wplata.data.strftime('%d.%m.%Y') }}</p>
<p class="mb-0"><strong>Zbiórka:</strong>
<a href="{{ url_for('zbiorka', zbiorka_id=najwyzsza_wplata.zbiorka_id) }}" class="text-decoration-none">
{{ najwyzsza_wplata.zbiorka.nazwa }}
</a>
</p>
{% else %}
<p class="text-muted mb-0">Brak wpłat</p>
{% endif %}
</div>
</div>
</div>
<div class="col-md-4">
<div class="card">
<div class="card-header bg-danger text-white">
<h6 class="mb-0">Najwyższy wydatek</h6>
</div>
<div class="card-body">
{% if najwyzszy_wydatek %}
<h4 class="mb-2">{{ "%.2f"|format(najwyzszy_wydatek.kwota) }} zł</h4>
<p class="mb-1"><strong>Opis:</strong> {{ najwyzszy_wydatek.opis or "Brak opisu" }}</p>
<p class="mb-1"><strong>Data:</strong> {{ najwyzszy_wydatek.data.strftime('%d.%m.%Y') }}</p>
<p class="mb-0"><strong>Zbiórka:</strong>
<a href="{{ url_for('zbiorka', zbiorka_id=najwyzszy_wydatek.zbiorka_id) }}" class="text-decoration-none">
{{ najwyzszy_wydatek.zbiorka.nazwa }}
</a>
</p>
{% else %}
<p class="text-muted mb-0">Brak wydatków</p>
{% endif %}
</div>
</div>
</div>
<div class="col-md-4">
<div class="card">
<div class="card-header bg-info text-white">
<h6 class="mb-0">Średnie wartości</h6>
</div>
<div class="card-body">
<p class="mb-2"><strong>Średnia wpłata:</strong> {{ "%.2f"|format(srednia_wplata) }} zł</p>
<p class="mb-0"><strong>Średni wydatek:</strong> {{ "%.2f"|format(sredni_wydatek) }} zł</p>
</div>
</div>
</div>
</div>
<!-- Top 10 wpłat -->
<div class="card mb-4">
<div class="card-header" style="background: var(--accent); color: #111;">
<h6 class="mb-0">Top 10 najwyższych wpłat</h6>
</div>
<div class="card-body p-0">
{% if top_10_wplat %}
<div class="table-responsive">
<table class="table table-dark table-striped table-hover align-middle mb-0">
<thead>
<tr>
<th style="width:60px;">#</th>
<th>Kwota</th>
<th>Opis</th>
<th>Data</th>
<th>Zbiórka</th>
</tr>
</thead>
<tbody>
{% for wplata in top_10_wplat %}
<tr>
<td class="text-muted">{{ loop.index }}</td>
<td><strong class="text-success">{{ "%.2f"|format(wplata.kwota) }} zł</strong></td>
<td>{{ wplata.opis or "Brak opisu" }}</td>
<td class="text-muted">{{ wplata.data.strftime('%d.%m.%Y') }}</td>
<td>
<a href="{{ url_for('zbiorka', zbiorka_id=wplata.zbiorka_id) }}" class="text-decoration-none">
{{ wplata.zbiorka.nazwa }}
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="card-body text-center py-4">
<p class="text-muted mb-0">Brak danych</p>
</div>
{% endif %}
</div>
</div>
<!-- Top 5 zbiórek -->
<div class="card mb-4">
<div class="card-header bg-primary text-white">
<h6 class="mb-0">Top 5 zbiórek (największe wpłaty)</h6>
</div>
<div class="card-body p-0">
{% if top_zbiorki %}
<div class="table-responsive">
<table class="table table-dark table-striped table-hover align-middle mb-0">
<thead>
<tr>
<th style="width:60px;">#</th>
<th>Nazwa zbiórki</th>
<th class="text-end" style="width:180px;">Suma wpłat</th>
</tr>
</thead>
<tbody>
{% for zbiorka, suma in top_zbiorki %}
<tr>
<td class="text-muted">{{ loop.index }}</td>
<td>
<a href="{{ url_for('zbiorka', zbiorka_id=zbiorka.id) }}" class="text-decoration-none">
{{ zbiorka.nazwa }}
</a>
</td>
<td class="text-end"><strong>{{ "%.2f"|format(suma) }} zł</strong></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="card-body text-center py-4">
<p class="text-muted mb-0">Brak danych</p>
</div>
{% endif %}
</div>
</div>
<!-- Top 5 źródeł przesunięć -->
<div class="card">
<div class="card-header bg-info text-white">
<h6 class="mb-0">Top 5 źródeł przesunięć</h6>
</div>
<div class="card-body p-0">
{% if top_zrodla_przesuniec %}
<div class="table-responsive">
<table class="table table-dark table-striped table-hover align-middle mb-0">
<thead>
<tr>
<th style="width:60px;">#</th>
<th>Zbiórka źródłowa</th>
<th class="text-end">Liczba przesunięć</th>
<th class="text-end" style="width:180px;">Suma</th>
</tr>
</thead>
<tbody>
{% for nazwa, liczba, suma in top_zrodla_przesuniec %}
<tr>
<td class="text-muted">{{ loop.index }}</td>
<td>{{ nazwa }}</td>
<td class="text-end text-muted">{{ liczba }}</td>
<td class="text-end"><strong>{{ "%.2f"|format(suma) }} zł</strong></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="card-body text-center py-4">
<p class="text-muted mb-0">Brak przesunięć</p>
</div>
{% endif %}
</div>
</div>
</div>
<!-- PANE: Aktywność 7/30 dni -->
<div class="tab-pane fade" id="pane-aktywnosc" role="tabpanel" aria-labelledby="tab-aktywnosc" tabindex="0">
<div class="row g-3">
<!-- Ostatnie 7 dni -->
<div class="col-md-6">
<div class="card">
<div class="card-header bg-success text-white">
<h6 class="mb-0">Ostatnie 7 dni</h6>
</div>
<div class="card-body">
<h5 class="mb-3">Wpłaty</h5>
<p class="mb-1"><strong>Liczba:</strong> {{ wplaty_7dni.liczba or 0 }}</p>
<p class="mb-3"><strong>Suma:</strong> {{ "%.2f"|format(wplaty_7dni.suma or 0) }} zł</p>
<h5 class="mb-3">Wydatki</h5>
<p class="mb-1"><strong>Liczba:</strong> {{ wydatki_7dni.liczba or 0 }}</p>
<p class="mb-0"><strong>Suma:</strong> {{ "%.2f"|format(wydatki_7dni.suma or 0) }} zł</p>
</div>
</div>
</div>
<!-- Ostatnie 30 dni -->
<div class="col-md-6">
<div class="card">
<div class="card-header bg-primary text-white">
<h6 class="mb-0">Ostatnie 30 dni</h6>
</div>
<div class="card-body">
<h5 class="mb-3">Wpłaty</h5>
<p class="mb-1"><strong>Liczba:</strong> {{ wplaty_30dni.liczba or 0 }}</p>
<p class="mb-3"><strong>Suma:</strong> {{ "%.2f"|format(wplaty_30dni.suma or 0) }} zł</p>
<h5 class="mb-3">Wydatki</h5>
<p class="mb-1"><strong>Liczba:</strong> {{ wydatki_30dni.liczba or 0 }}</p>
<p class="mb-0"><strong>Suma:</strong> {{ "%.2f"|format(wydatki_30dni.suma or 0) }} zł</p>
</div>
</div>
</div>
</div>
</div>
<!-- PANE: Statystyki miesięczne -->
<div class="tab-pane fade" id="pane-miesieczne" role="tabpanel" aria-labelledby="tab-miesieczne" tabindex="0">
<div class="card">
<div class="card-header" style="background: var(--accent); color: #111;">
<h6 class="mb-0">Ostatnie 12 miesięcy</h6>
</div>
<div class="card-body p-0">
{% if wplaty_miesieczne or wydatki_miesieczne or przesuniecia_miesieczne %}
<div class="table-responsive">
<table class="table table-dark table-striped table-hover align-middle mb-0">
<thead>
<tr>
<th>Miesiąc</th>
<th class="text-end">Wpłaty (suma)</th>
<th class="text-end">Wpłaty (liczba)</th>
<th class="text-end">Wydatki (suma)</th>
<th class="text-end">Wydatki (liczba)</th>
<th class="text-end">Przesunięcia (suma)</th>
<th class="text-end">Bilans</th>
</tr>
</thead>
<tbody>
{% set wplaty_dict = {} %}
{% set wydatki_dict = {} %}
{% set przesuniecia_dict = {} %}
{% for rok, miesiac, suma, liczba in wplaty_miesieczne %}
{% set klucz = "%d-%02d"|format(rok|int, miesiac|int) %}
{% set _ = wplaty_dict.update({klucz: {'suma': suma, 'liczba': liczba}}) %}
{% endfor %}
{% for rok, miesiac, suma, liczba in wydatki_miesieczne %}
{% set klucz = "%d-%02d"|format(rok|int, miesiac|int) %}
{% set _ = wydatki_dict.update({klucz: {'suma': suma, 'liczba': liczba}}) %}
{% endfor %}
{% for rok, miesiac, suma, liczba in przesuniecia_miesieczne %}
{% set klucz = "%d-%02d"|format(rok|int, miesiac|int) %}
{% set _ = przesuniecia_dict.update({klucz: {'suma': suma, 'liczba': liczba}}) %}
{% endfor %}
{% set miesiace = (wplaty_dict.keys() | list + wydatki_dict.keys() | list + przesuniecia_dict.keys() | list) | unique | sort | reverse %}
{% for miesiac_key in miesiace %}
{% set wp = wplaty_dict.get(miesiac_key, {'suma': 0, 'liczba': 0}) %}
{% set wy = wydatki_dict.get(miesiac_key, {'suma': 0, 'liczba': 0}) %}
{% set pr = przesuniecia_dict.get(miesiac_key, {'suma': 0, 'liczba': 0}) %}
{% set bilans_m = wp.suma - wy.suma %}
<tr>
<td><strong>{{ miesiac_key }}</strong></td>
<td class="text-end text-success">{{ "%.2f"|format(wp.suma) }} zł</td>
<td class="text-end text-muted">{{ wp.liczba }}</td>
<td class="text-end text-danger">{{ "%.2f"|format(wy.suma) }} zł</td>
<td class="text-end text-muted">{{ wy.liczba }}</td>
<td class="text-end text-info">{{ "%.2f"|format(pr.suma) }} zł</td>
<td class="text-end {% if bilans_m >= 0 %}text-success{% else %}text-danger{% endif %}">
<strong>{{ "%.2f"|format(bilans_m) }} zł</strong>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="card-body text-center py-4">
<p class="text-muted mb-0">Brak danych</p>
</div>
{% endif %}
</div>
</div>
</div>
<!-- PANE: Statystyki roczne -->
<div class="tab-pane fade" id="pane-roczne" role="tabpanel" aria-labelledby="tab-roczne" tabindex="0">
<div class="card">
<div class="card-header bg-secondary text-white">
<h6 class="mb-0">Zestawienie roczne</h6>
</div>
<div class="card-body p-0">
{% if wplaty_roczne or wydatki_roczne %}
<div class="table-responsive">
<table class="table table-dark table-striped table-hover align-middle mb-0">
<thead>
<tr>
<th>Rok</th>
<th class="text-end">Wpłaty (suma)</th>
<th class="text-end">Wpłaty (liczba)</th>
<th class="text-end">Wydatki (suma)</th>
<th class="text-end">Wydatki (liczba)</th>
<th class="text-end">Bilans</th>
</tr>
</thead>
<tbody>
{% set wplaty_dict = {} %}
{% set wydatki_dict = {} %}
{% for rok, suma, liczba in wplaty_roczne %}
{% set _ = wplaty_dict.update({rok|int: {'suma': suma, 'liczba': liczba}}) %}
{% endfor %}
{% for rok, suma, liczba in wydatki_roczne %}
{% set _ = wydatki_dict.update({rok|int: {'suma': suma, 'liczba': liczba}}) %}
{% endfor %}
{% set lata = (wplaty_dict.keys() | list + wydatki_dict.keys() | list) | unique | sort | reverse %}
{% for rok in lata %}
{% set wp = wplaty_dict.get(rok, {'suma': 0, 'liczba': 0}) %}
{% set wy = wydatki_dict.get(rok, {'suma': 0, 'liczba': 0}) %}
{% set bilans_rok = wp.suma - wy.suma %}
<tr>
<td><strong>{{ rok|int }}</strong></td>
<td class="text-end text-success">{{ "%.2f"|format(wp.suma) }} zł</td>
<td class="text-end text-muted">{{ wp.liczba }}</td>
<td class="text-end text-danger">{{ "%.2f"|format(wy.suma) }} zł</td>
<td class="text-end text-muted">{{ wy.liczba }}</td>
<td class="text-end {% if bilans_rok >= 0 %}text-success{% else %}text-danger{% endif %}">
<strong>{{ "%.2f"|format(bilans_rok) }} zł</strong>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="card-body text-center py-4">
<p class="text-muted mb-0">Brak danych</p>
</div>
{% endif %}
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -3,14 +3,30 @@
{% block content %}
<div class="container my-4">
<!-- Nagłówek -->
<div class="d-flex flex-wrap align-items-center justify-content-between gap-2 mb-4">
<div>
<h2 class="mb-1">Ustawienia globalne</h2>
<p class="text-muted mb-0">Konfiguracja systemu, płatności i wyglądu</p>
</div>
<div class="d-flex flex-wrap gap-2">
<a href="{{ url_for('admin_statystyki') }}" class="btn btn-outline-light">
Statystyki
</a>
<a href="{{ url_for('admin_dashboard') }}" class="btn btn-outline-light">
← Panel Admina
</a>
</div>
</div>
<form method="post" novalidate id="form-global-settings">
{# {{ form.csrf_token }} jeśli używasz Flask-WTF #}
<!-- SEKCJA: Dane płatności -->
<div class="card shadow-sm mb-4">
<div class="card-header bg-secondary text-white d-flex align-items-center justify-content-between gap-2">
<h3 class="card-title mb-0">Dane płatności</h3>
<small class="opacity-75">Używane jako wartości domyślne przy dodawaniu/edycji zbiórek</small>
<small class="opacity-75">Wartości domyślne dla zbiórek</small>
</div>
<div class="card-body">
@@ -23,7 +39,7 @@
value="{{ settings.numer_konta if settings else '' }}" inputmode="numeric" autocomplete="off"
placeholder="12 3456 7890 1234 5678 9012 3456" required aria-describedby="ibanHelp">
</div>
<div id="ibanHelp" class="form-text">Wpisz ciąg cyfr — spacje dodadzą się automatycznie co 4 znaki.</div>
<div id="ibanHelp" class="form-text">Wpisz ciąg cyfr — spacje dodadzą się automatycznie co 4 znaki</div>
</div>
<div class="col-12 col-md-6">
@@ -34,7 +50,7 @@
value="{{ settings.numer_telefonu_blik if settings else '' }}" inputmode="tel" pattern="[0-9 ]{9,13}"
placeholder="123 456 789" required aria-describedby="blikHelp">
</div>
<div id="blikHelp" class="form-text">9 cyfr. Spacje i format 3-3-3 dodajemy dla czytelności.</div>
<div id="blikHelp" class="form-text">9 cyfr. Format 3-3-3 dla czytelności</div>
</div>
</div>
</div>
@@ -43,8 +59,8 @@
<!-- SEKCJA: Dostępy / biała lista IP -->
<div class="card shadow-sm mb-4">
<div class="card-header bg-secondary text-white d-flex align-items-center justify-content-between gap-2">
<h3 class="card-title mb-0">Dostęp — dozwolone adresy IP / hosty</h3>
<small class="opacity-75">Zależnie od konfiguracji logowanie może wymagać dopasowania do białej listy</small>
<h3 class="card-title mb-0">Kontrola dostępu</h3>
<small class="opacity-75">Biała lista IP/hostów dla logowania</small>
</div>
<div class="card-body">
@@ -59,16 +75,16 @@
Dodaj
</button>
</div>
<div id="hostAddHelp" class="form-text">Po wpisaniu kliknij „Dodaj. Duplikaty są pomijane.</div>
<div id="hostAddHelp" class="form-text">Po wpisaniu kliknij „Dodaj". Duplikaty są pomijane</div>
</div>
<div class="col-12 col-lg-4">
<div class="d-flex flex-wrap gap-2 justify-content-lg-end">
<button type="button" class="btn btn-light text-dark" id="btn-add-my-ip" data-my-ip="{{ client_ip }}">
<i class="fas fa-location-arrow"></i> Dodaj moje IP ({{ client_ip }})
Dodaj moje IP ({{ client_ip }})
</button>
<button type="button" class="btn btn-outline-light" id="btn-dedupe">
Usuń duplikaty
Usuń duplikaty
</button>
</div>
</div>
@@ -86,12 +102,37 @@
placeholder="Adresy IP lub nazwy domen — każdy w osobnej linii lub rozdzielony przecinkiem">{{ settings.dozwolone_hosty_logowania if settings and settings.dozwolone_hosty_logowania else '' }}</textarea>
<small class="text-muted d-block mt-1">
Akceptowane separatory: przecinek (`,`), średnik (`;`) i nowa linia.
Akceptowane separatory: przecinek (`,`), średnik (`;`) i nowa linia
</small>
</div>
</div>
</div>
<!-- SEKCJA: Kolejność list rezerwowych -->
<div class="card shadow-sm mb-4">
<div class="card-header bg-secondary text-white d-flex align-items-center justify-content-between gap-2">
<h3 class="card-title mb-0">Kolejność wyświetlania</h3>
<small class="opacity-75">Pozycja list rezerwowych na stronie głównej</small>
</div>
<div class="card-body">
<div class="mb-3">
<label for="kolejnosc_rezerwowych" class="form-label fw-semibold">Kolejność list rezerwowych</label>
<select class="form-select" id="kolejnosc_rezerwowych" name="kolejnosc_rezerwowych">
<option value="id" {% if settings and settings.kolejnosc_rezerwowych == 'id' %}selected{% endif %}>
Według ID (domyślnie)
</option>
<option value="first" {% if settings and settings.kolejnosc_rezerwowych == 'first' %}selected{% endif %}>
Jako pierwsze
</option>
<option value="last" {% if settings and settings.kolejnosc_rezerwowych == 'last' %}selected{% endif %}>
Jako ostatnie
</option>
</select>
<small class="text-muted d-block mt-1">Określa, gdzie na stronie głównej będą wyświetlane listy rezerwowe względem standardowych zbiórek</small>
</div>
</div>
</div>
<!-- SEKCJA: Branding -->
<div class="card shadow-sm mb-4">
@@ -107,7 +148,7 @@
<label for="logo_url" class="form-label">Logo (URL PNG/SVG)</label>
<input type="text" class="form-control" id="logo_url" name="logo_url"
value="{{ settings.logo_url if settings else '' }}" placeholder="https://example.com/logo.svg">
<div class="form-text">Transparentne, do ~60px wysokości.</div>
<div class="form-text">Transparentne, do ~60px wysokości</div>
{% if settings and settings.logo_url %}
<div class="mt-2">
<img src="{{ settings.logo_url }}" alt="Logo preview" style="max-height:50px">
@@ -140,7 +181,7 @@
%}checked{% endif %}>
<label class="form-check-label" for="navbar_mode_text">Pokaż tekst</label>
</div>
<div class="form-text mt-1">Jeśli wybierzesz logo, użyjemy adresu z pola "Tytuł serwisu".</div>
<div class="form-text mt-1">Jeśli wybierzesz logo, użyjemy adresu z pola "Logo URL"</div>
</div>
<!-- STOPKA -->
@@ -157,17 +198,16 @@
<label class="form-check-label" for="footer_mode_text">Tekst</label>
</div>
<label for="stopka_text" class="form-label mt-2">Tekst w stopce (gdy wybrano „Tekst)</label>
<label for="stopka_text" class="form-label mt-2">Tekst w stopce (gdy wybrano „Tekst")</label>
<input type="text" class="form-control" id="stopka_text" name="stopka_text"
value="{{ settings.stopka_text if settings and settings.stopka_text else '' }}"
placeholder="Np. © {{ now().year if now else '2025' }} Zbiórki">
<div class="form-text">Pozostaw pusty, by użyć domyślnego.</div>
<div class="form-text">Pozostaw pusty, by użyć domyślnego</div>
</div>
</div>
</div>
</div>
<!-- CTA -->
<div class="d-flex justify-content-between">
<a href="{{ url_for('admin_dashboard') }}" class="btn btn-outline-light">Powrót</a>
@@ -180,4 +220,4 @@
{% block extra_scripts %}
{{ super() }}
<script src="{{ url_for('static', filename='js/ustawienia.js') }}?v={{ APP_VERSION }}"></script>
{% endblock %}
{% endblock %}