MemberPage.tsx 8.9 KB

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