1- import  React ,  {  useState ,  useEffect  }  from  "react" ; 
1+ import  React ,  {  useState ,  useEffect ,   useRef  }  from  "react" ; 
22import  SockJS  from  "sockjs-client" ; 
33import  Stomp  from  "stompjs" ; 
44
55const  Profile  =  ( {  userInfo } )  =>  { 
6-  const  [ seasonCommitCount ,  setSeasonCommitCount ]  =  useState ( userInfo . seasonCommitCount ) ; 
7-  const  [ petExp ,  setPetExp ]  =  useState ( userInfo . petExp ) ; 
6+  const  [ seasonCommitCount ,  setSeasonCommitCount ]  =  useState ( userInfo . seasonCommitCount   ||   0 ) ; 
7+  const  [ petExp ,  setPetExp ]  =  useState ( userInfo . petExp   ||   0 ) ; 
88 const  [ commitCount ,  setCommitCount ]  =  useState ( 0 ) ; 
99 const  [ client ,  setClient ]  =  useState ( null ) ;  // WebSocket 클라이언트 상태 
10+  const  [ lastRefreshTime ,  setLastRefreshTime ]  =  useState ( new  Date ( ) ) ; 
11+  const  [ isRefreshing ,  setIsRefreshing ]  =  useState ( false ) ; 
12+  const  refreshTimerRef  =  useRef ( null ) ; 
1013
1114 const  maxExp  =  userInfo . petGrow  ===  "EGG"  ? 150  : userInfo . petGrow  ===  "HATCH"  ? 300  : 300 ; 
15+  
16+  // 티어 아이콘 매핑 
1217 const  tierEmojis  =  { 
1318 SEED : "🌱" , 
1419 SPROUT : "🌿" , 
@@ -17,15 +22,83 @@ const Profile = ({ userInfo }) => {
1722 TREE : "🌳" , 
1823 } ; 
1924
25+  // 펫 성장 단계 한글화 
26+  const  petGrowthStages  =  { 
27+  EGG : "알" , 
28+  HATCH : "부화" , 
29+  BABY : "아기" , 
30+  ADULT : "성체" , 
31+  } ; 
32+ 
2033 // 경험치 바 계산 
2134 const  progress  =  ( petExp  /  maxExp )  *  100 ; 
2235
36+  // 프로필 정보 자동 새로고침 함수 
37+  const  refreshProfileData  =  async  ( )  =>  { 
38+  setIsRefreshing ( true ) ; 
39+  try  { 
40+  // 실제로는 여기서 API 호출을 통해 최신 데이터를 가져옵니다 
41+  const  response  =  await  fetch ( "/api/user/info" ,  {  
42+  credentials : 'include' , 
43+  headers : { 
44+  'Cache-Control' : 'no-cache' 
45+  } 
46+  } ) ; 
47+  
48+  if  ( response . ok )  { 
49+  const  data  =  await  response . json ( ) ; 
50+  // 새로운 데이터로 상태 업데이트 
51+  setSeasonCommitCount ( data . data . seasonCommitCount  ||  0 ) ; 
52+  setPetExp ( data . data . petExp  ||  0 ) ; 
53+  // 마지막 갱신 시간 업데이트 
54+  setLastRefreshTime ( new  Date ( ) ) ; 
55+  } 
56+  }  catch  ( error )  { 
57+  console . error ( "프로필 데이터 새로고침 오류:" ,  error ) ; 
58+  }  finally  { 
59+  setIsRefreshing ( false ) ; 
60+  } 
61+  } ; 
62+ 
63+  // 자동 새로고침 설정 (30초마다) 
64+  useEffect ( ( )  =>  { 
65+  refreshTimerRef . current  =  setInterval ( refreshProfileData ,  30000 ) ; 
66+  
67+  // 컴포넌트 언마운트 시 타이머 정리 
68+  return  ( )  =>  { 
69+  if  ( refreshTimerRef . current )  { 
70+  clearInterval ( refreshTimerRef . current ) ; 
71+  } 
72+  } ; 
73+  } ,  [ ] ) ; 
74+ 
2375 // userInfo가 변경되면 값 업데이트 
2476 useEffect ( ( )  =>  { 
25-  setSeasonCommitCount ( userInfo . seasonCommitCount ) ; 
26-  setPetExp ( userInfo . petExp ) ; 
77+  setSeasonCommitCount ( userInfo . seasonCommitCount  ||  0 ) ; 
78+  setPetExp ( userInfo . petExp  ||  0 ) ; 
79+  setLastRefreshTime ( new  Date ( ) ) ; 
2780 } ,  [ userInfo ] ) ; 
2881
82+  // 날짜 포맷팅 함수 
83+  const  formatDate  =  ( dateString )  =>  { 
84+  if  ( ! dateString )  return  "없음" ; 
85+  const  date  =  new  Date ( dateString ) ; 
86+  return  date . toLocaleDateString ( 'ko-KR' ,  {  
87+  year : 'numeric' ,  
88+  month : 'long' ,  
89+  day : 'numeric'  
90+  } ) ; 
91+  } ; 
92+  
93+  // 새로고침 시간 포맷팅 함수 
94+  const  formatRefreshTime  =  ( date )  =>  { 
95+  return  date . toLocaleTimeString ( 'ko-KR' ,  { 
96+  hour : '2-digit' , 
97+  minute : '2-digit' , 
98+  second : '2-digit' 
99+  } ) ; 
100+  } ; 
101+ 
29102 useEffect ( ( )  =>  { 
30103 // userInfo.username이 없으면 WebSocket 연결 안 함 
31104 if  ( ! userInfo . username )  { 
@@ -75,46 +148,100 @@ const Profile = ({ userInfo }) => {
75148 } ,  [ userInfo . username ] ) ;  // username이 변경될 때마다 WebSocket 연결 
76149
77150 return  ( 
78-  < div  className = "flex-box" > 
79-  < div  className = "profile-container" > 
80-  { /* 왼쪽: 펫 이미지 */ } 
81-  < div  className = "pet-box" > 
82-  < img  src = { `/pets/${ userInfo . petGrow }  }  alt = "Pet"  className = "animated-pet"  /> 
151+  < div  className = "profile-container" > 
152+  { /* 왼쪽: 펫 이미지 */ } 
153+  < div  className = "pet-section" > 
154+  < div  className = "pet-frame" > 
155+  < img  
156+  src = { `/pets/${ userInfo . petGrow }  }  
157+  alt = "Pet"  
158+  className = { `pet-image animated-pet ${ isRefreshing  ? 'refreshing'  : '' }  }  
159+  /> 
160+  </ div > 
161+  < div  className = "pet-stage" > 
162+  { petGrowthStages [ userInfo . petGrow ]  ||  userInfo . petGrow } 
163+  </ div > 
164+  { isRefreshing  &&  < div  className = "refreshing-indicator" > </ div > } 
165+  </ div > 
166+ 
167+  { /* 오른쪽: 사용자 정보 및 펫 정보 */ } 
168+  < div  className = "user-info" > 
169+  { /* 유저 이름과 아바타 */ } 
170+  < div  className = "user-header" > 
171+  < div  className = "avatar-container" > 
172+  < img  src = { userInfo . avatarUrl }  alt = "User Avatar"  /> 
173+  </ div > 
174+  < span  className = "username" > { userInfo . username  ||  "사용자" } </ span > 
83175 </ div > 
84176
85-  { /* 오른쪽: 사용자 정보 및 펫 정보 */ } 
86-  < div  className = "info-box" > 
87-  < div > 
88-  < img  src = { userInfo . avatarUrl }  alt = "User Avatar"  className = "avatar"  />  { userInfo . username } 
177+  { /* 유저 세부 정보 */ } 
178+  < div  className = "user-details" > 
179+  < div  className = "detail-item" > 
180+  < span  className = "detail-icon" > 📊</ span > 
181+  < span  className = "detail-text" > 
182+  이번 시즌 커밋: < span  className = "detail-value" > { seasonCommitCount } </ span > 
183+  </ span > 
184+  </ div > 
185+  
186+  < div  className = "detail-item" > 
187+  < span  className = "detail-icon" > 🔄</ span > 
188+  < span  className = "detail-text" > 
189+  업데이트 커밋: < span  className = "detail-value" > { commitCount } </ span > 
190+  </ span > 
89191 </ div > 
90-  < div > 이번 시즌 커밋 수: { seasonCommitCount } </ div > 
91-  < div > 업데이트 커밋 수: { commitCount } </ div > 
92-  < div > 티어: { tierEmojis [ userInfo . tier ]  ||  userInfo . tier }  / 마지막 커밋 날짜: { new  Date ( userInfo . lastCommitted ) . toLocaleDateString ( ) } </ div > 
93- 
94-  { /* 펫 정보 */ } 
95-  < div > 🐾 펫 정보</ div > 
96-  < div  className = "exp-bar" > 
97-  < div  className = "bar" > 
98-  < div  style = { {  width : "100%" ,  height : "5px" ,  backgroundColor : "#F3F3F3" ,  borderRadius : "2px"  } } > 
99-  < div 
100-  style = { { 
101-  width : `${ progress }  ,  // 경험치 비율 적용 
102-  height : "100%" , 
103-  backgroundColor : "#FF69B4" , 
104-  borderRadius : "2px" , 
105-  } } 
106-  /> 
107-  </ div > 
192+  
193+  < div  className = "detail-item" > 
194+  < span  className = "detail-icon" > 🏆</ span > 
195+  < span  className = "detail-text" > 
196+  티어: < span  className = "tier-badge" > 
197+  { tierEmojis [ userInfo . tier ]  ||  "" }  { userInfo . tier  ||  "없음" } 
198+  </ span > 
199+  </ span > 
200+  </ div > 
201+  
202+  < div  className = "detail-item" > 
203+  < span  className = "detail-icon" > 📅</ span > 
204+  < span  className = "detail-text" > 
205+  마지막 커밋: < span  className = "detail-value" > { formatDate ( userInfo . lastCommitted ) } </ span > 
206+  </ span > 
207+  </ div > 
208+  </ div > 
209+ 
210+  { /* 펫 정보 */ } 
211+  < div  className = "pet-info" > 
212+  < div  className = "pet-title" > 
213+  < span > 🐾</ span >  펫 정보
214+  </ div > 
215+  
216+  < div  className = "exp-bar-container" > 
217+  < div  className = "exp-bar" > 
218+  < div  
219+  className = "exp-progress"  
220+  style = { {  width : `${ progress }   } } 
221+  > </ div > 
108222 </ div > 
109-  < div > 
223+  < span   className = "exp-text" > 
110224 { petExp }  / { maxExp } 
111-  </ div > 
225+  </ span > 
226+  </ div > 
227+  
228+  { /* 새로고침 버튼 및 마지막 새로고침 시간 표시 */ } 
229+  < div  className = "refresh-info" > 
230+  < button  
231+  className = "refresh-button"  
232+  onClick = { refreshProfileData } 
233+  disabled = { isRefreshing } 
234+  > 
235+  < span  className = { `refresh-icon ${ isRefreshing  ? 'rotating'  : '' }  } > 🔄</ span > 
236+  </ button > 
237+  < span  className = "last-refresh-time" > 
238+  { isRefreshing  ? '새로고침 중...'  : `마지막 업데이트: ${ formatRefreshTime ( lastRefreshTime ) }  } 
239+  </ span > 
112240 </ div > 
113-  < div > 성장 단계: { userInfo . petGrow } </ div > 
114241 </ div > 
115242 </ div > 
116243 </ div > 
117244 ) ; 
118245} ; 
119246
120- export  default  Profile ; 
247+ export  default  Profile ; 
0 commit comments