1- // 사용자 프로필 페이지
1+ "use client"
2+
3+ import { useState } from "react"
4+ import { useAuth } from "@/hooks/auth/useAuth"
5+ import { userApi } from "@/lib/api/user"
6+ import { Button } from "@/components/ui/Button"
7+ import { Input } from "@/components/ui/input"
8+ import { Label } from "@/components/ui/label"
9+ import { Card } from "@/components/ui/card"
10+ import { useToast } from "@/components/ui/Toast"
11+ import { User , Mail , Lock , Save } from "lucide-react"
12+
13+ export default function ProfilePage ( ) {
14+ const { user, fetchUserInfo } = useAuth ( )
15+ const toast = useToast ( )
16+
17+ const [ isEditingName , setIsEditingName ] = useState ( false )
18+ const [ isEditingPassword , setIsEditingPassword ] = useState ( false )
19+ const [ name , setName ] = useState ( user ?. name || "" )
20+ const [ password , setPassword ] = useState ( "" )
21+ const [ passwordCheck , setPasswordCheck ] = useState ( "" )
22+ const [ isLoading , setIsLoading ] = useState ( false )
23+
24+ const handleNameUpdate = async ( ) => {
25+ if ( ! name . trim ( ) ) {
26+ toast . push ( "이름을 입력해주세요." )
27+ return
28+ }
29+
30+ try {
31+ setIsLoading ( true )
32+ await userApi . updateName ( { name : name . trim ( ) } )
33+ toast . push ( "이름이 성공적으로 변경되었습니다." )
34+ setIsEditingName ( false )
35+ await fetchUserInfo ( ) // 사용자 정보 새로고침
36+ } catch ( error ) {
37+ console . error ( "이름 변경 실패:" , error )
38+ toast . push ( "이름 변경에 실패했습니다." )
39+ } finally {
40+ setIsLoading ( false )
41+ }
42+ }
43+
44+ const handlePasswordUpdate = async ( ) => {
45+ if ( ! password . trim ( ) ) {
46+ toast . push ( "새 비밀번호를 입력해주세요." )
47+ return
48+ }
49+
50+ if ( password !== passwordCheck ) {
51+ toast . push ( "비밀번호가 일치하지 않습니다." )
52+ return
53+ }
54+
55+ if ( password . length < 6 ) {
56+ toast . push ( "비밀번호는 6자 이상이어야 합니다." )
57+ return
58+ }
59+
60+ try {
61+ setIsLoading ( true )
62+ await userApi . updatePassword ( {
63+ password : password . trim ( ) ,
64+ passwordCheck : passwordCheck . trim ( )
65+ } )
66+ toast . push ( "비밀번호가 성공적으로 변경되었습니다." )
67+ setIsEditingPassword ( false )
68+ setPassword ( "" )
69+ setPasswordCheck ( "" )
70+ } catch ( error ) {
71+ console . error ( "비밀번호 변경 실패:" , error )
72+ toast . push ( "비밀번호 변경에 실패했습니다." )
73+ } finally {
74+ setIsLoading ( false )
75+ }
76+ }
77+
78+ const cancelNameEdit = ( ) => {
79+ setName ( user ?. name || "" )
80+ setIsEditingName ( false )
81+ }
82+
83+ const cancelPasswordEdit = ( ) => {
84+ setPassword ( "" )
85+ setPasswordCheck ( "" )
86+ setIsEditingPassword ( false )
87+ }
88+
89+ if ( ! user ) {
90+ return (
91+ < div className = "min-h-screen bg-background flex items-center justify-center" >
92+ < div className = "text-center" >
93+ < h1 className = "text-2xl font-bold mb-4" > 로그인이 필요합니다</ h1 >
94+ < p className = "text-muted-foreground" > 마이페이지를 보려면 로그인해주세요.</ p >
95+ </ div >
96+ </ div >
97+ )
98+ }
99+
100+ return (
101+ < div className = "min-h-screen bg-background" >
102+ < div className = "container mx-auto px-4 sm:px-6 lg:px-8 py-16" >
103+ < div className = "mx-auto max-w-2xl" >
104+ < div className = "mb-8 text-center" >
105+ < h1 className = "text-3xl font-bold mb-2" > 마이페이지</ h1 >
106+ < p className = "text-muted-foreground" > 개인정보를 수정할 수 있습니다.</ p >
107+ </ div >
108+
109+ < div className = "space-y-6" >
110+ { /* 이메일 정보 (수정 불가) */ }
111+ < Card className = "p-6" >
112+ < div className = "flex items-center gap-3 mb-4" >
113+ < Mail className = "h-5 w-5 text-muted-foreground" />
114+ < h2 className = "text-lg font-semibold" > 이메일</ h2 >
115+ </ div >
116+ < div className = "flex items-center justify-between" >
117+ < span className = "text-muted-foreground" > { user . email } </ span >
118+ < span className = "text-xs bg-muted px-2 py-1 rounded" > 고정</ span >
119+ </ div >
120+ </ Card >
121+
122+ { /* 이름 수정 */ }
123+ < Card className = "p-6" >
124+ < div className = "flex items-center gap-3 mb-4" >
125+ < User className = "h-5 w-5 text-muted-foreground" />
126+ < h2 className = "text-lg font-semibold" > 이름</ h2 >
127+ </ div >
128+
129+ { isEditingName ? (
130+ < div className = "space-y-4" >
131+ < div >
132+ < Label htmlFor = "name" > 새 이름</ Label >
133+ < Input
134+ id = "name"
135+ value = { name }
136+ onChange = { ( e ) => setName ( e . target . value ) }
137+ placeholder = "이름을 입력하세요"
138+ disabled = { isLoading }
139+ />
140+ </ div >
141+ < div className = "flex gap-2" >
142+ < Button
143+ onClick = { handleNameUpdate }
144+ disabled = { isLoading }
145+ size = "sm"
146+ >
147+ < Save className = "h-4 w-4 mr-2" />
148+ { isLoading ? "저장 중..." : "저장" }
149+ </ Button >
150+ < Button
151+ variant = "outline"
152+ onClick = { cancelNameEdit }
153+ disabled = { isLoading }
154+ size = "sm"
155+ >
156+ 취소
157+ </ Button >
158+ </ div >
159+ </ div >
160+ ) : (
161+ < div className = "flex items-center justify-between" >
162+ < span className = "text-muted-foreground" > { user . name } </ span >
163+ < Button
164+ variant = "outline"
165+ onClick = { ( ) => setIsEditingName ( true ) }
166+ size = "sm"
167+ >
168+ 수정
169+ </ Button >
170+ </ div >
171+ ) }
172+ </ Card >
173+
174+ { /* 비밀번호 수정 */ }
175+ < Card className = "p-6" >
176+ < div className = "flex items-center gap-3 mb-4" >
177+ < Lock className = "h-5 w-5 text-muted-foreground" />
178+ < h2 className = "text-lg font-semibold" > 비밀번호</ h2 >
179+ </ div >
180+
181+ { isEditingPassword ? (
182+ < div className = "space-y-4" >
183+ < div >
184+ < Label htmlFor = "password" > 새 비밀번호</ Label >
185+ < Input
186+ id = "password"
187+ type = "password"
188+ value = { password }
189+ onChange = { ( e ) => setPassword ( e . target . value ) }
190+ placeholder = "새 비밀번호를 입력하세요"
191+ disabled = { isLoading }
192+ />
193+ </ div >
194+ < div >
195+ < Label htmlFor = "passwordCheck" > 비밀번호 확인</ Label >
196+ < Input
197+ id = "passwordCheck"
198+ type = "password"
199+ value = { passwordCheck }
200+ onChange = { ( e ) => setPasswordCheck ( e . target . value ) }
201+ placeholder = "비밀번호를 다시 입력하세요"
202+ disabled = { isLoading }
203+ />
204+ </ div >
205+ < div className = "flex gap-2" >
206+ < Button
207+ onClick = { handlePasswordUpdate }
208+ disabled = { isLoading }
209+ size = "sm"
210+ >
211+ < Save className = "h-4 w-4 mr-2" />
212+ { isLoading ? "저장 중..." : "저장" }
213+ </ Button >
214+ < Button
215+ variant = "outline"
216+ onClick = { cancelPasswordEdit }
217+ disabled = { isLoading }
218+ size = "sm"
219+ >
220+ 취소
221+ </ Button >
222+ </ div >
223+ </ div >
224+ ) : (
225+ < div className = "flex items-center justify-between" >
226+ < span className = "text-muted-foreground" > ••••••••</ span >
227+ < Button
228+ variant = "outline"
229+ onClick = { ( ) => setIsEditingPassword ( true ) }
230+ size = "sm"
231+ >
232+ 수정
233+ </ Button >
234+ </ div >
235+ ) }
236+ </ Card >
237+ </ div >
238+ </ div >
239+ </ div >
240+ </ div >
241+ )
242+ }
0 commit comments