179 lines
9.7 KiB
JavaScript
179 lines
9.7 KiB
JavaScript
import { useEffect, useState } from 'react'
|
|
import { Container } from 'react-bootstrap'
|
|
import { useParams } from 'react-router-dom'
|
|
import { useTranslation } from 'react-i18next'
|
|
import { Link } from 'react-router-dom'
|
|
import { getUserProfile, listUserThanksGiven, listUserThanksReceived } from '../api/client'
|
|
|
|
export default function Profile() {
|
|
const { id } = useParams()
|
|
const { t } = useTranslation()
|
|
const [profile, setProfile] = useState(null)
|
|
const [error, setError] = useState('')
|
|
const [loading, setLoading] = useState(true)
|
|
const [thanksGiven, setThanksGiven] = useState([])
|
|
const [thanksReceived, setThanksReceived] = useState([])
|
|
const [loadingThanks, setLoadingThanks] = useState(true)
|
|
|
|
useEffect(() => {
|
|
let active = true
|
|
setLoading(true)
|
|
setError('')
|
|
|
|
Promise.all([getUserProfile(id), listUserThanksGiven(id), listUserThanksReceived(id)])
|
|
.then(([profileData, givenData, receivedData]) => {
|
|
if (!active) return
|
|
setProfile(profileData)
|
|
setThanksGiven(Array.isArray(givenData) ? givenData : [])
|
|
setThanksReceived(Array.isArray(receivedData) ? receivedData : [])
|
|
})
|
|
.catch((err) => {
|
|
if (!active) return
|
|
setError(err.message)
|
|
setThanksGiven([])
|
|
setThanksReceived([])
|
|
})
|
|
.finally(() => {
|
|
if (!active) return
|
|
setLoading(false)
|
|
setLoadingThanks(false)
|
|
})
|
|
|
|
return () => {
|
|
active = false
|
|
}
|
|
}, [id])
|
|
|
|
const formatDateTime = (value) => {
|
|
if (!value) return '—'
|
|
const date = new Date(value)
|
|
if (Number.isNaN(date.getTime())) return '—'
|
|
const day = String(date.getDate()).padStart(2, '0')
|
|
const month = String(date.getMonth() + 1).padStart(2, '0')
|
|
const year = String(date.getFullYear())
|
|
const hours = String(date.getHours()).padStart(2, '0')
|
|
const minutes = String(date.getMinutes()).padStart(2, '0')
|
|
const seconds = String(date.getSeconds()).padStart(2, '0')
|
|
return `${day}.${month}.${year} ${hours}:${minutes}:${seconds}`
|
|
}
|
|
|
|
return (
|
|
<Container fluid className="py-5 bb-portal-shell">
|
|
<div className="bb-portal-card">
|
|
<div className="bb-portal-card-title">{t('profile.title')}</div>
|
|
{loading && <p className="bb-muted">{t('profile.loading')}</p>}
|
|
{error && <p className="text-danger">{error}</p>}
|
|
{profile && (
|
|
<div className="bb-profile">
|
|
<div className="bb-profile-avatar">
|
|
{profile.avatar_url ? (
|
|
<img src={profile.avatar_url} alt="" />
|
|
) : (
|
|
<i className="bi bi-person" aria-hidden="true" />
|
|
)}
|
|
</div>
|
|
<div className="bb-profile-meta">
|
|
<div className="bb-profile-name">{profile.name}</div>
|
|
{profile.created_at && (
|
|
<div className="bb-muted">
|
|
{t('profile.registered')} {profile.created_at.slice(0, 10)}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
)}
|
|
{profile && (
|
|
<div className="bb-profile-thanks mt-4">
|
|
<div className="bb-profile-section">
|
|
<div className="bb-portal-card-title">{t('profile.thanks_given')}</div>
|
|
{loadingThanks && <p className="bb-muted">{t('profile.loading')}</p>}
|
|
{!loadingThanks && thanksGiven.length === 0 && (
|
|
<p className="bb-muted">{t('profile.thanks_empty')}</p>
|
|
)}
|
|
{!loadingThanks && thanksGiven.length > 0 && (
|
|
<ul className="bb-profile-thanks-list">
|
|
{thanksGiven.map((item) => (
|
|
<li key={item.id} className="bb-profile-thanks-item">
|
|
<Link to={`/thread/${item.thread_id}#post-${item.post_id}`}>
|
|
{item.thread_title || t('thread.label')}
|
|
</Link>
|
|
{item.post_author_id ? (
|
|
<span className="bb-profile-thanks-meta">
|
|
{t('profile.thanks_for')}{' '}
|
|
<Link
|
|
to={`/profile/${item.post_author_id}`}
|
|
style={
|
|
item.post_author_rank_color || item.post_author_group_color
|
|
? {
|
|
'--bb-user-link-color':
|
|
item.post_author_rank_color || item.post_author_group_color,
|
|
}
|
|
: undefined
|
|
}
|
|
>
|
|
{item.post_author_name || t('thread.anonymous')}
|
|
</Link>
|
|
</span>
|
|
) : (
|
|
<span className="bb-profile-thanks-meta">
|
|
{t('profile.thanks_for')} {item.post_author_name || t('thread.anonymous')}
|
|
</span>
|
|
)}
|
|
<span className="bb-profile-thanks-date">
|
|
{formatDateTime(item.thanked_at)}
|
|
</span>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
)}
|
|
</div>
|
|
<div className="bb-profile-section">
|
|
<div className="bb-portal-card-title">{t('profile.thanks_received')}</div>
|
|
{loadingThanks && <p className="bb-muted">{t('profile.loading')}</p>}
|
|
{!loadingThanks && thanksReceived.length === 0 && (
|
|
<p className="bb-muted">{t('profile.thanks_empty')}</p>
|
|
)}
|
|
{!loadingThanks && thanksReceived.length > 0 && (
|
|
<ul className="bb-profile-thanks-list">
|
|
{thanksReceived.map((item) => (
|
|
<li key={item.id} className="bb-profile-thanks-item">
|
|
<Link to={`/thread/${item.thread_id}#post-${item.post_id}`}>
|
|
{item.thread_title || t('thread.label')}
|
|
</Link>
|
|
{item.thanker_id ? (
|
|
<span className="bb-profile-thanks-meta">
|
|
{t('profile.thanks_by')}{' '}
|
|
<Link
|
|
to={`/profile/${item.thanker_id}`}
|
|
style={
|
|
item.thanker_rank_color || item.thanker_group_color
|
|
? {
|
|
'--bb-user-link-color':
|
|
item.thanker_rank_color || item.thanker_group_color,
|
|
}
|
|
: undefined
|
|
}
|
|
>
|
|
{item.thanker_name || t('thread.anonymous')}
|
|
</Link>
|
|
</span>
|
|
) : (
|
|
<span className="bb-profile-thanks-meta">
|
|
{t('profile.thanks_by')} {item.thanker_name || t('thread.anonymous')}
|
|
</span>
|
|
)}
|
|
<span className="bb-profile-thanks-date">
|
|
{formatDateTime(item.thanked_at)}
|
|
</span>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
)}
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</Container>
|
|
)
|
|
}
|