4.2 KiB
4.2 KiB
PWA Frontend Integration for Fantasy Draft Games
Auth flow (index.html)
- Dual-mode form: Registration + Login toggled by
isLoginModeboolean - On success: Store token in
localStorage.getItem('shark_token'), user inlocalStorage.setItem('shark_user') - Post-auth:
GET /api/leagues— branch by count:- 0 leagues → show create/join UI
- 1 league → auto-redirect
draft-room.html?league_id=X - Multiple → show league picker
- Auth guard on every protected page:
if (!getToken()) window.location.href = 'index.html' - Register response:
{user_id, token, display_name}— backend must passdisplay_namefrom request
League management (index.html)
- Create:
POST /api/leagues {name}→ returns{id, invite_code} - Join:
POST /api/leagues/join {invite_code}→ returns{league_id, league_name} - Redirect after create/join:
window.location.href = 'draft-room.html?league_id=' + result.id
Draft room (draft-room.html)
League picker overlay
- GET
/api/leagueson load - If no
league_idURL param, show overlay with league cards - On select:
history.replaceState(null, '', '?league_id=' + id)+loadAll()
Data loading
async function loadAll() {
const [league, board, scores, regions] = await Promise.all([
apiCall('/api/leagues/' + leagueId),
apiCall('/api/leagues/' + leagueId + '/draft'),
apiCall('/api/leagues/' + leagueId + '/scores'),
apiCall('/api/regions'),
]);
renderAll();
}
Draft board tabs
- Draft tab: Region cards grid + status bar (round/turn info)
- Team tab: User's drafted regions + cumulative points
- Leaderboard tab: Ranked user list with scores
- League info tab: Invite code (copyable), member list, start draft (commissioner only)
Card states
- Available: teal border, "DRAFT" button
- Your pick: amber glow border + "⭐ YOUR PICK"
- Taken: grayed out, "Drafted by [player]"
- WAITING (draft not started): dimmed, "WAITING" label
Pitfalls
league_idfrom URL vs API: After creating a league, the API returnsresult.id, notresult.league_id. Useresult.idin redirect URL..hiddenCSS class: Every standalone page MUST define.hidden { display: none !important; }in its own<style>block. Sibling pages don't inherit it.- Overlay staying visible: Missing
.hiddenclass causes the league picker overlay to remain on screen after selecting a league — the JS adds the class but the browser has no matching CSS rule. - API calls that work from curl may fail from the browser if CORS headers are missing on the backend. FastAPI's
CORSMiddlewarewithallow_origins=["*"]fixes this during development. - Token expiry: JWT tokens set for 30 days. The frontend doesn't handle token refresh — if the token expires, the user gets "Invalid token" error and must re-login.
HTML table templates (score charts, stats)
When rendering leaderboard/team data as HTML inside JS template literals, use inline <table> elements matching the game's dark theme:
function renderLeaderboard(data) {
return `<table style="width:100%;border-collapse:collapse;font-size:13px;">
<tr style="background:rgba(15,23,42,0.8);">
<th style="padding:8px;text-align:left;font-weight:600;">Player</th>
<th style="padding:8px;text-align:center;font-weight:600;">Points</th>
</tr>
${data.map(p => `<tr>
<td style="padding:8px 10px;border-bottom:1px solid rgba(255,255,255,0.05);">${p.display_name}</td>
<td style="padding:8px 10px;text-align:center;border-bottom:1px solid rgba(255,255,255,0.05);color:var(--amber);">${p.total_points}</td>
</tr>`).join('')}
</table>`;
}
Common pitfalls
- Registration displays name as null — backend must include
display_name=req.display_namein AuthResponse (fix at/api/auth/registerendpoint) - Mobile Safari caching — after updating frontend files, users may see cached versions. Hard refresh or clear Safari cache is needed.
- League creation redirect — API returns
id, notleague_id. Useresult.id. - API call errors — Use try/catch + user-facing error messages. The
apiCall()helper throws on non-ok status codes.