import { useEffect, useState } from 'react'; import { useNavigate, useParams, useLocation } from 'react-router-dom'; import { ArrowLeft, FileText, Hash, Heart, Mail, MessageCircle, PenLine, Settings, Star, } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import UserBadges from '../components/UserBadges'; import { Spinner } from '@/components/ui/spinner'; import { notify } from '@/lib/notify'; import { api } from '../api/client'; import type { PostItem, UserActivityStats, UserPublic } from '../api/types'; import { useAuth } from '../hooks/useAuth'; import { useForumLimits } from '../hooks/useForumLimits'; import { useSessionResource } from '../hooks/useSessionResource'; import PostListItem from '../components/PostListItem'; import FeedPagination from '../components/FeedPagination'; import ComposeMessageDialog from '../components/ComposeMessageDialog'; import { openForumPost } from '../utils/openPost'; import { formatDateTime } from '../utils/content'; import { usePageSEO } from '../hooks/usePageSEO'; import { loginPath } from '../utils/authRedirect'; import { canonicalRedirectPath, parsePermalinkID, userPath } from '../utils/permalink'; import NotFoundPage from './NotFoundPage'; import { InFlowSiteFooter } from '../components/SiteFooter'; type ProfileSnap = { profile: UserPublic; stats: UserActivityStats | null }; type PostsSnap = { posts: PostItem[]; total: number }; export default function UserProfilePage() { const { id: idParam } = useParams(); const userId = parsePermalinkID(idParam); const nav = useNavigate(); const location = useLocation(); const { user: me } = useAuth(); const { limits } = useForumLimits(); const pageSize = limits.page_size_default > 0 ? limits.page_size_default : 20; const [msgOpen, setMsgOpen] = useState(false); const [notFound, setNotFound] = useState(false); const [postPage, setPostPage] = useState(1); const profileKey = userId && !Number.isNaN(userId) ? `user:${userId}` : null; const { data: profileSnap, loading } = useSessionResource( profileKey, () => api.userProfile(userId).then(d => ({ profile: d.user, stats: d.stats ?? null })), { enabled: !!profileKey, onError: () => setNotFound(true), }, ); const profile = profileSnap?.profile ?? null; const stats = profileSnap?.stats ?? null; const postsKey = profileKey && profile ? `${profileKey}:posts:${postPage}:${pageSize}` : null; const { data: postsSnap, loading: postsLoading } = useSessionResource( postsKey, () => api.posts({ user_id: userId, page: postPage, size: pageSize, sort: 'latest' }) .then(d => ({ posts: Array.isArray(d.posts) ? d.posts : [], total: d.total ?? 0 })), { enabled: !!postsKey, onError: (e) => notify.error(e instanceof Error ? e.message : '加载帖子失败'), }, ); const posts = postsSnap?.posts ?? []; const postTotal = postsSnap?.total ?? 0; const isSelf = !!me && me.id === userId; const totalPages = Math.max(1, Math.ceil(postTotal / pageSize)); useEffect(() => { if (!userId || Number.isNaN(userId)) { setNotFound(true); } }, [userId]); useEffect(() => { setNotFound(false); setPostPage(1); }, [userId]); useEffect(() => { if (!userId || Number.isNaN(userId)) return; const target = canonicalRedirectPath('user', userId, location.pathname, limits); if (target) nav(target + location.search + location.hash, { replace: true }); }, [userId, location.pathname, location.search, location.hash, limits, nav]); usePageSEO(profile ? { title: `${profile.nickname} 的主页`, description: profile.signature?.trim() || `${profile.nickname} 的主页`, canonicalPath: userPath(profile.id, limits), ogType: 'profile', ogImage: profile.avatar || '', jsonLd: { '@context': 'https://schema.org', '@type': 'ProfilePage', mainEntity: { '@type': 'Person', name: profile.nickname, description: profile.signature?.trim() || undefined, }, }, } : null); if (loading) { return
; } if (notFound || !profile) { return ( ); } const joinedAt = profile.created_at ? formatDateTime(profile.created_at) : ''; const signature = profile.signature?.trim() || ''; return (
{profile.avatar ? : profile.nickname[0]}

{profile.nickname}

{profile.banned && 已禁言}
@{profile.username}
UID {profile.id}
{signature ? (

{signature}

) : (

这个人很懒,还没有签名

)}
{joinedAt && (
注册时间
{joinedAt}
)}
{isSelf ? ( ) : ( )}
{!!profile.badges?.length && (

徽章

)}
{stats?.post_count ?? 0} 帖子
{stats?.comment_count ?? 0} 评论
{stats?.like_received ?? 0} 获赞
{isSelf && ( )}
{isSelf ? '我的帖子' : `${profile.nickname} 的帖子`} {postTotal > 0 && {postTotal}}
{postsLoading ? (
) : posts.length === 0 ? (

{isSelf ? '还没有发布过帖子' : '暂无公开帖子'}

{isSelf && }
) : ( <>
{posts.map(post => ( openForumPost(nav, id, limits.open_posts_in_new_tab)} /> ))}
{totalPages > 1 && ( )} )}
{!isSelf && profile && me && ( nav(`/messages?peer=${profile.id}`)} /> )}
); }