84 lines
4.2 KiB
Markdown
84 lines
4.2 KiB
Markdown
# PWA Frontend Integration for Fantasy Draft Games
|
|
|
|
## Auth flow (index.html)
|
|
|
|
1. **Dual-mode form:** Registration + Login toggled by `isLoginMode` boolean
|
|
2. **On success:** Store token in `localStorage.getItem('shark_token')`, user in `localStorage.setItem('shark_user')`
|
|
3. **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
|
|
4. **Auth guard** on every protected page: `if (!getToken()) window.location.href = 'index.html'`
|
|
5. **Register response:** `{user_id, token, display_name}` — backend must pass `display_name` from 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/leagues` on load
|
|
- If no `league_id` URL param, show overlay with league cards
|
|
- On select: `history.replaceState(null, '', '?league_id=' + id)` + `loadAll()`
|
|
|
|
### Data loading
|
|
```javascript
|
|
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_id` from URL vs API:** After creating a league, the API returns `result.id`, not `result.league_id`. Use `result.id` in redirect URL.
|
|
- **`.hidden` CSS 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 `.hidden` class 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 `CORSMiddleware` with `allow_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:
|
|
|
|
```javascript
|
|
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_name` in AuthResponse (fix at `/api/auth/register` endpoint)
|
|
- **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`, not `league_id`. Use `result.id`.
|
|
- **API call errors** — Use try/catch + user-facing error messages. The `apiCall()` helper throws on non-ok status codes.
|