import { useState } from 'react' import { api } from '../../api/client.js' // Shown when a user tries to trust a device but is already at the trusted-device // cap. Styled like the TOTP entry flow (centered card on a dim overlay). The user // MUST revoke at least one existing device before they can continue — there is no // silent pruning — or they can cancel and leave the device untrusted. // // Props: // devices — the existing trusted devices (from the 409 / trustLimitReached payload) // onTrusted — called after the current device is successfully trusted (post-revoke) // onCancel — called when the user backs out without trusting this device export default function TrustLimitModal({ devices: initialDevices, onTrusted, onCancel }) { const [devices, setDevices] = useState(initialDevices || []) const [revokedAny, setRevokedAny] = useState(false) const [busy, setBusy] = useState(false) const [error, setError] = useState('') async function revoke(id) { setBusy(true) setError('') try { await api.revokeTrustedDevice(id) setDevices((list) => list.filter((d) => d.id !== id)) setRevokedAny(true) } catch { setError('Could not revoke that device. Please try again.') } finally { setBusy(false) } } async function trustNow() { setBusy(true) setError('') try { await api.trustThisDevice() onTrusted?.() } catch (err) { // Still at the cap somehow (a race) — surface it and let them revoke more. if (err.status === 409 && err.body?.devices) { setDevices(err.body.devices) setError('Still at the limit — revoke another device.') } else { setError('Could not trust this device. Please try again.') } } finally { setBusy(false) } } return (

Trusted-device limit reached

You can trust up to {Math.max(devices.length, 1)} devices. Revoke one below to make room, then continue — or cancel to leave this device untrusted.

{devices.map((d) => (
{d.deviceName || d.platform || 'Device'}
{d.userAgent || '—'}
))} {devices.length === 0 && (

All devices revoked. You can trust this one now.

)}
{error &&

{error}

}
) } const overlay = { position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.6)', display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 16, zIndex: 1000, } const card = { width: '100%', maxWidth: 460, background: 'var(--panel, #1a1a1f)', border: '1px solid var(--line)', borderRadius: 12, padding: 24, } const row = { display: 'flex', alignItems: 'center', gap: 12, padding: '10px 14px', border: '1px solid var(--line)', borderRadius: 8, }