import { useCallback, useEffect, useState } from 'react' import { api } from '../../api/client.js' import TrustLimitModal from './TrustLimitModal.jsx' // Self-service list of the devices allowed to skip the TOTP step at login (MFA // "Trust this device"). Uses the role-agnostic /auth/me/trusted-devices surface, so // the same panel serves players and staff. Shown only when 2FA is enabled — trust // is meaningless without a second factor to skip. function fmtDate(s) { if (!s) return '—' const d = new Date(s) return Number.isNaN(d.getTime()) ? '—' : d.toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' }) } export default function TrustedDevicesPanel() { const [devices, setDevices] = useState(null) const [error, setError] = useState('') const [busy, setBusy] = useState(false) const [msg, setMsg] = useState('') const [capModal, setCapModal] = useState(null) // { devices } when the cap is hit const load = useCallback(async () => { try { setDevices(await api.myTrustedDevices()) } catch { setError('Could not load your trusted devices.') } }, []) useEffect(() => { load() }, [load]) async function trustThis() { setBusy(true) setMsg('') setError('') try { await api.trustThisDevice() setMsg('This device is now trusted.') await load() } catch (err) { if (err.status === 409 && err.body?.error === 'trusted_device_limit') { setCapModal({ devices: err.body.devices || [] }) } else { setError('Could not trust this device.') } } finally { setBusy(false) } } async function revoke(id) { setBusy(true) setMsg('') setError('') try { await api.revokeTrustedDevice(id) await load() } catch { setError('Could not revoke that device.') } finally { setBusy(false) } } async function revokeAll() { if (!window.confirm('Untrust every device? Each will require the full two-factor step at the next login.')) return setBusy(true) setMsg('') setError('') try { await api.revokeAllTrustedDevices() setMsg('All devices untrusted.') await load() } catch { setError('Could not untrust devices.') } finally { setBusy(false) } } if (!devices) return null return (

Trusted devices

Devices you’ve trusted skip the authenticator step at login (your password is still required). Revoke any you don’t recognize.

{devices.length > 0 ? (
{devices.map((d) => (
{d.deviceName || (d.platform === 'mobile' ? 'Mobile app' : 'Browser')}
{d.userAgent || '—'} · last used {fmtDate(d.lastUsedAt)} · expires {fmtDate(d.expiresAt)}
))}
) : (

No trusted devices yet.

)}
{devices.length > 0 && ( )}
{msg &&

{msg}

} {error &&

{error}

} {capModal && ( { setCapModal(null); setMsg('This device is now trusted.'); load() }} onCancel={() => setCapModal(null)} /> )}
) }