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
138export 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}
0 commit comments