MemberPage.tsx 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. import React from 'react';
  2. import { useNavigate } from 'react-router-dom';
  3. import { useAuth } from '@/client/home/hooks/AuthProvider';
  4. import { Button } from '@/client/components/ui/button';
  5. import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/client/components/ui/card';
  6. import { Avatar, AvatarFallback, AvatarImage } from '@/client/components/ui/avatar';
  7. import { Separator } from '@/client/components/ui/separator';
  8. import {
  9. User,
  10. MapPin,
  11. Globe,
  12. Calendar,
  13. LogOut,
  14. Settings,
  15. UserCog,
  16. ShieldCheck,
  17. Clock
  18. } from 'lucide-react';
  19. import { format } from 'date-fns';
  20. import { zhCN } from 'date-fns/locale';
  21. const MemberPage: React.FC = () => {
  22. const navigate = useNavigate();
  23. const { user, logout } = useAuth();
  24. if (!user) {
  25. return (
  26. <div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-slate-50 to-slate-100 px-4">
  27. <Card className="max-w-md">
  28. <CardHeader>
  29. <CardTitle>用户不存在</CardTitle>
  30. <CardDescription>请先登录后再访问此页面</CardDescription>
  31. </CardHeader>
  32. <CardContent>
  33. <Button onClick={() => navigate('/')} className="w-full">
  34. 返回首页
  35. </Button>
  36. </CardContent>
  37. </Card>
  38. </div>
  39. );
  40. }
  41. return (
  42. <div className="min-h-screen bg-gradient-to-br from-slate-50 to-slate-100">
  43. <div className="container mx-auto py-8">
  44. <div className="mx-auto max-w-4xl space-y-8">
  45. {/* 用户资料卡片 */}
  46. <Card className="border-0 shadow-lg">
  47. <CardContent className="pt-6">
  48. <div className="flex flex-col items-center space-y-4">
  49. <Avatar className="h-24 w-24">
  50. <AvatarImage
  51. src={user.avatar || `https://avatar.vercel.sh/${user.username}`}
  52. alt={user.nickname || user.username}
  53. />
  54. <AvatarFallback className="text-2xl bg-primary text-primary-foreground">
  55. {user.username?.charAt(0).toUpperCase()}
  56. </AvatarFallback>
  57. </Avatar>
  58. <div className="text-center space-y-2">
  59. <h1 className="text-3xl font-bold">{user.nickname || user.username}</h1>
  60. <p className="text-muted-foreground">@{user.username}</p>
  61. </div>
  62. <div className="flex items-center space-x-4">
  63. <div className="text-center">
  64. <p className="text-2xl font-bold">0</p>
  65. <p className="text-sm text-muted-foreground">内容</p>
  66. </div>
  67. <Separator orientation="vertical" className="h-8" />
  68. <div className="text-center">
  69. <p className="text-2xl font-bold">0</p>
  70. <p className="text-sm text-muted-foreground">关注</p>
  71. </div>
  72. <Separator orientation="vertical" className="h-8" />
  73. <div className="text-center">
  74. <p className="text-2xl font-bold">0</p>
  75. <p className="text-sm text-muted-foreground">粉丝</p>
  76. </div>
  77. </div>
  78. <div className="flex items-center space-x-2">
  79. <Button
  80. onClick={() => navigate('/profile/edit')}
  81. className="flex items-center space-x-2"
  82. >
  83. <UserCog className="h-4 w-4" />
  84. <span>编辑资料</span>
  85. </Button>
  86. <Button
  87. variant="outline"
  88. onClick={async () => {
  89. await logout();
  90. navigate('/');
  91. }}
  92. className="flex items-center space-x-2"
  93. >
  94. <LogOut className="h-4 w-4" />
  95. <span>退出登录</span>
  96. </Button>
  97. </div>
  98. </div>
  99. </CardContent>
  100. </Card>
  101. {/* 个人资料详情 */}
  102. <Card className="border-0 shadow-lg">
  103. <CardHeader>
  104. <CardTitle className="flex items-center space-x-2">
  105. <User className="h-5 w-5" />
  106. <span>个人资料</span>
  107. </CardTitle>
  108. </CardHeader>
  109. <CardContent className="space-y-6">
  110. <div className="grid gap-4">
  111. <div className="space-y-1">
  112. <div className="flex items-center space-x-2 text-sm text-muted-foreground">
  113. <User className="h-4 w-4" />
  114. <span>用户名</span>
  115. </div>
  116. <p className="font-medium">{user.username}</p>
  117. </div>
  118. <div className="space-y-1">
  119. <div className="flex items-center space-x-2 text-sm text-muted-foreground">
  120. <ShieldCheck className="h-4 w-4" />
  121. <span>邮箱</span>
  122. </div>
  123. <p className="font-medium">{user.email || '未设置'}</p>
  124. </div>
  125. {(user as any).location && (
  126. <div className="space-y-1">
  127. <div className="flex items-center space-x-2 text-sm text-muted-foreground">
  128. <MapPin className="h-4 w-4" />
  129. <span>位置</span>
  130. </div>
  131. <p className="font-medium">{(user as any).location}</p>
  132. </div>
  133. )}
  134. {(user as any).website && (
  135. <div className="space-y-1">
  136. <div className="flex items-center space-x-2 text-sm text-muted-foreground">
  137. <Globe className="h-4 w-4" />
  138. <span>网站</span>
  139. </div>
  140. <a
  141. href={(user as any).website}
  142. target="_blank"
  143. rel="noopener noreferrer"
  144. className="font-medium text-primary hover:underline"
  145. >
  146. {(user as any).website}
  147. </a>
  148. </div>
  149. )}
  150. {(user as any).bio && (
  151. <div className="space-y-1">
  152. <div className="flex items-center space-x-2 text-sm text-muted-foreground">
  153. <User className="h-4 w-4" />
  154. <span>个人简介</span>
  155. </div>
  156. <p className="font-medium">{(user as any).bio}</p>
  157. </div>
  158. )}
  159. </div>
  160. <Separator />
  161. <div className="grid gap-4 md:grid-cols-2">
  162. <div className="space-y-1">
  163. <div className="flex items-center space-x-2 text-sm text-muted-foreground">
  164. <Calendar className="h-4 w-4" />
  165. <span>注册时间</span>
  166. </div>
  167. <p className="font-medium">
  168. {user.createdAt ? format(new Date(user.createdAt), 'yyyy年MM月dd日', { locale: zhCN }) : '未知'}
  169. </p>
  170. </div>
  171. <div className="space-y-1">
  172. <div className="flex items-center space-x-2 text-sm text-muted-foreground">
  173. <Clock className="h-4 w-4" />
  174. <span>最后登录</span>
  175. </div>
  176. <p className="font-medium">
  177. {user.updatedAt ? format(new Date(user.updatedAt), 'yyyy年MM月dd日 HH:mm', { locale: zhCN }) : '从未登录'}
  178. </p>
  179. </div>
  180. </div>
  181. </CardContent>
  182. </Card>
  183. {/* 设置区域 */}
  184. <Card className="border-0 shadow-lg">
  185. <CardHeader>
  186. <CardTitle className="flex items-center space-x-2">
  187. <Settings className="h-5 w-5" />
  188. <span>账号设置</span>
  189. </CardTitle>
  190. </CardHeader>
  191. <CardContent className="space-y-4">
  192. <Button
  193. variant="outline"
  194. className="w-full justify-start"
  195. onClick={() => navigate('/profile/security')}
  196. >
  197. <ShieldCheck className="h-4 w-4 mr-2" />
  198. <span>安全设置</span>
  199. </Button>
  200. <Button
  201. variant="outline"
  202. className="w-full justify-start"
  203. onClick={() => navigate('/profile/preferences')}
  204. >
  205. <Settings className="h-4 w-4 mr-2" />
  206. <span>偏好设置</span>
  207. </Button>
  208. </CardContent>
  209. </Card>
  210. </div>
  211. </div>
  212. </div>
  213. );
  214. };
  215. export default MemberPage;