Skip to content

Commit b666244

Browse files
committed
tes
1 parent c70dea3 commit b666244

File tree

2 files changed

+284
-255
lines changed

2 files changed

+284
-255
lines changed

app/profile/UserProfileContent.tsx

Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
// app/profile/UserProfileContent.tsx
2+
"use client";
3+
4+
import React, { useState, useEffect } from "react";
5+
import { useAuth } from "@/app/context/AuthContext";
6+
import {
7+
Card,
8+
CardContent,
9+
CardHeader,
10+
CardTitle,
11+
CardDescription,
12+
CardFooter,
13+
} from "@/components/ui/card";
14+
import { Button } from "@/components/ui/button";
15+
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
16+
import BadgeDisplay from "@/components/BadgeDisplay";
17+
import AuthenticationDialog from "@/components/AuthenticationDialog";
18+
import UserProjectRequests from "@/components/UserProjectRequests";
19+
import { useRouter, useSearchParams } from "next/navigation";
20+
import {
21+
Award,
22+
Star,
23+
MessageSquare,
24+
User,
25+
Settings,
26+
FileText,
27+
} from "lucide-react";
28+
import ProfileForm from "@/components/ProfileForm";
29+
30+
interface ProfileStats {
31+
ratings: number;
32+
comments: number;
33+
submissions: number;
34+
}
35+
36+
const UserProfileContent = () => {
37+
const { user, isAuthenticated } = useAuth();
38+
const router = useRouter();
39+
const searchParams = useSearchParams();
40+
const tabParam = searchParams.get('tab');
41+
42+
const [showAuthDialog, setShowAuthDialog] = useState(false);
43+
const [stats, setStats] = useState<ProfileStats>({
44+
ratings: 0,
45+
comments: 0,
46+
submissions: 0,
47+
});
48+
const [activeTab, setActiveTab] = useState<string>("profile");
49+
50+
useEffect(() => {
51+
if (!isAuthenticated) {
52+
setShowAuthDialog(true);
53+
} else if (user) {
54+
// Set active tab from URL parameter if present
55+
if (tabParam && ['profile', 'my-requests'].includes(tabParam)) {
56+
setActiveTab(tabParam);
57+
}
58+
59+
// Fetch user stats
60+
const fetchStats = async () => {
61+
try {
62+
const [ratingsRes, commentsRes] = await Promise.all([
63+
fetch(`/api/ratings?userId=${user.id}`),
64+
fetch(`/api/comments?userId=${user.id}`),
65+
]);
66+
67+
const ratings = await ratingsRes.json();
68+
const comments = await commentsRes.json();
69+
70+
setStats({
71+
ratings: ratings.length,
72+
comments: comments.length,
73+
submissions: 0, // Will be updated when we fetch project requests
74+
});
75+
} catch (error) {
76+
console.error("Error fetching user stats:", error);
77+
}
78+
};
79+
80+
fetchStats();
81+
}
82+
}, [isAuthenticated, user, tabParam]);
83+
84+
if (!isAuthenticated) {
85+
return (
86+
<div className="min-h-screen bg-gradient-to-br from-slate-900 via-slate-800 to-slate-900 py-12 mt-10">
87+
<div className="container mx-auto px-4">
88+
<div className="max-w-md mx-auto bg-slate-800/50 border border-slate-700 rounded-lg p-8 text-center">
89+
<h1 className="text-2xl font-bold text-white mb-4">Profile</h1>
90+
<p className="text-gray-400 mb-6">
91+
You need to be signed in to view your profile.
92+
</p>
93+
<Button
94+
onClick={() => setShowAuthDialog(true)}
95+
className="bg-purple-500 hover:bg-purple-600 text-white"
96+
>
97+
Sign In
98+
</Button>
99+
100+
<AuthenticationDialog
101+
isOpen={showAuthDialog}
102+
onOpenChange={setShowAuthDialog}
103+
/>
104+
</div>
105+
</div>
106+
</div>
107+
);
108+
}
109+
110+
if (!user) return null;
111+
112+
const levelProgress = user.points % 100;
113+
const pointsToNextLevel = 100 - levelProgress;
114+
115+
return (
116+
<div className="min-h-screen bg-gradient-to-br from-slate-900 via-slate-800 to-slate-900 py-12 mt-10">
117+
<div className="container mx-auto px-4">
118+
<div className="max-w-5xl mx-auto">
119+
<h1 className="text-3xl font-bold text-white text-center mb-8">
120+
Your Profile
121+
</h1>
122+
123+
<div className="grid grid-cols-1 lg:grid-cols-4 gap-8">
124+
{/* Sidebar */}
125+
<div className="lg:col-span-1">
126+
<Card className="bg-slate-800/50 border-slate-700 text-white h-fit">
127+
<CardHeader className="pb-4">
128+
<CardTitle className="text-xl">
129+
<User className="inline-block mr-2 text-purple-400" />
130+
{user.displayName}
131+
</CardTitle>
132+
<CardDescription className="text-gray-400">
133+
@{user.username}
134+
</CardDescription>
135+
</CardHeader>
136+
<CardContent className="space-y-4">
137+
<div className="flex flex-col items-center">
138+
<div className="relative mb-3">
139+
{user.avatarUrl ? (
140+
<img
141+
src={user.avatarUrl}
142+
alt={user.displayName}
143+
className="w-24 h-24 rounded-full"
144+
/>
145+
) : (
146+
<div className="w-24 h-24 rounded-full bg-slate-700 flex items-center justify-center">
147+
<User className="h-12 w-12 text-slate-400" />
148+
</div>
149+
)}
150+
</div>
151+
152+
<div className="flex items-center gap-2 mb-1">
153+
<Award className="text-yellow-500" />
154+
<span className="font-bold">Level {user.level}</span>
155+
</div>
156+
157+
<div className="text-sm text-gray-400 mb-2">
158+
{user.points} points ({pointsToNextLevel} to Level{" "}
159+
{user.level + 1})
160+
</div>
161+
162+
<div className="w-full bg-slate-700 rounded-full h-2 mb-4">
163+
<div
164+
className="bg-gradient-to-r from-purple-500 to-blue-500 h-2 rounded-full"
165+
style={{ width: `${levelProgress}%` }}
166+
></div>
167+
</div>
168+
</div>
169+
170+
<div className="space-y-3">
171+
<div className="flex justify-between items-center">
172+
<div className="flex items-center gap-2">
173+
<Star className="text-yellow-500 w-4 h-4" />
174+
<span className="text-sm">Ratings</span>
175+
</div>
176+
<span className="font-semibold">{stats.ratings}</span>
177+
</div>
178+
179+
<div className="flex justify-between items-center">
180+
<div className="flex items-center gap-2">
181+
<MessageSquare className="text-blue-500 w-4 h-4" />
182+
<span className="text-sm">Comments</span>
183+
</div>
184+
<span className="font-semibold">{stats.comments}</span>
185+
</div>
186+
187+
<div className="flex justify-between items-center">
188+
<div className="flex items-center gap-2">
189+
<FileText className="text-green-500 w-4 h-4" />
190+
<span className="text-sm">Submissions</span>
191+
</div>
192+
<span className="font-semibold">{stats.submissions}</span>
193+
</div>
194+
</div>
195+
</CardContent>
196+
</Card>
197+
198+
<Card className="bg-slate-800/50 border-slate-700 text-white mt-6">
199+
<CardHeader>
200+
<CardTitle className="text-lg">Your Badges</CardTitle>
201+
</CardHeader>
202+
<CardContent>
203+
<BadgeDisplay userBadges={user.badges} />
204+
</CardContent>
205+
<CardFooter>
206+
<Button
207+
variant="outline"
208+
className="w-full bg-slate-700 hover:bg-slate-600 border-slate-600 text-white"
209+
onClick={() => router.push("/badges")}
210+
>
211+
View All Badges
212+
</Button>
213+
</CardFooter>
214+
</Card>
215+
</div>
216+
217+
{/* Main Content */}
218+
<div className="lg:col-span-3">
219+
<Card className="bg-slate-800/50 border-slate-700 text-white">
220+
<CardHeader>
221+
<Tabs
222+
defaultValue={activeTab}
223+
value={activeTab}
224+
onValueChange={(value) => {
225+
setActiveTab(value);
226+
router.push(`/profile?tab=${value}`);
227+
}}
228+
>
229+
<TabsList className="bg-slate-700 w-full grid grid-cols-2">
230+
<TabsTrigger
231+
value="profile"
232+
className="data-[state=active]:bg-slate-900"
233+
>
234+
<Settings className="h-4 w-4 mr-2" />
235+
Profile Settings
236+
</TabsTrigger>
237+
<TabsTrigger
238+
value="my-requests"
239+
className="data-[state=active]:bg-slate-900"
240+
>
241+
<FileText className="h-4 w-4 mr-2" />
242+
My Project Requests
243+
</TabsTrigger>
244+
</TabsList>
245+
246+
<TabsContent value="profile" className="pt-6">
247+
<ProfileForm />
248+
</TabsContent>
249+
250+
<TabsContent value="my-requests" className="pt-6">
251+
<UserProjectRequests />
252+
</TabsContent>
253+
</Tabs>
254+
</CardHeader>
255+
</Card>
256+
</div>
257+
</div>
258+
</div>
259+
</div>
260+
</div>
261+
);
262+
};
263+
264+
export default UserProfileContent;

0 commit comments

Comments
 (0)