Add avatars, profiles, and auth flows
This commit is contained in:
@@ -1,9 +1,34 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { Container, Form, Row, Col } from 'react-bootstrap'
|
||||
import { getCurrentUser, uploadAvatar } from '../api/client'
|
||||
import { useAuth } from '../context/AuthContext'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
export default function Ucp({ theme, setTheme, accentOverride, setAccentOverride }) {
|
||||
const { t, i18n } = useTranslation()
|
||||
const { token } = useAuth()
|
||||
const accentMode = accentOverride ? 'custom' : 'system'
|
||||
const [avatarError, setAvatarError] = useState('')
|
||||
const [avatarUploading, setAvatarUploading] = useState(false)
|
||||
const [avatarPreview, setAvatarPreview] = useState('')
|
||||
|
||||
useEffect(() => {
|
||||
if (!token) return
|
||||
let active = true
|
||||
|
||||
getCurrentUser()
|
||||
.then((data) => {
|
||||
if (!active) return
|
||||
setAvatarPreview(data?.avatar_url || '')
|
||||
})
|
||||
.catch(() => {
|
||||
if (active) setAvatarPreview('')
|
||||
})
|
||||
|
||||
return () => {
|
||||
active = false
|
||||
}
|
||||
}, [token])
|
||||
|
||||
const handleLanguageChange = (event) => {
|
||||
const locale = event.target.value
|
||||
@@ -12,7 +37,48 @@ export default function Ucp({ theme, setTheme, accentOverride, setAccentOverride
|
||||
}
|
||||
|
||||
return (
|
||||
<Container className="py-5 bb-portal-shell">
|
||||
<Container fluid className="py-5 bb-portal-shell">
|
||||
<div className="bb-portal-card mb-4">
|
||||
<div className="bb-portal-card-title">{t('ucp.profile')}</div>
|
||||
<p className="bb-muted mb-4">{t('ucp.profile_hint')}</p>
|
||||
<Row className="g-3 align-items-center">
|
||||
<Col md="auto">
|
||||
<div className="bb-avatar-preview">
|
||||
{avatarPreview ? (
|
||||
<img src={avatarPreview} alt="" />
|
||||
) : (
|
||||
<i className="bi bi-person" aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
</Col>
|
||||
<Col>
|
||||
{avatarError && <p className="text-danger mb-2">{avatarError}</p>}
|
||||
<Form.Group>
|
||||
<Form.Label>{t('ucp.avatar_label')}</Form.Label>
|
||||
<Form.Control
|
||||
type="file"
|
||||
accept="image/png,image/jpeg,image/jpg,image/gif,image/webp"
|
||||
disabled={!token || avatarUploading}
|
||||
onChange={async (event) => {
|
||||
const file = event.target.files?.[0]
|
||||
if (!file) return
|
||||
setAvatarError('')
|
||||
setAvatarUploading(true)
|
||||
try {
|
||||
const response = await uploadAvatar(file)
|
||||
setAvatarPreview(response.url)
|
||||
} catch (err) {
|
||||
setAvatarError(err.message)
|
||||
} finally {
|
||||
setAvatarUploading(false)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Form.Text className="bb-muted">{t('ucp.avatar_hint')}</Form.Text>
|
||||
</Form.Group>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
<div className="bb-portal-card">
|
||||
<div className="bb-portal-card-title">{t('portal.user_control_panel')}</div>
|
||||
<p className="bb-muted mb-4">{t('ucp.intro')}</p>
|
||||
|
||||
Reference in New Issue
Block a user