import { useState, useEffect, useContext, useCallback } from 'react' import { AuthContext } from '../App.jsx' import { updateProfile, changePassword, listTokens, createToken, deleteToken, getInstanceSettings, updateInstanceSettings, } from '../api.js' const ROLE_ADMIN = 4 export default function SettingsView() { const { currentUser, setCurrentUser } = useContext(AuthContext) ?? {} const isAdmin = currentUser && ((currentUser.role_bits & ROLE_ADMIN) !== 0) const [tab, setTab] = useState('profile') const tabs = ['profile', 'tokens', ...(isAdmin ? ['instance'] : [])] const tabLabels = { profile: 'Profile', tokens: 'API Tokens', instance: 'Instance' } return (

Settings

{tabs.map(t => ( ))}
{tab === 'profile' && } {tab === 'tokens' && } {tab === 'instance' && isAdmin && }
) } function ProfileTab({ currentUser, setCurrentUser }) { const [displayName, setDisplayName] = useState(currentUser?.display_name ?? '') const [saving, setSaving] = useState(false) const [saveMsg, setSaveMsg] = useState(null) const [curPw, setCurPw] = useState('') const [newPw, setNewPw] = useState('') const [confirmPw, setConfirmPw] = useState('') const [pwSaving, setPwSaving] = useState(false) const [pwMsg, setPwMsg] = useState(null) async function handleSaveProfile(e) { e.preventDefault() setSaving(true) setSaveMsg(null) try { await updateProfile(displayName) setCurrentUser(u => ({ ...u, display_name: displayName || null })) setSaveMsg({ ok: true, text: 'Saved.' }) } catch (err) { setSaveMsg({ ok: false, text: err.message }) } finally { setSaving(false) } } async function handleChangePassword(e) { e.preventDefault() if (newPw !== confirmPw) { setPwMsg({ ok: false, text: 'Passwords do not match.' }); return } setPwSaving(true) setPwMsg(null) try { await changePassword(curPw, newPw) setCurPw(''); setNewPw(''); setConfirmPw('') setPwMsg({ ok: true, text: 'Password changed.' }) } catch (err) { setPwMsg({ ok: false, text: err.message }) } finally { setPwSaving(false) } } return (

Display Name

setDisplayName(e.target.value)} />
{saveMsg &&
{saveMsg.text}
}

Change Password

setCurPw(e.target.value)} required />
setNewPw(e.target.value)} required />
setConfirmPw(e.target.value)} required />
{pwMsg &&
{pwMsg.text}
}
) } function TokensTab() { const [tokens, setTokens] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [newName, setNewName] = useState('') const [creating, setCreating] = useState(false) const [newToken, setNewToken] = useState(null) const refresh = useCallback(async () => { setLoading(true); setError(null) try { setTokens(await listTokens()) } catch (e) { setError(e.message) } finally { setLoading(false) } }, []) useEffect(() => { refresh() }, [refresh]) async function handleCreate(e) { e.preventDefault() if (!newName.trim()) return setCreating(true) try { const tok = await createToken(newName.trim()) setNewToken(tok) setNewName('') refresh() } catch (err) { setError(err.message) } finally { setCreating(false) } } async function handleDelete(tokenUid) { try { await deleteToken(tokenUid) setTokens(ts => ts.filter(t => t.token_uid !== tokenUid)) } catch (err) { setError(err.message) } } return (

API Tokens

{newToken && (
Token created. Copy it now — it won't be shown again. {newToken.raw_token}
)}
setNewName(e.target.value)} required />
{error &&
{error}
} {loading ? (
Loading\u2026
) : (
{tokens.length === 0 &&
No tokens yet.
} {tokens.map(tok => (
{tok.name}
Created {tok.created_at.slice(0, 10)} {tok.last_used_at && ` \u00b7 Last used ${tok.last_used_at.slice(0, 10)}`}
))}
)}
) } function InstanceTab() { const [settings, setSettings] = useState(null) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [saving, setSaving] = useState(false) const [saveMsg, setSaveMsg] = useState(null) useEffect(() => { (async () => { try { setSettings(await getInstanceSettings()) } catch (e) { setError(e.message) } finally { setLoading(false) } })() }, []) async function handleSave(e) { e.preventDefault() setSaving(true); setSaveMsg(null) try { await updateInstanceSettings(settings) setSaveMsg({ ok: true, text: 'Saved.' }) } catch (err) { setSaveMsg({ ok: false, text: err.message }) } finally { setSaving(false) } } if (loading) return
Loading\u2026
if (error) return
{error}
if (!settings) return null return (

Instance Settings

{[ ['public_index_enabled', 'Public index (unauthenticated browsing)'], ['public_entry_content_enabled', 'Public entry content'], ['open_registration_enabled', 'Open registration'], ].map(([key, label]) => ( ))}
{saveMsg &&
{saveMsg.text}
}
) }