import { useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useOwnDevices } from '../../hooks/useOwnDevices'; import { getDeviceRowId } from '../../lib/deviceRowId'; import { SpinnerIcon } from '../icons'; function formatLastSeen(iso: string, locale: string): string { try { const d = new Date(iso); return d.toLocaleString(locale, { dateStyle: 'medium', timeStyle: 'short' }); } catch { return iso; } } export function DeviceListTab() { const { t, i18n } = useTranslation(); const { devices, loading, error, revoke } = useOwnDevices(); const ownId = getDeviceRowId(); const [busy, setBusy] = useState(null); const [opError, setOpError] = useState(null); const handleRevoke = async (id: string) => { setOpError(null); setBusy(id); try { await revoke(id); } catch (err) { setOpError(err instanceof Error ? err.message : 'revoke failed'); } finally { setBusy(null); } }; if (loading) { return (
); } if (error) { return (

{t('app:settings.devices.error', { defaultValue: 'Geräteliste konnte nicht geladen werden.' })}

); } if (devices.length === 0) { return (

{t('app:settings.devices.empty', { defaultValue: 'Noch keine Geräte angemeldet.' })}

); } return (
{opError && (

{opError}

)}
    {devices.map((d) => { const isOwn = d.id === ownId; const isRevoked = d.revokedAt !== null; return (
  • {d.name} {isOwn && ( {t('app:settings.devices.this_device', { defaultValue: 'Dieses Gerät' })} )} {isRevoked && ( {t('app:settings.devices.revoked', { defaultValue: 'Abgemeldet' })} )}

    {d.platform} · {t('app:settings.devices.last_seen', { defaultValue: 'zuletzt' })}{' '} {formatLastSeen(d.lastSeenAt, i18n.language)}

    {isOwn ? ( ) : isRevoked ? ( {t('app:settings.devices.already_revoked', { defaultValue: '—' })} ) : ( )}
  • ); })}
); }