zmiany ux i kodowe

This commit is contained in:
Mateusz Gruszczyński
2025-09-23 10:25:11 +02:00
parent 1a423a8b92
commit bbe318f995
12 changed files with 205 additions and 71 deletions

114
app.py
View File

@@ -1,3 +1,7 @@
import markdown as md
import hashlib, os
import re
import socket
from flask import Flask, render_template, request, redirect, url_for, flash from flask import Flask, render_template, request, redirect, url_for, flash
from flask_sqlalchemy import SQLAlchemy from flask_sqlalchemy import SQLAlchemy
from flask_login import ( from flask_login import (
@@ -11,29 +15,42 @@ from flask_login import (
from werkzeug.security import generate_password_hash, check_password_hash from werkzeug.security import generate_password_hash, check_password_hash
from datetime import datetime, timezone from datetime import datetime, timezone
from markupsafe import Markup from markupsafe import Markup
from sqlalchemy import event, Numeric from sqlalchemy import event, Numeric, select
from sqlalchemy.engine import Engine from sqlalchemy.engine import Engine
from decimal import Decimal, InvalidOperation from decimal import Decimal, InvalidOperation
import markdown as md
from flask import request, flash, abort from flask import request, flash, abort
import os try:
import re from zoneinfo import ZoneInfo # Python 3.9+
import socket except ImportError:
from backports.zoneinfo import ZoneInfo
def build_fingerprint(paths):
h = hashlib.sha256()
for base in paths:
if not os.path.exists(base):
continue
for root, _, files in os.walk(base):
for f in sorted(files):
p = os.path.join(root, f)
try:
with open(p, "rb") as fh:
h.update(fh.read())
except Exception:
continue
return h.hexdigest()[:8]
APP_VERSION = f"{datetime.now():%Y.%m.%d}+{build_fingerprint(['templates','static','app.py'])}"
app = Flask(__name__) app = Flask(__name__)
app.config['APP_VERSION'] = APP_VERSION
# Ładujemy konfigurację z pliku config.py # Ładujemy konfigurację z pliku config.py
app.config.from_object("config.Config") app.config.from_object("config.Config")
db = SQLAlchemy(app) db = SQLAlchemy(app)
login_manager = LoginManager(app) login_manager = LoginManager(app)
login_manager.login_view = "zaloguj" login_manager.login_view = "zaloguj"
try:
from zoneinfo import ZoneInfo # Python 3.9+
except ImportError:
from backports.zoneinfo import ZoneInfo
LOCAL_TZ = ZoneInfo("Europe/Warsaw") LOCAL_TZ = ZoneInfo("Europe/Warsaw")
@@ -143,7 +160,7 @@ class GlobalSettings(db.Model):
@login_manager.user_loader @login_manager.user_loader
def load_user(user_id): def load_user(user_id):
return User.query.get(int(user_id)) return db.session.get(User, int(user_id))
@event.listens_for(Engine, "connect") @event.listens_for(Engine, "connect")
@@ -235,6 +252,11 @@ def inject_globals():
} }
@app.context_processor
def inject_version():
return {'APP_VERSION': app.config['APP_VERSION']}
# TRASY PUBLICZNE # TRASY PUBLICZNE
@app.route("/") @app.route("/")
def index(): def index():
@@ -255,7 +277,9 @@ def page_not_found(e):
@app.route("/zbiorka/<int:zbiorka_id>") @app.route("/zbiorka/<int:zbiorka_id>")
def zbiorka(zbiorka_id): def zbiorka(zbiorka_id):
zb = Zbiorka.query.get_or_404(zbiorka_id) zb = db.session.get(Zbiorka, zbiorka_id)
if zb is None:
abort(404)
if zb.ukryta and (not current_user.is_authenticated or not current_user.is_admin): if zb.ukryta and (not current_user.is_authenticated or not current_user.is_admin):
abort(404) abort(404)
@@ -364,7 +388,9 @@ def formularz_zbiorek(zbiorka_id=None):
# Tryb # Tryb
is_edit = zbiorka_id is not None is_edit = zbiorka_id is not None
zb = Zbiorka.query.get_or_404(zbiorka_id) if is_edit else None zb = db.session.get(Zbiorka, zbiorka_id)
if zb is None:
abort(404)
global_settings = GlobalSettings.query.first() global_settings = GlobalSettings.query.first()
if request.method == "POST": if request.method == "POST":
@@ -498,7 +524,9 @@ def dodaj_wplate(zbiorka_id):
flash("Brak uprawnień", "danger") flash("Brak uprawnień", "danger")
return redirect(url_for("index")) return redirect(url_for("index"))
zb = Zbiorka.query.get_or_404(zbiorka_id) zb = db.session.get(Zbiorka, zbiorka_id) if is_edit else None
if is_edit and not zb:
abort(404)
if request.method == "POST": if request.method == "POST":
try: try:
@@ -527,7 +555,9 @@ def usun_zbiorka(zbiorka_id):
if not current_user.is_admin: if not current_user.is_admin:
flash("Brak uprawnień", "danger") flash("Brak uprawnień", "danger")
return redirect(url_for("index")) return redirect(url_for("index"))
zb = Zbiorka.query.get_or_404(zbiorka_id) zb = db.session.get(Zbiorka, zbiorka_id)
if zb is None:
abort(404)
db.session.delete(zb) db.session.delete(zb)
db.session.commit() db.session.commit()
flash("Zbiórka została usunięta", "success") flash("Zbiórka została usunięta", "success")
@@ -540,7 +570,9 @@ def edytuj_stan(zbiorka_id):
if not current_user.is_admin: if not current_user.is_admin:
flash("Brak uprawnień", "danger") flash("Brak uprawnień", "danger")
return redirect(url_for("index")) return redirect(url_for("index"))
zb = Zbiorka.query.get_or_404(zbiorka_id) zb = db.session.get(Zbiorka, zbiorka_id)
if zb is None:
abort(404)
if request.method == "POST": if request.method == "POST":
try: try:
nowy_stan = Decimal(request.form.get("stan", "").replace(",", ".")) nowy_stan = Decimal(request.form.get("stan", "").replace(",", "."))
@@ -560,7 +592,9 @@ def zmien_widzialnosc(zbiorka_id):
if not current_user.is_admin: if not current_user.is_admin:
flash("Brak uprawnień", "danger") flash("Brak uprawnień", "danger")
return redirect(url_for("index")) return redirect(url_for("index"))
zb = Zbiorka.query.get_or_404(zbiorka_id) zb = db.session.get(Zbiorka, zbiorka_id)
if zb is None:
abort(404)
zb.ukryta = not zb.ukryta zb.ukryta = not zb.ukryta
db.session.commit() db.session.commit()
flash("Zbiórka została " + ("ukryta" if zb.ukryta else "przywrócona"), "success") flash("Zbiórka została " + ("ukryta" if zb.ukryta else "przywrócona"), "success")
@@ -579,7 +613,6 @@ def create_admin_account():
@app.after_request @app.after_request
def apply_headers(response): def apply_headers(response):
# --- STATIC: jak wcześniej ---
if request.path.startswith("/static/"): if request.path.startswith("/static/"):
response.headers.pop("Content-Disposition", None) response.headers.pop("Content-Disposition", None)
response.headers["Vary"] = "Accept-Encoding" response.headers["Vary"] = "Accept-Encoding"
@@ -616,7 +649,7 @@ def apply_headers(response):
response.headers.pop("Vary", None) response.headers.pop("Vary", None)
else: else:
response.headers["Vary"] = "Cookie, Accept-Encoding" response.headers["Vary"] = "Cookie, Accept-Encoding"
default_cache = app.config.get("CACHE_CONTROL_HEADER") or "private, max-age=0" default_cache = app.config.get("CACHE_CONTROL_HEADER") or "private, no-store"
response.headers["Cache-Control"] = default_cache response.headers["Cache-Control"] = default_cache
if ( if (
@@ -694,7 +727,9 @@ def dodaj_wydatek(zbiorka_id):
flash("Brak uprawnień", "danger") flash("Brak uprawnień", "danger")
return redirect(url_for("index")) return redirect(url_for("index"))
zb = Zbiorka.query.get_or_404(zbiorka_id) zb = db.session.get(Zbiorka, zbiorka_id)
if zb is None:
abort(404)
if request.method == "POST": if request.method == "POST":
try: try:
@@ -734,7 +769,9 @@ def oznacz_zbiorka(zbiorka_id):
flash("Brak uprawnień do wykonania tej operacji", "danger") flash("Brak uprawnień do wykonania tej operacji", "danger")
return redirect(url_for("index")) return redirect(url_for("index"))
zb = Zbiorka.query.get_or_404(zbiorka_id) zb = db.session.get(Zbiorka, zbiorka_id)
if zb is None:
abort(404)
if "niezrealizowana" in request.path: if "niezrealizowana" in request.path:
zb.zrealizowana = False zb.zrealizowana = False
@@ -762,7 +799,9 @@ def robots():
def transakcje_zbiorki(zbiorka_id): def transakcje_zbiorki(zbiorka_id):
if not current_user.is_admin: if not current_user.is_admin:
flash("Brak uprawnień", "danger"); return redirect(url_for("index")) flash("Brak uprawnień", "danger"); return redirect(url_for("index"))
zb = Zbiorka.query.get_or_404(zbiorka_id) zb = db.session.get(Zbiorka, zbiorka_id)
if zb is None:
abort(404)
aktywnosci = ( aktywnosci = (
[{"typ": "wpłata", "id": w.id, "kwota": w.kwota, "opis": w.opis, "data": w.data} for w in zb.wplaty] + [{"typ": "wpłata", "id": w.id, "kwota": w.kwota, "opis": w.opis, "data": w.data} for w in zb.wplaty] +
[{"typ": "wydatek","id": x.id, "kwota": x.kwota,"opis": x.opis,"data": x.data} for x in zb.wydatki] [{"typ": "wydatek","id": x.id, "kwota": x.kwota,"opis": x.opis,"data": x.data} for x in zb.wydatki]
@@ -776,7 +815,9 @@ def transakcje_zbiorki(zbiorka_id):
def zapisz_wplate(wplata_id): def zapisz_wplate(wplata_id):
if not current_user.is_admin: if not current_user.is_admin:
flash("Brak uprawnień", "danger"); return redirect(url_for("index")) flash("Brak uprawnień", "danger"); return redirect(url_for("index"))
w = Wplata.query.get_or_404(wplata_id) w = db.session.get(Wplata, wplata_id)
if w is None:
abort(404)
zb = w.zbiorka zb = w.zbiorka
try: try:
nowa_kwota = Decimal(request.form.get("kwota", "").replace(",", ".")) nowa_kwota = Decimal(request.form.get("kwota", "").replace(",", "."))
@@ -800,7 +841,9 @@ def zapisz_wplate(wplata_id):
def usun_wplate(wplata_id): def usun_wplate(wplata_id):
if not current_user.is_admin: if not current_user.is_admin:
flash("Brak uprawnień", "danger"); return redirect(url_for("index")) flash("Brak uprawnień", "danger"); return redirect(url_for("index"))
w = Wplata.query.get_or_404(wplata_id) w = db.session.get(Wplata, wplata_id)
if w is None:
abort(404)
zb = w.zbiorka zb = w.zbiorka
zb.stan -= w.kwota zb.stan -= w.kwota
db.session.delete(w) db.session.delete(w)
@@ -814,7 +857,9 @@ def usun_wplate(wplata_id):
def zapisz_wydatek(wydatek_id): def zapisz_wydatek(wydatek_id):
if not current_user.is_admin: if not current_user.is_admin:
flash("Brak uprawnień", "danger"); return redirect(url_for("index")) flash("Brak uprawnień", "danger"); return redirect(url_for("index"))
x = Wydatek.query.get_or_404(wydatek_id) x = db.session.get(Wydatek, wydatek_id)
if x is None:
abort(404)
zb = x.zbiorka zb = x.zbiorka
try: try:
nowa_kwota = Decimal(request.form.get("kwota", "").replace(",", ".")) nowa_kwota = Decimal(request.form.get("kwota", "").replace(",", "."))
@@ -839,7 +884,9 @@ def zapisz_wydatek(wydatek_id):
def usun_wydatek(wydatek_id): def usun_wydatek(wydatek_id):
if not current_user.is_admin: if not current_user.is_admin:
flash("Brak uprawnień", "danger"); return redirect(url_for("index")) flash("Brak uprawnień", "danger"); return redirect(url_for("index"))
x = Wydatek.query.get_or_404(wydatek_id) x = db.session.get(Wydatek, wydatek_id)
if x is None:
abort(404)
zb = x.zbiorka zb = x.zbiorka
zb.stan += x.kwota zb.stan += x.kwota
db.session.delete(x) db.session.delete(x)
@@ -867,9 +914,16 @@ if __name__ == "__main__":
with app.app_context(): with app.app_context():
db.create_all() db.create_all()
# Tworzenie konta głównego admina, jeśli nie istnieje # Tworzenie konta głównego admina, jeśli nie istnieje
if not User.query.filter_by(is_admin=True).first(): stmt = select(User).filter_by(is_admin=True)
main_admin = User(username=app.config["MAIN_ADMIN_USERNAME"], is_admin=True) admin = db.session.execute(stmt).scalars().first()
if not admin:
main_admin = User(
username=app.config["MAIN_ADMIN_USERNAME"],
is_admin=True
)
main_admin.set_password(app.config["MAIN_ADMIN_PASSWORD"]) main_admin.set_password(app.config["MAIN_ADMIN_PASSWORD"])
db.session.add(main_admin) db.session.add(main_admin)
db.session.commit() db.session.commit()
app.run(debug=True) app.run(debug=True)

View File

@@ -14,11 +14,26 @@
<h3 class="card-title mb-0">Dodaj wpłatę: <span class="fw-semibold">{{ zbiorka.nazwa }}</span></h3> <h3 class="card-title mb-0">Dodaj wpłatę: <span class="fw-semibold">{{ zbiorka.nazwa }}</span></h3>
<div class="d-flex align-items-center gap-2"> <div class="d-flex align-items-center gap-2">
{% if zbiorka.cel %} {% if zbiorka.cel %}
<span class="badge bg-dark border" style="border-color: var(--border);">Cel: {{ zbiorka.cel|round(2) }} <span class="badge bg-dark border" style="border-color: var(--border);">
PLN</span> Cel: {{ zbiorka.cel|round(2) }} PLN
</span>
{% endif %}
<span class="badge bg-dark border" style="border-color: var(--border);">
Stan: {{ zbiorka.stan|round(2) }} PLN
</span>
{% if zbiorka.cel and zbiorka.cel > 0 %}
{% set delta = zbiorka.cel - zbiorka.stan %}
{% if delta > 0 %}
<span class="badge bg-dark border" style="border-color: var(--border);">
Brakuje: {{ delta|round(2) }} PLN
</span>
{% else %}
<span class="badge bg-dark border" style="border-color: var(--border);">
Nadwyżka: {{ (-delta)|round(2) }} PLN
</span>
{% endif %}
{% endif %} {% endif %}
<span class="badge bg-dark border" style="border-color: var(--border);">Stan: {{ zbiorka.stan|round(2) }}
PLN</span>
</div> </div>
</div> </div>
@@ -82,5 +97,5 @@
{% endblock %} {% endblock %}
{% block extra_scripts %} {% block extra_scripts %}
{{ super() }} {{ super() }}
<script src="{{ url_for('static', filename='js/dodaj_wplate.js') }}"></script> <script src="{{ url_for('static', filename='js/dodaj_wplate.js') }}?v={{ APP_VERSION }}"></script>
{% endblock %} {% endblock %}

View File

@@ -13,14 +13,30 @@
<div <div
class="card-header bg-secondary text-white d-flex flex-wrap align-items-center justify-content-between gap-2"> class="card-header bg-secondary text-white d-flex flex-wrap align-items-center justify-content-between gap-2">
<h3 class="card-title mb-0">Dodaj wydatek: <span class="fw-semibold">{{ zbiorka.nazwa }}</span></h3> <h3 class="card-title mb-0">Dodaj wydatek: <span class="fw-semibold">{{ zbiorka.nazwa }}</span></h3>
<div class="d-flex align-items-center gap-2"> <div class="d-flex align-items-center flex-wrap gap-2">
{% if zbiorka.cel %} {% if has_cel %}
<span class="badge bg-dark border" style="border-color: var(--border);">Cel: {{ zbiorka.cel|round(2) }} <span class="badge bg-dark border" style="border-color: var(--border);">
PLN</span> Cel: {{ zbiorka.cel|round(2) }} PLN
</span>
{% endif %}
<span class="badge bg-dark border" style="border-color: var(--border);">
Obecnie: {{ zbiorka.stan|round(2) }} PLN
</span>
{% if has_cel %}
{% set delta = zbiorka.cel - zbiorka.stan %}
{% if delta > 0 %}
<span class="badge bg-dark border" style="border-color: var(--border);">
Brakuje: {{ delta|round(2) }} PLN
</span>
{% else %}
<span class="badge bg-dark border" style="border-color: var(--border);">
Nadwyżka: {{ (-delta)|round(2) }} PLN
</span>
{% endif %}
{% endif %} {% endif %}
<span class="badge bg-dark border" style="border-color: var(--border);">Stan: {{ zbiorka.stan|round(2)
}} PLN</span>
</div> </div>
</div> </div>
<div class="card-body"> <div class="card-body">
@@ -59,5 +75,5 @@
{% block extra_scripts %} {% block extra_scripts %}
{{ super() }} {{ super() }}
<script src="{{ url_for('static', filename='js/dodaj_wydatek.js') }}"></script> <script src="{{ url_for('static', filename='js/dodaj_wydatek.js') }}?v={{ APP_VERSION }}"></script>
{% endblock %} {% endblock %}

View File

@@ -20,11 +20,26 @@
<h3 class="card-title mb-0">Edytuj stan: <span class="fw-semibold">{{ zbiorka.nazwa }}</span></h3> <h3 class="card-title mb-0">Edytuj stan: <span class="fw-semibold">{{ zbiorka.nazwa }}</span></h3>
<div class="d-flex align-items-center flex-wrap gap-2"> <div class="d-flex align-items-center flex-wrap gap-2">
{% if has_cel %} {% if has_cel %}
<span class="badge bg-dark border" style="border-color: var(--border);">Cel: {{ zbiorka.cel|round(2) }} <span class="badge bg-dark border" style="border-color: var(--border);">
PLN</span> Cel: {{ zbiorka.cel|round(2) }} PLN
</span>
{% endif %}
<span class="badge bg-dark border" style="border-color: var(--border);">
Obecnie: {{ zbiorka.stan|round(2) }} PLN
</span>
{% if has_cel %}
{% set delta = zbiorka.cel - zbiorka.stan %}
{% if delta > 0 %}
<span class="badge bg-dark border" style="border-color: var(--border);">
Brakuje: {{ delta|round(2) }} PLN
</span>
{% else %}
<span class="badge bg-dark border" style="border-color: var(--border);">
Nadwyżka: {{ (-delta)|round(2) }} PLN
</span>
{% endif %}
{% endif %} {% endif %}
<span class="badge bg-dark border" style="border-color: var(--border);">Obecnie: {{ zbiorka.stan|round(2) }}
PLN</span>
</div> </div>
</div> </div>
@@ -124,5 +139,5 @@
{% block extra_scripts %} {% block extra_scripts %}
{{ super() }} {{ super() }}
<script src="{{ url_for('static', filename='js/edytuj_stan.js') }}"></script> <script src="{{ url_for('static', filename='js/edytuj_stan.js') }}?v={{ APP_VERSION }}"></script>
{% endblock %} {% endblock %}

View File

@@ -37,15 +37,35 @@
Cel: {{ zbiorka.cel|round(2) }} PLN Cel: {{ zbiorka.cel|round(2) }} PLN
</span> </span>
{% endif %} {% endif %}
{% if zbiorka.ukryj_kwote %}
<span class="badge bg-secondary">Kwoty ukryte</span> {% if not zbiorka.ukryj_kwote %}
{% else %} <span class="badge bg-dark border" style="border-color: var(--border);">
<span class="badge bg-success">Kwoty widoczne</span> Stan: {{ zbiorka.stan|round(2) }} PLN
{% endif %} </span>
{% if zbiorka.cel %}
{% set delta = zbiorka.cel - zbiorka.stan %}
{% if delta > 0 %}
<span class="badge bg-dark border" style="border-color: var(--border);">
Brakuje: {{ delta|round(2) }} PLN
</span>
{% elif delta < 0 %} <span class="badge bg-dark border" style="border-color: var(--border);">
Nadwyżka: {{ (-delta)|round(2) }} PLN
</span>
{% endif %}
{% endif %}
{% endif %}
{% if zbiorka.ukryj_kwote %}
<span class="badge bg-secondary">Kwoty niepubliczne</span>
{% else %}
<span class="badge bg-success">Kwoty widoczne</span>
{% endif %}
</div> </div>
{% else %} {% else %}
<small class="opacity-75">Uzupełnij podstawowe dane i dane płatności</small> <small class="opacity-75">Uzupełnij podstawowe dane i dane płatności</small>
{% endif %} {% endif %}
</div> </div>
<div class="card-body"> <div class="card-body">
@@ -82,10 +102,10 @@
<!-- SEKCJA: Lista produktów --> <!-- SEKCJA: Lista produktów -->
<div class="mb-4"> <div class="mb-4">
<h6 class="text-muted mb-2">Lista produktów</h6> <h6 class="text-muted mb-2">Lista produktów / Pozycje / Cele</h6>
<p class="text-muted small mb-3"> <p class="text-muted small mb-3">
Wypunktuj dokładnie produkty do zakupu — podaj nazwę, opcjonalny link do sklepu i cenę. Wypunktuj dokładnie produkty do zakupu — podaj nazwę, opcjonalny link do sklepu i cenę.
Status domyślnie <em>Do kupienia</em>; przełącz na <em>Kupione</em> po realizacji. Status domyślnie <code>Do kupienia</code>; przełącz na <code>Kupione</code> po realizacji.
</p> </p>
<div class="table-responsive"> <div class="table-responsive">
@@ -221,7 +241,6 @@
<div class="mb-4"> <div class="mb-4">
<h6 class="text-muted mb-2">Cel i widoczność</h6> <h6 class="text-muted mb-2">Cel i widoczność</h6>
{# === BOX: zgodność sumy produktów z celem === #}
<div id="celSyncBox" class="alert d-none py-2 px-3 mb-3" role="alert"> <div id="celSyncBox" class="alert d-none py-2 px-3 mb-3" role="alert">
<div class="d-flex flex-wrap align-items-center justify-content-between gap-2"> <div class="d-flex flex-wrap align-items-center justify-content-between gap-2">
<div id="celSyncMsg" class="small"></div> <div id="celSyncMsg" class="small"></div>
@@ -268,8 +287,8 @@
{% block extra_scripts %} {% block extra_scripts %}
{{ super() }} {{ super() }}
<script src="https://cdn.jsdelivr.net/simplemde/latest/simplemde.min.js"></script> <script src="https://cdn.jsdelivr.net/simplemde/latest/simplemde.min.js"></script>
<script src="{{ url_for('static', filename='js/mde_custom.js') }}"></script> <script src="{{ url_for('static', filename='js/mde_custom.js') }}?v={{ APP_VERSION }}"></script>
<script src="{{ url_for('static', filename='js/formularz_zbiorek.js') }}"></script> <script src="{{ url_for('static', filename='js/formularz_zbiorek.js') }}?v={{ APP_VERSION }}"></script>
<script src="{{ url_for('static', filename='js/produkty_formularz.js') }}"></script> <script src="{{ url_for('static', filename='js/produkty_formularz.js') }}?v={{ APP_VERSION }}"></script>
<script src="{{ url_for('static', filename='js/kwoty_formularz.js') }}"></script> <script src="{{ url_for('static', filename='js/kwoty_formularz.js') }}?v={{ APP_VERSION }}"></script>
{% endblock %} {% endblock %}

View File

@@ -139,5 +139,5 @@
{% block extra_scripts %} {% block extra_scripts %}
{{ super() }} {{ super() }}
<script src="{{ url_for('static', filename='js/transakcje.js') }}"></script> <script src="{{ url_for('static', filename='js/transakcje.js') }}?v={{ APP_VERSION }}"></script>
{% endblock %} {% endblock %}

View File

@@ -162,5 +162,5 @@
{% block extra_scripts %} {% block extra_scripts %}
{{ super() }} {{ super() }}
<script src="{{ url_for('static', filename='js/ustawienia.js') }}"></script> <script src="{{ url_for('static', filename='js/ustawienia.js') }}?v={{ APP_VERSION }}"></script>
{% endblock %} {% endblock %}

View File

@@ -6,7 +6,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" /> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<title>{% block title %}Aplikacja Zbiórek{% endblock %}</title> <title>{% block title %}Aplikacja Zbiórek{% endblock %}</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootswatch@5.3.0/dist/darkly/bootstrap.min.css"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootswatch@5.3.0/dist/darkly/bootstrap.min.css">
<link rel="stylesheet" href="{{ url_for('static', filename='css/custom.css') }}" /> <link rel="stylesheet" href="{{ url_for('static', filename='css/custom.css') }}?v={{ APP_VERSION }}" />
{% block extra_head %}{% endblock %} {% block extra_head %}{% endblock %}
</head> </head>
@@ -80,10 +80,12 @@
{{ global_settings.footer_text if global_settings and global_settings.footer_text else "© " ~ (now().year if now {{ global_settings.footer_text if global_settings and global_settings.footer_text else "© " ~ (now().year if now
else '2025') ~ " linuxiarz.pl" }} else '2025') ~ " linuxiarz.pl" }}
{% endif %} {% endif %}
<div class="small text-muted">v{{ APP_VERSION }}</div>
</footer> </footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="{{ url_for('static', filename='js/progress.js') }}"></script> <script src="{{ url_for('static', filename='js/progress.js') }}?v={{ APP_VERSION }}"></script>
{% block extra_scripts %}{% endblock %} {% block extra_scripts %}{% endblock %}
</body> </body>

View File

@@ -49,11 +49,24 @@ zbiórki{% endif %}{% endblock %}
<span class="badge bg-dark border" style="border-color: var(--border);"> <span class="badge bg-dark border" style="border-color: var(--border);">
Stan: {{ z.stan|round(2) }} PLN Stan: {{ z.stan|round(2) }} PLN
</span> </span>
{% else %}
<span class="badge bg-secondary">Kwoty ukryte</span> {% if z.cel > 0 %}
{% endif %} {% set delta = z.cel - z.stan %}
{% if delta > 0 %}
<span class="badge bg-dark border" style="border-color: var(--border);">
Brakuje: {{ delta|round(2) }} PLN
</span>
{% elif delta < 0 %} <span class="badge bg-dark border" style="border-color: var(--border);">
Nadwyżka: {{ (-delta)|round(2) }} PLN
</span>
{% endif %}
{% endif %}
{% else %}
<span class="badge bg-secondary">Kwoty niepubliczne</span>
{% endif %}
</div> </div>
<div class="mb-1"> <div class="mb-1">
<div class="progress" role="progressbar" aria-valuemin="0" aria-valuemax="100" <div class="progress" role="progressbar" aria-valuemin="0" aria-valuemax="100"
aria-valuenow="{{ progress_clamped|round(2) if not z.ukryj_kwote else '' }}" aria-valuenow="{{ progress_clamped|round(2) if not z.ukryj_kwote else '' }}"

View File

@@ -51,5 +51,5 @@
{% endblock %} {% endblock %}
{% block extra_scripts %} {% block extra_scripts %}
<script src="{{ url_for('static', filename='js/walidacja_logowanie.js') }}"></script> <script src="{{ url_for('static', filename='js/walidacja_logowanie.js') }}?v={{ APP_VERSION }}"></script>
{% endblock %} {% endblock %}

View File

@@ -57,5 +57,5 @@
{% endblock %} {% endblock %}
{% block extra_scripts %} {% block extra_scripts %}
<script src="{{ url_for('static', filename='js/walidacja_rejestracja.js') }}"></script> <script src="{{ url_for('static', filename='js/walidacja_rejestracja.js') }}?v={{ APP_VERSION }}"></script>
{% endblock %} {% endblock %}

View File

@@ -18,7 +18,7 @@
<span class="badge rounded-pill" style="background: var(--accent); color:#111;">Zrealizowana</span> <span class="badge rounded-pill" style="background: var(--accent); color:#111;">Zrealizowana</span>
{% endif %} {% endif %}
{% if zbiorka.ukryj_kwote %} {% if zbiorka.ukryj_kwote %}
<span class="badge bg-secondary">Kwoty ukryte</span> <span class="badge bg-secondary">Kwoty niepubliczne</span>
{% else %} {% else %}
<span class="badge bg-success">Kwoty widoczne</span> <span class="badge bg-success">Kwoty widoczne</span>
{% endif %} {% endif %}
@@ -264,6 +264,6 @@
{% block extra_scripts %} {% block extra_scripts %}
{{ super() }} {{ super() }}
<script src="{{ url_for('static', filename='js/zbiorka.js') }}"></script> <script src="{{ url_for('static', filename='js/zbiorka.js') }}?v={{ APP_VERSION }}"></script>
<script src="{{ url_for('static', filename='js/progress.js') }}"></script> <script src="{{ url_for('static', filename='js/progress.js') }}?v={{ APP_VERSION }}"></script>
{% endblock %} {% endblock %}