Fase 2 (isla): selector de cuenta de juego en React/TSX, sin POST
El selector de cuenta de juego (bnet con varias) pasa a isla React y la selección
se hace vía GET (a petición), no POST:
- Nuevo endpoint GET /api/account/select/?account_id=<id> (account_select_api):
idempotente y solo permite elegir cuentas ligadas a la bnet en sesión; fija la
cuenta en sesión y devuelve {success, redirect}. 401 si no hay sesión bnet.
- select_account_view: se elimina el manejo de POST (queda solo la lógica GET:
redirect si no hay bnet, autoseleccionar si hay una, render si hay varias).
- SelectAccount.tsx lee las cuentas embebidas con json_script y, al pulsar, hace
fetch GET y redirige. Nueva entry 'select_account'.
- select_account.html: el <form> POST se sustituye por la isla + json_script.
Verificado: check OK, endpoint 401 sin sesión, /select-account/ redirige a login.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
import { useState } from 'react'
|
||||
|
||||
export interface GameAccount {
|
||||
id: number
|
||||
username: string
|
||||
index: number
|
||||
}
|
||||
|
||||
interface Props {
|
||||
accounts: GameAccount[]
|
||||
selectUrl: string
|
||||
}
|
||||
|
||||
export function SelectAccount({ accounts, selectUrl }: Props) {
|
||||
const [busy, setBusy] = useState<number | null>(null)
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
|
||||
async function select(id: number) {
|
||||
if (busy !== null) return
|
||||
setBusy(id)
|
||||
setError(null)
|
||||
try {
|
||||
const r = await fetch(`${selectUrl}?account_id=${id}`, {
|
||||
headers: { Accept: 'application/json' },
|
||||
credentials: 'same-origin',
|
||||
})
|
||||
const d: { success?: boolean; redirect?: string; error?: string } = await r.json()
|
||||
if (d.success && d.redirect) {
|
||||
window.location.href = d.redirect
|
||||
} else {
|
||||
setError(d.error || 'No se pudo seleccionar la cuenta.')
|
||||
setBusy(null)
|
||||
}
|
||||
} catch {
|
||||
setError('Error de red. Inténtalo de nuevo.')
|
||||
setBusy(null)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<table className="middle-center-table">
|
||||
<tbody>
|
||||
{accounts.map((a) => (
|
||||
<tr key={a.id}>
|
||||
<td>
|
||||
<button
|
||||
type="button"
|
||||
className="login-button"
|
||||
disabled={busy !== null}
|
||||
onClick={() => select(a.id)}
|
||||
>
|
||||
{busy === a.id ? 'Entrando…' : a.username}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
{error && (
|
||||
<tr>
|
||||
<td>
|
||||
<span className="red-form-response">{error}</span>
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user