Tighten ACP forum actions and avatar handling

This commit is contained in:
Micha
2026-01-13 00:07:25 +01:00
parent 3bb2946656
commit 98094459e3
9 changed files with 116 additions and 38 deletions

View File

@@ -905,32 +905,34 @@ export default function Acp({ isAdmin }) {
>
<i className="bi bi-arrow-down-up" aria-hidden="true" />
</span>
<ButtonGroup size="sm" className="bb-action-group">
{node.type === 'category' && (
<>
<Button
variant="dark"
onClick={() => handleStartCreateChild('category', node.id)}
title={t('acp.add_category')}
>
<i className="bi bi-folder-plus" aria-hidden="true" />
</Button>
<Button
variant="dark"
onClick={() => handleStartCreateChild('forum', node.id)}
title={t('acp.add_forum')}
>
<i className="bi bi-chat-left-text" aria-hidden="true" />
</Button>
</>
)}
<Button variant="dark" onClick={() => handleSelectForum(node)} title={t('acp.edit')}>
<i className="bi bi-pencil" aria-hidden="true" />
</Button>
<Button variant="dark" onClick={() => handleDelete(node.id)} title={t('acp.delete')}>
<i className="bi bi-trash" aria-hidden="true" />
</Button>
</ButtonGroup>
<div className="bb-tree-action-group">
<ButtonGroup size="sm" className="bb-action-group w-100">
{node.type === 'category' && (
<>
<Button
variant="dark"
onClick={() => handleStartCreateChild('category', node.id)}
title={t('acp.add_category')}
>
<i className="bi bi-folder-plus" aria-hidden="true" />
</Button>
<Button
variant="dark"
onClick={() => handleStartCreateChild('forum', node.id)}
title={t('acp.add_forum')}
>
<i className="bi bi-chat-left-text" aria-hidden="true" />
</Button>
</>
)}
<Button variant="dark" onClick={() => handleSelectForum(node)} title={t('acp.edit')}>
<i className="bi bi-pencil" aria-hidden="true" />
</Button>
<Button variant="dark" onClick={() => handleDelete(node.id)} title={t('acp.delete')}>
<i className="bi bi-trash" aria-hidden="true" />
</Button>
</ButtonGroup>
</div>
</div>
</div>
{node.children?.length > 0 &&

View File

@@ -1,8 +1,9 @@
import { useEffect, useMemo, useState } from 'react'
import { Badge, Container } from 'react-bootstrap'
import { Link } from 'react-router-dom'
import { listAllForums, listThreads } from '../api/client'
import { getCurrentUser, listAllForums, listThreads } from '../api/client'
import { useTranslation } from 'react-i18next'
import { useAuth } from '../context/AuthContext'
export default function Home() {
const [forums, setForums] = useState([])
@@ -10,6 +11,8 @@ export default function Home() {
const [error, setError] = useState('')
const [loadingForums, setLoadingForums] = useState(true)
const [loadingThreads, setLoadingThreads] = useState(true)
const [profile, setProfile] = useState(null)
const { token, roles, email } = useAuth()
const { t } = useTranslation()
useEffect(() => {
@@ -26,6 +29,27 @@ export default function Home() {
.finally(() => setLoadingThreads(false))
}, [])
useEffect(() => {
if (!token) {
setProfile(null)
return
}
let active = true
getCurrentUser()
.then((data) => {
if (!active) return
setProfile(data)
})
.catch(() => {
if (active) setProfile(null)
})
return () => {
active = false
}
}, [token])
const getParentId = (forum) => {
if (!forum.parent) return null
if (typeof forum.parent === 'string') {
@@ -79,6 +103,13 @@ export default function Home() {
.slice(0, 12)
}, [threads])
const roleLabel = useMemo(() => {
if (!roles?.length) return t('portal.user_role_member')
if (roles.includes('ROLE_ADMIN')) return t('portal.user_role_operator')
if (roles.includes('ROLE_MODERATOR')) return t('portal.user_role_moderator')
return t('portal.user_role_member')
}, [roles, t])
const resolveForumName = (thread) => {
if (!thread?.forum) return t('portal.unknown_forum')
const parts = thread.forum.split('/')
@@ -205,9 +236,15 @@ export default function Home() {
<div className="bb-portal-card">
<div className="bb-portal-card-title">{t('portal.user_menu')}</div>
<div className="bb-portal-user-card">
<div className="bb-portal-user-avatar" />
<div className="bb-portal-user-name">tracer</div>
<div className="bb-portal-user-role">Operator</div>
<div className="bb-portal-user-avatar">
{profile?.avatar_url ? (
<img src={profile.avatar_url} alt="" />
) : (
<i className="bi bi-person" aria-hidden="true" />
)}
</div>
<div className="bb-portal-user-name">{profile?.name || email || 'User'}</div>
<div className="bb-portal-user-role">{roleLabel}</div>
</div>
<ul className="bb-portal-list">
<li>{t('portal.user_new_posts')}</li>