import { useCallback, useEffect, useState } from 'react' import { Link } from 'react-router-dom' import { Loading, ErrorState } from './PageState.jsx' // Shared game-account linking + character roster, used by both the player portal // (/player) and the staff account page (/admin/account). `scope` is the api // object with { link, accounts, roster } (player or admin self-service); `charTo` // maps a serial to the route for that character's sheet. function LinkForm({ scope, onLinked, compact }) { const [code, setCode] = useState('') const [busy, setBusy] = useState(false) const [msg, setMsg] = useState('') const [error, setError] = useState('') async function submit(e) { e.preventDefault() setMsg(''); setError('') if (!code.trim()) return setBusy(true) try { const { account } = await scope.link(code.trim()) setMsg(`Linked ${account}.`) setCode('') await onLinked() } catch (err) { setError(err.message || 'Could not link that code.') } finally { setBusy(false) } } return (
{msg && {msg}} {error && {error}}
) } function AccountRoster({ scope, account, charTo }) { const [roster, setRoster] = useState(null) const [error, setError] = useState('') const [unavailable, setUnavailable] = useState(false) const load = useCallback(async () => { setError(''); setUnavailable(false) try { setRoster(await scope.roster(account)) } catch (err) { if (err.status === 503) setUnavailable(true) else setError(err.message || 'Could not load this account.') } }, [scope, account]) useEffect(() => { load() }, [load]) if (unavailable) { return (

The game server is restarting — try again shortly.

) } if (error) return

{error}

if (!roster) return

Loading…

const chars = roster.chars || [] if (chars.length === 0) return

No characters on this account.

return (
{chars.map((c) => ( {(c.name || '?').charAt(0)}
{c.name}
{c.online ? 'Online' : 'Offline'}
))}
) } export default function GameAccounts({ scope, charTo }) { const [accounts, setAccounts] = useState(null) const [error, setError] = useState('') const load = useCallback(async () => { setError('') try { setAccounts(await scope.accounts()) } catch { setError('Could not load your game accounts.') } }, [scope]) useEffect(() => { load() }, [load]) if (error) return if (!accounts) return // Not linked yet — prompt to link. if (accounts.length === 0) { return (
Link your game account

You haven’t linked a game account yet. In game, type [link to get a one-time code, then enter it below to see your characters, stats, skills and vendors here.

) } // Linked — characters grouped by account. return (
{accounts.map((a) => (
{a.account}
))}
Link another account
) }