Skip to content

Commit ae80fba

Browse files
authored
Merge pull request #95 from codeunia-dev/feat/implementprofileview
feat: implement profile view and enhance profile page with new components
2 parents 6b00b51 + 9c762e9 commit ae80fba

File tree

8 files changed

+524
-4
lines changed

8 files changed

+524
-4
lines changed

app/protected/profile/page.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,20 @@ export default async function ProfilePage() {
3535
<div className="relative">
3636
<ProfileSettings />
3737
</div>
38+
39+
{/* View Profile Link */}
40+
<div className="text-center">
41+
<a
42+
href="/protected/profile/view"
43+
className="inline-flex items-center gap-2 px-6 py-3 bg-gradient-to-r from-green-500 to-blue-600 text-white rounded-lg hover:from-green-600 hover:to-blue-700 transition-all duration-200 font-medium"
44+
>
45+
<svg className="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
46+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
47+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
48+
</svg>
49+
View Your Profile
50+
</a>
51+
</div>
3852
</div>
3953
</div>
4054
);

app/protected/profile/view.tsx

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import React from 'react';
2+
import { useProfile } from '@/hooks/useProfile';
3+
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card';
4+
import { Loader2, User, MapPin, Briefcase } from 'lucide-react';
5+
6+
export default function ProfileView() {
7+
const { profile, loading } = useProfile();
8+
9+
if (loading) {
10+
return (
11+
<div className="flex items-center justify-center p-8">
12+
<Loader2 className="h-8 w-8 animate-spin" />
13+
</div>
14+
);
15+
}
16+
17+
if (!profile) {
18+
return <div className="text-center">Profile not found.</div>;
19+
}
20+
21+
return (
22+
<div className="max-w-3xl mx-auto p-6 space-y-6">
23+
<Card className="hover:shadow-lg transition-shadow">
24+
<CardHeader>
25+
<CardTitle className="flex items-center gap-2">
26+
<User className="h-5 w-5" />
27+
{profile.display_name || `${profile.first_name} ${profile.last_name}`}
28+
</CardTitle>
29+
<CardDescription>Your public profile information</CardDescription>
30+
</CardHeader>
31+
<CardContent className="space-y-4">
32+
<div className="flex items-center gap-2">
33+
<MapPin className="h-4 w-4" />
34+
{profile.location || 'Location not set'}
35+
</div>
36+
<div className="flex items-center gap-2">
37+
<Briefcase className="h-4 w-4" />
38+
{profile.current_position || 'Position not set'} at {profile.company || 'Company not set'}
39+
</div>
40+
<div>
41+
<h2 className="text-lg font-medium">Bio</h2>
42+
<p>{profile.bio || 'No bio available.'}</p>
43+
</div>
44+
</CardContent>
45+
</Card>
46+
</div>
47+
);
48+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { redirect } from "next/navigation";
2+
import { createClient } from "@/lib/supabase/server";
3+
import { ProfileView } from "@/components/users/ProfileView";
4+
5+
export default async function ProfileViewPage() {
6+
const supabase = await createClient();
7+
8+
const { data, error } = await supabase.auth.getUser();
9+
if (error || !data?.user) {
10+
redirect("/auth/signin");
11+
}
12+
13+
return (
14+
<div className="flex-1 w-full flex flex-col gap-8 p-6 max-w-6xl mx-auto">
15+
<div className="space-y-6">
16+
{/* Page Header */}
17+
<div className="text-center space-y-4">
18+
<div className="inline-flex items-center justify-center w-16 h-16 bg-gradient-to-br from-green-500 to-blue-600 rounded-full mb-4">
19+
<svg className="h-8 w-8 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
20+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
21+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
22+
</svg>
23+
</div>
24+
25+
<div className="space-y-2">
26+
<h1 className="text-4xl md:text-5xl font-bold bg-gradient-to-r from-gray-900 via-green-800 to-blue-800 dark:from-white dark:via-green-200 dark:to-blue-200 bg-clip-text text-transparent">
27+
Profile View
28+
</h1>
29+
<p className="text-xl text-gray-600 dark:text-gray-300 font-medium">
30+
See how your profile appears to others
31+
</p>
32+
</div>
33+
</div>
34+
35+
{/* Profile View Component */}
36+
<div className="relative">
37+
<ProfileView />
38+
</div>
39+
</div>
40+
</div>
41+
);
42+
}

components/ui/avatar.tsx

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
"use client"
2+
3+
import * as React from "react"
4+
import * as AvatarPrimitive from "@radix-ui/react-avatar"
5+
6+
import { cn } from "@/lib/utils"
7+
8+
const Avatar = React.forwardRef<
9+
React.ElementRef<typeof AvatarPrimitive.Root>,
10+
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>
11+
>(({ className, ...props }, ref) => (
12+
<AvatarPrimitive.Root
13+
ref={ref}
14+
className={cn(
15+
"relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",
16+
className
17+
)}
18+
{...props}
19+
/>
20+
))
21+
Avatar.displayName = AvatarPrimitive.Root.displayName
22+
23+
const AvatarImage = React.forwardRef<
24+
React.ElementRef<typeof AvatarPrimitive.Image>,
25+
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>
26+
>(({ className, ...props }, ref) => (
27+
<AvatarPrimitive.Image
28+
ref={ref}
29+
className={cn("aspect-square h-full w-full", className)}
30+
{...props}
31+
/>
32+
))
33+
AvatarImage.displayName = AvatarPrimitive.Image.displayName
34+
35+
const AvatarFallback = React.forwardRef<
36+
React.ElementRef<typeof AvatarPrimitive.Fallback>,
37+
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>
38+
>(({ className, ...props }, ref) => (
39+
<AvatarPrimitive.Fallback
40+
ref={ref}
41+
className={cn(
42+
"flex h-full w-full items-center justify-center rounded-full bg-muted",
43+
className
44+
)}
45+
{...props}
46+
/>
47+
))
48+
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName
49+
50+
export { Avatar, AvatarImage, AvatarFallback }

0 commit comments

Comments
 (0)