Skip to content

Commit f3c17bd

Browse files
committed
Fix
1 parent be55633 commit f3c17bd

File tree

5 files changed

+136
-132
lines changed

5 files changed

+136
-132
lines changed

app/profile/page.tsx

Lines changed: 3 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -1,136 +1,10 @@
1-
'use client'
1+
import ProfileClient from './profile-client'
22

3-
import { useEffect, useState } from 'react'
4-
import { supabase } from '@/lib/supabase/client'
5-
import { useRouter } from 'next/navigation'
6-
import type { Metadata } from 'next'
7-
8-
export const metadata: Metadata = {
3+
export const metadata = {
94
title: 'Profile – ChatGPT Clone',
105
description: 'Manage your profile, update your name, or delete your account.'
116
}
127

138
export default function ProfilePage() {
14-
const [profile, setProfile] = useState<{ email: string; full_name: string } | null>(null)
15-
const [fullName, setFullName] = useState('')
16-
const [loading, setLoading] = useState(true)
17-
const [error, setError] = useState<string | null>(null)
18-
const [success, setSuccess] = useState<string | null>(null)
19-
const router = useRouter()
20-
21-
useEffect(() => {
22-
let ignore = false
23-
async function fetchProfile() {
24-
setLoading(true)
25-
setError(null)
26-
const { data: { user }, error: userError } = await supabase.auth.getUser()
27-
if (userError || !user) {
28-
router.replace('/sign-in')
29-
return
30-
}
31-
const { data, error: profileError } = await supabase
32-
.from('users')
33-
.select('email, full_name')
34-
.eq('id', user.id)
35-
.single()
36-
if (!ignore) {
37-
if (profileError) setError(profileError.message)
38-
else {
39-
setProfile({
40-
email: data?.email || '',
41-
full_name: data?.full_name || '',
42-
})
43-
setFullName(data?.full_name || '')
44-
}
45-
setLoading(false)
46-
}
47-
}
48-
fetchProfile()
49-
return () => { ignore = true }
50-
}, [router])
51-
52-
const handleSave = async () => {
53-
setError(null)
54-
setSuccess(null)
55-
setLoading(true)
56-
const { data: { user } } = await supabase.auth.getUser()
57-
const { error: updateError } = await supabase
58-
.from('users')
59-
.update({ full_name: fullName })
60-
.eq('id', user?.id || '')
61-
if (updateError) setError(updateError.message)
62-
else setSuccess('Profile updated!')
63-
setLoading(false)
64-
}
65-
66-
const handleLogout = async () => {
67-
await supabase.auth.signOut()
68-
router.replace('/sign-in')
69-
}
70-
71-
const handleDelete = async () => {
72-
setError(null)
73-
setSuccess(null)
74-
setLoading(true)
75-
const { data: { user } } = await supabase.auth.getUser()
76-
// You should use a secure API route for this in production
77-
const { error: deleteError } = await supabase.from('users').delete().eq('id', user?.id || '')
78-
if (deleteError) setError(deleteError.message)
79-
else {
80-
await supabase.auth.signOut()
81-
router.replace('/sign-up')
82-
}
83-
setLoading(false)
84-
}
85-
86-
if (loading) return <div className="flex justify-center items-center h-64 text-muted-foreground">Loading...</div>
87-
88-
return (
89-
<div className="max-w-lg mx-auto mt-12 bg-card rounded-xl shadow-2xl p-8 text-card-foreground">
90-
<h1 className="text-2xl font-bold mb-6">Profile</h1>
91-
<div className="mb-4">
92-
<label className="block text-muted-foreground mb-1">Email</label>
93-
<input
94-
type="email"
95-
value={profile?.email || ''}
96-
disabled
97-
className="w-full bg-input border border-border rounded px-3 py-2 text-foreground opacity-60 cursor-not-allowed"
98-
/>
99-
</div>
100-
<div className="mb-6">
101-
<label className="block text-muted-foreground mb-1">Full Name</label>
102-
<input
103-
type="text"
104-
value={fullName || ''}
105-
onChange={e => setFullName(e.target.value)}
106-
className="w-full bg-input border border-border rounded px-3 py-2 text-foreground"
107-
name="full_name"
108-
autoComplete="off"
109-
/>
110-
<button
111-
onClick={handleSave}
112-
className="mt-2 bg-primary hover:bg-primary/90 text-primary-foreground font-semibold px-4 py-2 rounded"
113-
disabled={loading || !fullName.trim()}
114-
>
115-
Save
116-
</button>
117-
</div>
118-
<div className="flex gap-2 mt-6">
119-
<button
120-
onClick={handleLogout}
121-
className="bg-muted text-foreground font-semibold px-4 py-2 rounded border border-border"
122-
>
123-
Log out
124-
</button>
125-
<button
126-
onClick={handleDelete}
127-
className="bg-destructive hover:bg-red-700 text-white font-semibold px-4 py-2 rounded"
128-
>
129-
Delete Account
130-
</button>
131-
</div>
132-
{error && <div className="text-destructive text-sm mt-4">{error}</div>}
133-
{success && <div className="text-green-500 text-sm mt-4">{success}</div>}
134-
</div>
135-
)
9+
return <ProfileClient />
13610
}

app/profile/profile-client.tsx

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
'use client'
2+
3+
import { useEffect, useState } from 'react'
4+
import { supabase } from '@/lib/supabase/client'
5+
import { useRouter } from 'next/navigation'
6+
7+
export default function ProfileClient() {
8+
const [profile, setProfile] = useState<{ email: string; full_name: string } | null>(null)
9+
const [fullName, setFullName] = useState('')
10+
const [loading, setLoading] = useState(true)
11+
const [error, setError] = useState<string | null>(null)
12+
const [success, setSuccess] = useState<string | null>(null)
13+
const router = useRouter()
14+
15+
useEffect(() => {
16+
let ignore = false
17+
async function fetchProfile() {
18+
setLoading(true)
19+
setError(null)
20+
const { data: { user }, error: userError } = await supabase.auth.getUser()
21+
if (userError || !user) {
22+
router.replace('/sign-in')
23+
return
24+
}
25+
const { data, error: profileError } = await supabase
26+
.from('users')
27+
.select('email, full_name')
28+
.eq('id', user.id)
29+
.single()
30+
if (!ignore) {
31+
if (profileError) setError(profileError.message)
32+
else {
33+
setProfile({
34+
email: data?.email || '',
35+
full_name: data?.full_name || '',
36+
})
37+
setFullName(data?.full_name || '')
38+
}
39+
setLoading(false)
40+
}
41+
}
42+
fetchProfile()
43+
return () => { ignore = true }
44+
}, [router])
45+
46+
const handleSave = async () => {
47+
setError(null)
48+
setSuccess(null)
49+
setLoading(true)
50+
const { data: { user } } = await supabase.auth.getUser()
51+
const { error: updateError } = await supabase
52+
.from('users')
53+
.update({ full_name: fullName })
54+
.eq('id', user?.id || '')
55+
if (updateError) setError(updateError.message)
56+
else setSuccess('Profile updated!')
57+
setLoading(false)
58+
}
59+
60+
const handleLogout = async () => {
61+
await supabase.auth.signOut()
62+
router.replace('/sign-in')
63+
}
64+
65+
const handleDelete = async () => {
66+
setError(null)
67+
setSuccess(null)
68+
setLoading(true)
69+
const { data: { user } } = await supabase.auth.getUser()
70+
// You should use a secure API route for this in production
71+
const { error: deleteError } = await supabase.from('users').delete().eq('id', user?.id || '')
72+
if (deleteError) setError(deleteError.message)
73+
else {
74+
await supabase.auth.signOut()
75+
router.replace('/sign-up')
76+
}
77+
setLoading(false)
78+
}
79+
80+
if (loading) return <div className="flex justify-center items-center h-64 text-muted-foreground">Loading...</div>
81+
82+
return (
83+
<div className="max-w-lg mx-auto mt-12 bg-card rounded-xl shadow-2xl p-8 text-card-foreground">
84+
<h1 className="text-2xl font-bold mb-6">Profile</h1>
85+
<div className="mb-4">
86+
<label className="block text-muted-foreground mb-1">Email</label>
87+
<input
88+
type="email"
89+
value={profile?.email || ''}
90+
disabled
91+
className="w-full bg-input border border-border rounded px-3 py-2 text-foreground opacity-60 cursor-not-allowed"
92+
/>
93+
</div>
94+
<div className="mb-6">
95+
<label className="block text-muted-foreground mb-1">Full Name</label>
96+
<input
97+
type="text"
98+
value={fullName || ''}
99+
onChange={e => setFullName(e.target.value)}
100+
className="w-full bg-input border border-border rounded px-3 py-2 text-foreground"
101+
name="full_name"
102+
autoComplete="off"
103+
/>
104+
<button
105+
onClick={handleSave}
106+
className="mt-2 bg-primary hover:bg-primary/90 text-primary-foreground font-semibold px-4 py-2 rounded"
107+
disabled={loading || !fullName.trim()}
108+
>
109+
Save
110+
</button>
111+
</div>
112+
<div className="flex gap-2 mt-6">
113+
<button
114+
onClick={handleLogout}
115+
className="bg-muted text-foreground font-semibold px-4 py-2 rounded border border-border"
116+
>
117+
Log out
118+
</button>
119+
<button
120+
onClick={handleDelete}
121+
className="bg-destructive hover:bg-red-700 text-white font-semibold px-4 py-2 rounded"
122+
>
123+
Delete Account
124+
</button>
125+
</div>
126+
{error && <div className="text-destructive text-sm mt-4">{error}</div>}
127+
{success && <div className="text-green-500 text-sm mt-4">{success}</div>}
128+
</div>
129+
)
130+
}

components/chat/sidebar.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ export default function Sidebar({ open, setOpen }: { open: boolean, setOpen: (op
8888
>
8989
{open ? (
9090
<>
91-
<SidebarHeader open={open} setOpen={setOpen} userId={userId} defaultModel={defaultModel} />
91+
<SidebarHeader open={open} setOpen={setOpen} userId={userId} />
9292
{/* Search input always visible */}
9393
<div className="px-2 pb-2">
9494
<input

hooks/use-delete-conversation.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export function useDeleteConversation(options?: UseMutationOptions<
3030
queryClient.setQueryData(['conversations', variables.user_id], context.previous)
3131
}
3232
},
33-
onSuccess: (_data, variables, context?: { previous: { id: string; user_id: string }[] }) => {
33+
onSuccess: (_data, variables, context: { previous: { id: string; user_id: string }[] }) => {
3434
queryClient.invalidateQueries({ queryKey: ['conversations', variables.user_id] })
3535
options?.onSuccess?.(_data, variables, context)
3636
},

hooks/use-update-conversation.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export function useUpdateConversation(options?: UseMutationOptions<
3030
queryClient.setQueryData(['conversations', variables.user_id], context.previous)
3131
}
3232
},
33-
onSuccess: (_data, variables, context?: { previous: { id: string; user_id: string; title: string }[] }) => {
33+
onSuccess: (_data, variables, context: { previous: { id: string; user_id: string; title: string }[] }) => {
3434
queryClient.invalidateQueries({ queryKey: ['conversations', variables.user_id] })
3535
options?.onSuccess?.(_data, variables, context)
3636
},

0 commit comments

Comments
 (0)