source: chapterx-frontend/src/pages/profile/ProfilePage.tsx@ b62cefc

main
Last change on this file since b62cefc was b62cefc, checked in by kikisrbinoska <srbinoskakristina07@…>, 4 months ago

Added frontend and imporoved AI Suggestions service

  • Property mode set to 100644
File size: 7.0 KB
Line 
1import React, { useState } from 'react'
2import { useParams, useNavigate } from 'react-router-dom'
3import { BookOpen, Heart, Users, Calendar, MessageCircle, Eye } from 'lucide-react'
4import { useAuthStore } from '../../store/authStore'
5import { useStoryStore } from '../../store/storyStore'
6import { Avatar } from '../../components/ui/Avatar'
7import { RoleBadge, StatusBadge } from '../../components/ui/Badge'
8import { StoryCard } from '../../components/ui/StoryCard'
9import { GenreBadge } from '../../components/ui/Badge'
10
11type Tab = 'stories' | 'about'
12
13export const ProfilePage: React.FC = () => {
14 const { username } = useParams<{ username: string }>()
15 const navigate = useNavigate()
16 const { allUsers, currentUser } = useAuthStore()
17 const { stories, comments } = useStoryStore()
18 const [tab, setTab] = useState<Tab>('stories')
19
20 const user = allUsers.find(u => u.username === username)
21
22 if (!user) {
23 return (
24 <div className="max-w-4xl mx-auto px-4 py-20 text-center">
25 <h2 className="text-2xl text-white mb-4">User not found</h2>
26 </div>
27 )
28 }
29
30 const userStories = stories.filter(s => s.user_id === user.user_id && s.status === 'published')
31 const totalLikes = userStories.reduce((acc, s) => acc + s.total_likes, 0)
32 const totalViews = userStories.reduce((acc, s) => acc + s.total_views, 0)
33 const userComments = comments.filter(c => c.user_id === user.user_id)
34 const allGenres = [...new Set(userStories.flatMap(s => s.genres))]
35
36 return (
37 <div className="max-w-5xl mx-auto px-4 py-8">
38 {/* Profile header */}
39 <div className="relative mb-8">
40 {/* Cover */}
41 <div className="h-32 sm:h-48 rounded-2xl bg-gradient-to-br from-indigo-900 via-violet-900 to-purple-900 mb-16 sm:mb-20 overflow-hidden">
42 <div className="absolute inset-0 rounded-2xl opacity-40">
43 <div className="absolute top-4 left-16 w-32 h-32 rounded-full bg-white/10 blur-2xl" />
44 <div className="absolute bottom-2 right-8 w-24 h-24 rounded-full bg-white/10 blur-xl" />
45 </div>
46 </div>
47
48 {/* Avatar + info */}
49 <div className="absolute bottom-0 left-0 right-0 px-6 flex items-end justify-between">
50 <Avatar name={`${user.name} ${user.surname}`} size="xl" className="ring-4 ring-slate-950" />
51 {currentUser?.user_id === user.user_id && (
52 <button className="mb-2 text-sm text-indigo-400 hover:text-indigo-300 transition-colors">
53 Edit Profile
54 </button>
55 )}
56 </div>
57 </div>
58
59 {/* User info */}
60 <div className="mb-8">
61 <div className="flex items-center gap-3 mb-1">
62 <h1 className="font-serif text-2xl font-bold text-white">
63 {user.name} {user.surname}
64 </h1>
65 <RoleBadge role={user.role} />
66 </div>
67 <p className="text-slate-400">@{user.username}</p>
68 {user.bio && <p className="text-slate-300 mt-3 max-w-xl">{user.bio}</p>}
69 <div className="flex items-center gap-4 mt-4 flex-wrap">
70 <span className="flex items-center gap-1 text-slate-400 text-sm">
71 <Calendar size={14} />
72 Joined {new Date(user.created_at).toLocaleDateString('en-US', { month: 'long', year: 'numeric' })}
73 </span>
74 <span className="flex items-center gap-1 text-slate-400 text-sm">
75 <Users size={14} />
76 {user.follower_count} followers · {user.following_count} following
77 </span>
78 </div>
79 </div>
80
81 {/* Stats */}
82 <div className="grid grid-cols-2 sm:grid-cols-4 gap-4 mb-8">
83 {[
84 { icon: <BookOpen size={16} className="text-indigo-400" />, value: userStories.length, label: 'Stories' },
85 { icon: <Heart size={16} className="text-rose-400" />, value: totalLikes.toLocaleString(), label: 'Likes' },
86 { icon: <Eye size={16} className="text-blue-400" />, value: totalViews.toLocaleString(), label: 'Views' },
87 { icon: <MessageCircle size={16} className="text-amber-400" />, value: userComments.length, label: 'Comments' },
88 ].map(s => (
89 <div key={s.label} className="bg-slate-800 border border-slate-700 rounded-xl p-4 text-center">
90 <div className="flex justify-center mb-1">{s.icon}</div>
91 <p className="text-xl font-bold text-white">{s.value}</p>
92 <p className="text-slate-500 text-xs">{s.label}</p>
93 </div>
94 ))}
95 </div>
96
97 {/* Tabs */}
98 <div className="flex gap-1 p-1 bg-slate-800 rounded-xl mb-6 w-fit">
99 {(['stories', 'about'] as Tab[]).map(t => (
100 <button
101 key={t}
102 onClick={() => setTab(t)}
103 className={`px-4 py-2 rounded-lg text-sm font-medium capitalize transition-colors ${
104 tab === t ? 'bg-indigo-600 text-white' : 'text-slate-400 hover:text-white'
105 }`}
106 >
107 {t}
108 </button>
109 ))}
110 </div>
111
112 {/* Tab content */}
113 {tab === 'stories' ? (
114 <div>
115 {userStories.length === 0 ? (
116 <div className="text-center py-16 text-slate-500">
117 <BookOpen size={40} className="mx-auto mb-3 opacity-40" />
118 <p>No published stories yet.</p>
119 </div>
120 ) : (
121 <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
122 {userStories.map(story => (
123 <StoryCard key={story.story_id} story={story} />
124 ))}
125 </div>
126 )}
127 </div>
128 ) : (
129 <div className="space-y-6">
130 <div className="bg-slate-800 border border-slate-700 rounded-2xl p-6">
131 <h3 className="text-white font-semibold mb-3">About</h3>
132 <p className="text-slate-300">{user.bio || 'No bio provided.'}</p>
133 </div>
134 {allGenres.length > 0 && (
135 <div className="bg-slate-800 border border-slate-700 rounded-2xl p-6">
136 <h3 className="text-white font-semibold mb-3">Writes In</h3>
137 <div className="flex flex-wrap gap-2">
138 {allGenres.map(g => <GenreBadge key={g} genre={g} />)}
139 </div>
140 </div>
141 )}
142 <div className="bg-slate-800 border border-slate-700 rounded-2xl p-6">
143 <h3 className="text-white font-semibold mb-3">Stats</h3>
144 <div className="space-y-3">
145 <div className="flex justify-between text-sm">
146 <span className="text-slate-400">Role</span>
147 <RoleBadge role={user.role} />
148 </div>
149 <div className="flex justify-between text-sm">
150 <span className="text-slate-400">Member since</span>
151 <span className="text-white">{new Date(user.created_at).toLocaleDateString()}</span>
152 </div>
153 <div className="flex justify-between text-sm">
154 <span className="text-slate-400">Published stories</span>
155 <span className="text-white">{userStories.length}</span>
156 </div>
157 </div>
158 </div>
159 </div>
160 )}
161 </div>
162 )
163}
Note: See TracBrowser for help on using the repository browser.