CRISIS FIX: login flow + mobile responsive + token expiry handling
ROOT CAUSE ISOLATED:
Backend POST /api/auth/login, GET/PUT /api/auth/me, POST avatar, POST /logout
all return 200 OK (verified curl). Damirov problem is browser-side:
stale localStorage tokens that don't match current backend → 401 cascade
→ avatar upload appears as 'failed: 401' → profile changes 'lost'.
FIXES:
1. apiAuth() in app.html now:
- Pre-checks JWT exp claim before request
- On 401 response: clears localStorage (pgz_access/refresh/user) +
redirects to /login?reason=unauthorized
- On JWT expired: redirects to /login?reason=expired
2. login.html displays toast for ?reason=expired/unauthorized
3. Mobile responsive CSS (max-width: 768px):
- app.html: hamburger menu, sidebar slide-in, full-width drill-down panel
- sport2.html: KPI grid 2-col, klubovi 1-col, tables horizontal scroll
- Both: viewport meta + media queries + touch-friendly buttons
4. Mobile menu toggle button + backdrop overlay added
VERIFIED E2E (curl):
- POST /auth/login → 200 + JWT
- GET /auth/me → 200 + telefon persisted
- PUT /auth/me → 200, DB row updated
- POST /auth/me/avatar → 200, file saved + avatar_url returned
- POST /auth/logout → 200, token revoked (next /me returns 401)
This commit is contained in:
@@ -185,6 +185,7 @@ table tbody tr.no-click:hover{background:transparent}
|
||||
.pp-stats{grid-template-columns:repeat(3,1fr)}
|
||||
}
|
||||
</style>
|
||||
<script src="/static/oib_format.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -580,7 +581,7 @@ async function openSavez(id){
|
||||
<div class="card">
|
||||
<div class="card-h"><div class="card-t">📋 Osnovne informacije</div></div>
|
||||
<div class="kv">
|
||||
<div class="k">OIB</div><div class="v">${txt(s.oib)}</div>
|
||||
<div class="k">OIB</div><div class="v">${s.oib?formatOib(s.oib,{savez_id:s.id}):'—'}</div>
|
||||
<div class="k">Adresa</div><div class="v">${txt(s.adresa)}</div>
|
||||
<div class="k">Predsjednik</div><div class="v">${txt(s.predsjednik)}</div>
|
||||
<div class="k">Tajnik</div><div class="v">${txt(s.tajnik)}</div>
|
||||
@@ -742,7 +743,7 @@ async function openKlub(id){
|
||||
<div id="k-info" class="ktab">
|
||||
<div class="kv">
|
||||
<div class="k">Naziv</div><div class="v">${esc(k.naziv||'')}</div>
|
||||
<div class="k">OIB</div><div class="v">${txt(k.oib)}</div>
|
||||
<div class="k">OIB</div><div class="v">${k.oib?formatOib(k.oib,{klub_id:k.id,savez_id:k.savez_id}):'—'}</div>
|
||||
<div class="k">Sport</div><div class="v">${txt(k.sport)}</div>
|
||||
<div class="k">Razina</div><div class="v">${txt(k.razina)}</div>
|
||||
<div class="k">Savez</div><div class="v">${txt(k.savez_naziv)}</div>
|
||||
@@ -992,7 +993,7 @@ async function openSportas(id){
|
||||
|
||||
<div id="p-bio" class="ptab" style="display:none">
|
||||
<div class="kv">
|
||||
<div class="k">OIB</div><div class="v">${txt(d.oib)}</div>
|
||||
<div class="k">OIB</div><div class="v">${d.oib?formatOib(d.oib,{klub_id:d.klub_id,savez_id:d.savez_id}):'—'}</div>
|
||||
<div class="k">Datum rođenja</div><div class="v">${fmtDate(dob)}</div>
|
||||
<div class="k">Mjesto rođenja</div><div class="v">${txt(d.mjesto_rodjenja||d.mjesto_rodenja)}</div>
|
||||
<div class="k">Spol</div><div class="v">${txt(d.spol)}</div>
|
||||
@@ -1253,7 +1254,7 @@ function openObjekt(id){
|
||||
<div class="k">Adresa</div><div class="v">${txt(o.adresa)}</div>
|
||||
<div class="k">Grad</div><div class="v">${txt(o.grad)}</div>
|
||||
<div class="k">Upravitelj</div><div class="v">${txt(o.upravitelj)}</div>
|
||||
<div class="k">OIB</div><div class="v">${txt(o.upravitelj_oib)}</div>
|
||||
<div class="k">OIB</div><div class="v">${o.upravitelj_oib?formatOib(o.upravitelj_oib):'—'}</div>
|
||||
<div class="k">Kapacitet</div><div class="v">${o.kapacitet?fmtNum(o.kapacitet)+' mjesta':'—'}</div>
|
||||
<div class="k">Veličina</div><div class="v">${txt(o.veličina)}</div>
|
||||
<div class="k">Sportovi</div><div class="v">${(o.sportovi||[]).map(s=>'<span class="tag b">'+esc(s)+'</span>').join(' ')||'—'}</div>
|
||||
|
||||
Reference in New Issue
Block a user