@@ -9,8 +9,10 @@ import { Skeleton } from "@/components/ui/skeleton";
99// 2a. 서버 응답 객체의 인터페이스 (스네이크 케이스)
1010interface ServerChatRoom {
1111 id : number ;
12- post_id : number ; // 서버에서 오는 필드명
12+ post_id : number ;
1313 title : string ;
14+ member_count : number ;
15+ updated_at : Date ;
1416}
1517
1618function ChatRoomList ( ) {
@@ -21,19 +23,16 @@ function ChatRoomList() {
2123 const [ selectedRoom , setSelectedRoom ] = useState < number | null > ( null ) ;
2224 const [ selectedRoomTitle , setSelectedRoomTitle ] = useState ( "" ) ;
2325
24-
2526 const fetchData = async ( ) => {
2627 setLoading ( true ) ;
2728 setError ( null ) ;
28- const token = localStorage . getItem ( "accessToken" ) ; // 토큰 가져오기
29+ const token = localStorage . getItem ( "accessToken" ) ;
2930
3031 if ( ! token ) {
3132 console . error ( "[fetchData] Authorization token not found in localStorage." ) ;
3233 setError ( "로그인이 필요합니다. 로그인 후 다시 시도해주세요." ) ;
3334 setLoading ( false ) ;
3435 setItems ( [ ] ) ;
35- // 여기서 로그인 페이지로 리디렉션하거나 사용자에게 명확한 안내를 할 수 있습니다.
36- // 예: router.push('/login'); (Next.js 사용 시)
3736 return ;
3837 }
3938
@@ -42,18 +41,16 @@ function ChatRoomList() {
4241 cache : "no-store" ,
4342 headers : {
4443 "Content-Type" : "application/json" ,
45- "Authorization" : `Bearer ${ token } ` , // Authorization 헤더 추가
44+ "Authorization" : `Bearer ${ token } ` ,
4645 } ,
4746 } ) ;
4847
4948 if ( ! res . ok ) {
5049 if ( res . status === 401 || res . status === 403 ) {
51- const errorText = await res . text ( ) ; // 에러 본문을 읽어옴 (JSON 형태일 수도 있음)
50+ const errorText = await res . text ( ) ;
5251 console . error ( `[fetchData] Authentication error (${ res . status } ):` , errorText ) ;
5352 setError ( `인증에 실패했습니다 (${ res . status } ). 세션이 만료되었거나 권한이 없습니다. 다시 로그인해주세요.` ) ;
54- // 필요하다면 여기서 로그아웃 처리 또는 로그인 페이지로 강제 이동
5553 } else {
56- // 기타 HTTP 에러
5754 const errorText = await res . text ( ) ;
5855 console . error ( `[fetchData] HTTP error! status: ${ res . status } , message: ${ errorText } ` ) ;
5956 throw new Error ( `HTTP error! status: ${ res . status } , message: ${ errorText } ` ) ;
@@ -66,15 +63,20 @@ function ChatRoomList() {
6663 const responseData : ServerChatRoom [ ] = await res . json ( ) ;
6764
6865 if ( responseData && Array . isArray ( responseData ) ) {
69- setItems ( responseData ) ;
66+ const sortedData = responseData . map ( room => ( {
67+ ...room ,
68+ updated_at : new Date ( room . updated_at )
69+ } ) ) . sort ( ( a , b ) => {
70+ return b . updated_at . getTime ( ) - a . updated_at . getTime ( )
71+ } ) ;
72+ setItems ( sortedData ) ;
7073 } else {
7174 setItems ( [ ] ) ;
7275 console . warn ( "[fetchData] API 응답에서 data 필드를 찾을 수 없거나 형식이 배열이 아닙니다." , responseData ) ;
7376 setError ( "채팅방 목록을 가져오는 데 실패했습니다. (응답 데이터 형식 오류)" ) ;
7477 }
7578 } catch ( e : any ) {
7679 console . error ( "[fetchData] 채팅방 목록을 가져오는 중 오류 발생: " , e ) ;
77- // 네트워크 에러 등의 경우 e.message가 있을 수 있음
7880 setError ( e . message || "알 수 없는 오류가 발생했습니다. 네트워크 연결을 확인해주세요." ) ;
7981 setItems ( [ ] ) ;
8082 } finally {
@@ -84,7 +86,7 @@ function ChatRoomList() {
8486
8587 useEffect ( ( ) => {
8688 fetchData ( ) ;
87- } , [ retryCount ] ) ; // retryCount 변경 시 fetchData 재호출
89+ } , [ retryCount ] ) ;
8890
8991 const handleRetry = ( ) => {
9092 setRetryCount ( ( prev ) => prev + 1 ) ;
@@ -103,16 +105,16 @@ function ChatRoomList() {
103105
104106 return (
105107 < div className = "flex h-[calc(100vh-4rem)] bg-[#f0f2f5] overflow-hidden p-4" >
106- < div className = { `transition-all duration-300 ease-in-out ${ selectedRoom ? "w-1/3 md:w-1/4 lg:w-1/5 " : "w-full" } ` } >
108+ < div className = { `transition-all duration-300 ease-in-out ${ selectedRoom ? "w-[280px] min-w-[280px] " : "w-full" } ` } >
107109 < div className = "h-full flex flex-col max-w-[480px] mx-auto" >
108110 < div className = "flex-grow overflow-hidden rounded-xl bg-white shadow-lg flex flex-col" >
109- < div className = "flex flex-col xl:flex-row xl:items-center justify-between p-4 border-b border-[#e4e6eb]" >
110- < h1 className = "text-xl font-bold text-[#1877f2] mb-2 xl:mb-0 " > 참여중인 채팅방 목록</ h1 >
111+ < div className = "flex flex-col p-4 border-b border-[#e4e6eb]" >
112+ < h1 className = "text-xl font-bold text-[#1877f2] mb-3 whitespace-nowrap truncate " > 참여중인 채팅방 목록</ h1 >
111113 < Button
112114 variant = "outline"
113115 onClick = { handleRetry }
114116 disabled = { loading }
115- className = "flex items-center gap-2 text-[#1877f2] border-[#e4e6eb] hover:bg-[#f0f2f5] w-full xl:w-auto "
117+ className = "flex items-center gap-2 text-[#1877f2] border-[#e4e6eb] hover:bg-[#f0f2f5] w-full"
116118 >
117119 < RefreshIcon className = "h-4 w-4" />
118120 새로고침
@@ -172,8 +174,8 @@ function ChatRoomList() {
172174 </ div >
173175 ) }
174176 </ div >
175- </ div >
176- ) ;
177+ </ div >
178+ )
177179}
178180
179181function ChatRoomSkeleton ( ) {
@@ -185,10 +187,10 @@ function ChatRoomSkeleton() {
185187 </ div >
186188 < Skeleton className = "h-4 w-32 mt-2" />
187189 </ div >
188- ) ;
190+ )
189191}
190192
191- function RefreshIcon ( props : React . SVGProps < SVGSVGElement > ) { // props 타입 추가
193+ function RefreshIcon ( props : React . SVGProps < SVGSVGElement > ) {
192194 return (
193195 < svg
194196 xmlns = "http://www.w3.org/2000/svg"
@@ -205,10 +207,10 @@ function RefreshIcon(props: React.SVGProps<SVGSVGElement>) { // props 타입 추
205207 < path d = "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16" />
206208 < path d = "M3 21v-5h5" />
207209 </ svg >
208- ) ;
210+ )
209211}
210212
211- function AlertCircleIcon ( props : React . SVGProps < SVGSVGElement > ) { // props 타입 추가
213+ function AlertCircleIcon ( props : React . SVGProps < SVGSVGElement > ) {
212214 return (
213215 < svg
214216 xmlns = "http://www.w3.org/2000/svg"
@@ -224,10 +226,10 @@ function AlertCircleIcon(props: React.SVGProps<SVGSVGElement>) { // props 타입
224226 < line x1 = "12" y1 = "8" x2 = "12" y2 = "12" />
225227 < line x1 = "12" y1 = "16" x2 = "12.01" y2 = "16" />
226228 </ svg >
227- ) ;
229+ )
228230}
229231
230- function ChatBubbleIcon ( props : React . SVGProps < SVGSVGElement > ) { // props 타입 추가
232+ function ChatBubbleIcon ( props : React . SVGProps < SVGSVGElement > ) {
231233 return (
232234 < svg
233235 xmlns = "http://www.w3.org/2000/svg"
@@ -242,7 +244,7 @@ function ChatBubbleIcon(props: React.SVGProps<SVGSVGElement>) { // props 타입
242244 < path d = "M14 9a2 2 0 0 1-2 2H6l-4 4V4c0-1.1.9-2 2-2h8a2 2 0 0 1 2 2v5Z" />
243245 < path d = "M18 9h2a2 2 0 0 1 2 2v11l-4-4h-6a2 2 0 0 1-2-2v-1" />
244246 </ svg >
245- ) ;
247+ )
246248}
247249
248- export default ChatRoomList ;
250+ export default ChatRoomList
0 commit comments