NeonClary's picture
Deploy tutorial feature and recent fixes
d8808e7 verified
Raw
History Blame Contribute Delete
3.54 kB
import { useState } from 'react'
import { apiFetch } from '../api'
import { useAuth } from '../context/AuthContext'
import { useHideCaretWhileTyping } from '../hooks/useHideCaretWhileTyping'
type Props = { onClose: () => void }
export function AccountModal({ onClose }: Props) {
const { onFormTextInput, onTextareaBlur } = useHideCaretWhileTyping()
const { user, refreshUser, signOut } = useAuth()
const [firstName, setFirstName] = useState(user?.firstName || '')
const [lastName, setLastName] = useState(user?.lastName || '')
const [email, setEmail] = useState(user?.email || '')
const [password, setPassword] = useState('')
const [err, setErr] = useState('')
const save = async () => {
setErr('')
const body: Record<string, string> = { firstName, lastName, email }
if (password.trim()) body.password = password
const r = await apiFetch('/api/auth/me', {
method: 'PATCH',
body: JSON.stringify(body),
})
if (!r.ok) {
setErr((await r.json().catch(() => ({}))).detail || 'Update failed')
return
}
await refreshUser()
onClose()
}
const deleteAccount = async () => {
if (!confirm('Delete your account and server-stored profile? This cannot be undone.')) return
const r = await apiFetch('/api/auth/me', { method: 'DELETE' })
if (r.ok) {
signOut()
onClose()
}
}
return (
<div className="modal-overlay" role="dialog" aria-modal>
<div className="modal-box">
<h2>Account</h2>
{err && <p style={{ color: '#b91c1c', fontSize: '0.9rem' }}>{err}</p>}
<div className="field">
<label>First name</label>
<input
value={firstName}
onChange={(e) => setFirstName(e.target.value)}
onInput={onFormTextInput}
onBlur={onTextareaBlur}
/>
</div>
<div className="field">
<label>Last name</label>
<input
value={lastName}
onChange={(e) => setLastName(e.target.value)}
onInput={onFormTextInput}
onBlur={onTextareaBlur}
/>
</div>
<div className="field">
<label>Email</label>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
onInput={onFormTextInput}
onBlur={onTextareaBlur}
/>
</div>
<div className="field">
<label>New password (optional)</label>
<input
type="password"
autoComplete="new-password"
value={password}
onChange={(e) => setPassword(e.target.value)}
onInput={onFormTextInput}
onBlur={onTextareaBlur}
placeholder="Leave blank to keep current"
/>
</div>
<div style={{ display: 'flex', gap: '0.5rem', justifyContent: 'space-between', flexWrap: 'wrap' }}>
<button type="button" className="btn btn-secondary" onClick={deleteAccount}>
Delete account
</button>
<div style={{ display: 'flex', gap: '0.5rem' }}>
<button type="button" className="btn btn-secondary" onClick={onClose}>
Cancel
</button>
<button type="button" className="btn btn-primary" onClick={save}>
Save
</button>
</div>
</div>
</div>
</div>
)
}