Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit1fd56ac

Browse files
committed
create profile page
1 parentc52e5e8 commit1fd56ac

File tree

4 files changed

+177
-93
lines changed

4 files changed

+177
-93
lines changed

‎app/dashboard/page.tsx‎

Lines changed: 0 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -23,89 +23,8 @@ export default async function DashboardPage() {
2323
.eq('user_id',user.id)
2424
.order('created_at',{ascending:false})
2525

26-
constusername=
27-
user.user_metadata?.username||user.email?.split('@')[0]||'User'
28-
29-
constpublicGraphCount=userGraphs?.filter((g)=>g.is_public).length||0
30-
constprivateGraphCount=userGraphs?.filter((g)=>!g.is_public).length||0
31-
3226
return(
3327
<divclassName="container mx-auto p-4 py-8 md:py-12">
34-
<divclassName="mb-10 space-y-2">
35-
<h1className="text-3xl font-bold tracking-tight md:text-4xl">
36-
{username}&apos;s Profile
37-
</h1>
38-
<pclassName="text-muted-foreground text-lg">
39-
View your profile information and manage all your graphs.
40-
</p>
41-
</div>
42-
43-
<divclassName="mb-12 grid gap-6 md:grid-cols-2">
44-
<CardclassName="shadow-sm">
45-
<CardHeader>
46-
<CardTitleclassName="text-xl">Profile Information</CardTitle>
47-
</CardHeader>
48-
<CardContentclassName="space-y-4">
49-
<div>
50-
<h3className="text-sm font-medium text-gray-500">Username</h3>
51-
<pclassName="mt-1 text-lg font-semibold text-gray-800">
52-
{username}
53-
</p>
54-
</div>
55-
<div>
56-
<h3className="text-sm font-medium text-gray-500">Email</h3>
57-
<pclassName="mt-1 text-gray-700">{user.email}</p>
58-
</div>
59-
<div>
60-
<h3className="text-sm font-medium text-gray-500">
61-
Account Created
62-
</h3>
63-
<pclassName="mt-1 text-gray-700">
64-
{user.created_at
65-
?formatDistanceToNow(newDate(user.created_at),{
66-
addSuffix:true,
67-
})
68-
:'Unknown'}
69-
</p>
70-
</div>
71-
</CardContent>
72-
</Card>
73-
74-
<CardclassName="shadow-sm">
75-
<CardHeader>
76-
<CardTitleclassName="text-xl">Graph Statistics</CardTitle>
77-
</CardHeader>
78-
<CardContent>
79-
<divclassName="grid grid-cols-3 gap-4 text-center">
80-
<divclassName="rounded-lg border bg-gray-50 p-4">
81-
<h3className="text-sm font-medium text-gray-500">
82-
Total Graphs
83-
</h3>
84-
<pclassName="mt-1 text-3xl font-bold text-gray-800">
85-
{userGraphs?.length||0}
86-
</p>
87-
</div>
88-
<divclassName="rounded-lg border bg-gray-50 p-4">
89-
<h3className="text-sm font-medium text-gray-500">
90-
Public Graphs
91-
</h3>
92-
<pclassName="mt-1 text-3xl font-bold text-gray-800">
93-
{publicGraphCount}
94-
</p>
95-
</div>
96-
<divclassName="rounded-lg border bg-gray-50 p-4">
97-
<h3className="text-sm font-medium text-gray-500">
98-
Private Graphs
99-
</h3>
100-
<pclassName="mt-1 text-3xl font-bold text-gray-800">
101-
{privateGraphCount}
102-
</p>
103-
</div>
104-
</div>
105-
</CardContent>
106-
</Card>
107-
</div>
108-
10928
<div>
11029
<h2className="mb-6 text-2xl font-bold">Your Graphs</h2>
11130
{userGraphs&&userGraphs.length>0 ?(

‎app/profile/[username]/page.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { Avatar, AvatarFallback } from '@/components/ui/avatar'
66
import{Card,CardContent,CardHeader,CardTitle}from'@/components/ui/card'
77
import{createClient}from'@/lib/supabase/server'
88

9-
exportdefaultasyncfunctionProfilePage({
9+
exportdefaultasyncfunctionUserProfilePage({
1010
params,
1111
}:{
1212
params:Promise<{

‎app/profile/page.tsx‎

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import{formatDistanceToNow}from'date-fns'
2+
import{redirect}from'next/navigation'
3+
4+
import{Card}from'@/components/ui/card'
5+
import{CardContent}from'@/components/ui/card'
6+
import{CardHeader}from'@/components/ui/card'
7+
import{CardTitle}from'@/components/ui/card'
8+
import{Input}from'@/components/ui/input'
9+
import{createClient}from'@/lib/supabase/server'
10+
11+
exportdefaultasyncfunctionProfilePage(){
12+
constsupabase=awaitcreateClient()
13+
const{
14+
data:{ user},
15+
}=awaitsupabase.auth.getUser()
16+
17+
if(!user){
18+
redirect('/auth/login')
19+
}
20+
21+
const{data:userGraphs}=awaitsupabase
22+
.from('graphs')
23+
.select('*')
24+
.eq('user_id',user.id)
25+
.order('created_at',{ascending:false})
26+
27+
constpublicGraphCount=userGraphs?.filter((g)=>g.is_public).length||0
28+
constprivateGraphCount=userGraphs?.filter((g)=>!g.is_public).length||0
29+
constusername=
30+
user.user_metadata?.username||user.email?.split('@')[0]||'User'
31+
32+
constbaseUrl=process.env.NEXT_PUBLIC_APP_URL||'http://localhost:3000'
33+
constshareUrl=username ?`${baseUrl}/profile/${username}` :''
34+
35+
return(
36+
<divclassName="container mx-auto p-4 py-8 md:py-12">
37+
<divclassName="mb-10 space-y-2">
38+
<h1className="text-3xl font-bold tracking-tight md:text-4xl">
39+
{username}&apos;s Profile
40+
</h1>
41+
<pclassName="text-muted-foreground text-lg">
42+
View your profile information and manage all your graphs.
43+
</p>
44+
</div>
45+
46+
<divclassName="mb-12 grid gap-6 md:grid-cols-2">
47+
<CardclassName="shadow-sm">
48+
<CardHeader>
49+
<CardTitleclassName="text-xl">Profile Information</CardTitle>
50+
</CardHeader>
51+
<CardContentclassName="space-y-4">
52+
<div>
53+
<h3className="text-sm font-medium text-gray-500">Username</h3>
54+
<pclassName="mt-1 text-lg font-semibold text-gray-800">
55+
{username}
56+
</p>
57+
</div>
58+
<div>
59+
<h3className="text-sm font-medium text-gray-500">Email</h3>
60+
<pclassName="mt-1 text-gray-700">{user.email}</p>
61+
</div>
62+
<div>
63+
<h3className="text-sm font-medium text-gray-500">
64+
Account Created
65+
</h3>
66+
<pclassName="mt-1 text-gray-700">
67+
{user.created_at
68+
?formatDistanceToNow(newDate(user.created_at),{
69+
addSuffix:true,
70+
})
71+
:'Unknown'}
72+
</p>
73+
</div>
74+
<div>
75+
<h3className="text-sm font-medium text-gray-500">
76+
Share Your Profile URL
77+
</h3>
78+
<pclassName="mt-1 text-sm text-gray-600 dark:text-gray-400">
79+
Your public profile can be accessed via this URL:
80+
</p>
81+
<Input
82+
readOnly
83+
value={shareUrl}
84+
className="mt-2 w-full cursor-default rounded-lg border border-gray-300 bg-gray-50 px-3 py-2 font-mono text-xs text-gray-700 shadow-sm dark:border-gray-600 dark:bg-gray-700 dark:text-gray-300"
85+
placeholder={username ?'Profile URL' :'Username not found'}
86+
/>
87+
</div>
88+
</CardContent>
89+
</Card>
90+
91+
<CardclassName="shadow-sm">
92+
<CardHeader>
93+
<CardTitleclassName="text-xl">Graph Statistics</CardTitle>
94+
</CardHeader>
95+
<CardContent>
96+
<divclassName="grid grid-cols-3 gap-4 text-center">
97+
<divclassName="rounded-lg border bg-gray-50 p-4">
98+
<h3className="text-sm font-medium text-gray-500">
99+
Total Graphs
100+
</h3>
101+
<pclassName="mt-1 text-3xl font-bold text-gray-800">
102+
{userGraphs?.length||0}
103+
</p>
104+
</div>
105+
<divclassName="rounded-lg border bg-gray-50 p-4">
106+
<h3className="text-sm font-medium text-gray-500">
107+
Public Graphs
108+
</h3>
109+
<pclassName="mt-1 text-3xl font-bold text-gray-800">
110+
{publicGraphCount}
111+
</p>
112+
</div>
113+
<divclassName="rounded-lg border bg-gray-50 p-4">
114+
<h3className="text-sm font-medium text-gray-500">
115+
Private Graphs
116+
</h3>
117+
<pclassName="mt-1 text-3xl font-bold text-gray-800">
118+
{privateGraphCount}
119+
</p>
120+
</div>
121+
</div>
122+
</CardContent>
123+
</Card>
124+
</div>
125+
</div>
126+
)
127+
}

‎components/TopBar.tsx‎

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { LogOut } from 'lucide-react'
99
import{Menu}from'lucide-react'
1010
import{X}from'lucide-react'
1111
import{Plus}from'lucide-react'
12+
import{UserCircle}from'lucide-react'
1213
importLinkfrom'next/link'
1314
import{useRouter}from'next/navigation'
1415
import{useEffect,useState}from'react'
@@ -119,14 +120,26 @@ export function TopBar() {
119120
</Link>
120121
</li>
121122
{user&&(
122-
<lirole="none">
123-
<Linkhref="/create">
124-
<Buttonsize="sm"className="gap-2 bg-green-600">
125-
<PlusclassName="h-4 w-4"/>
126-
Create
127-
</Button>
128-
</Link>
129-
</li>
123+
<>
124+
<lirole="none">
125+
<Link
126+
href="/dashboard"
127+
className="text-muted-foreground hover:text-foreground flex items-center space-x-1 text-sm font-medium transition-colors"
128+
role="menuitem"
129+
>
130+
<LayoutDashboardclassName="h-4 w-4"aria-hidden="true"/>
131+
<span>Dashboard</span>
132+
</Link>
133+
</li>
134+
<lirole="none">
135+
<Linkhref="/create">
136+
<Buttonsize="sm"className="gap-2 bg-green-600">
137+
<PlusclassName="h-4 w-4"/>
138+
Create
139+
</Button>
140+
</Link>
141+
</li>
142+
</>
130143
)}
131144

132145
<lirole="none">
@@ -158,15 +171,15 @@ export function TopBar() {
158171
<DropdownMenuContentalign="end"className="w-56"role="menu">
159172
<DropdownMenuItemasChildrole="none">
160173
<Link
161-
href="/dashboard"
174+
href="/profile"
162175
className="flex cursor-pointer items-center"
163176
role="menuitem"
164177
>
165-
<LayoutDashboard
178+
<UserCircle
166179
className="mr-2 h-4 w-4"
167180
aria-hidden="true"
168181
/>
169-
Dashboard
182+
Profile
170183
</Link>
171184
</DropdownMenuItem>
172185
<DropdownMenuSeparatorrole="separator"/>
@@ -271,6 +284,31 @@ export function TopBar() {
271284
</Button>
272285
</Link>
273286
</li>
287+
<lirole="none">
288+
<Link
289+
href="/dashboard"
290+
onClick={()=>setIsMenuOpen(false)}
291+
className="text-muted-foreground hover:text-foreground flex items-center space-x-2 px-2 py-1 text-sm font-medium transition-colors"
292+
role="menuitem"
293+
>
294+
<LayoutDashboard
295+
className="mr-2 h-4 w-4"
296+
aria-hidden="true"
297+
/>
298+
<span>Dashboard</span>
299+
</Link>
300+
</li>
301+
<lirole="none">
302+
<Link
303+
href="/profile"
304+
onClick={()=>setIsMenuOpen(false)}
305+
className="text-muted-foreground hover:text-foreground flex items-center space-x-2 px-2 py-1 text-sm font-medium transition-colors"
306+
role="menuitem"
307+
>
308+
<UserCircleclassName="mr-2 h-4 w-4"aria-hidden="true"/>
309+
<span>Profile</span>
310+
</Link>
311+
</li>
274312
<lirole="none">
275313
<Button
276314
variant="ghost"

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp