Skip to content

Commit

Permalink
[Feat] QFEED-130 채팅 기능 각종 오류 개선과 기능 추가 (#77)
Browse files Browse the repository at this point in the history
* feat: qfeed-130 본인 메세지 확인 후 입력 처리

* feat: qfeed-130 메세지 전송 후 저장, 읽음 처리 완료

* fix: qfeed-130 스크롤 밑에 고정된 채로 채팅내역 띄우기

* fix: qfeed-130 채팅 기능 테스트 전 완성
  • Loading branch information
ahnjongin authored Dec 19, 2024
1 parent b9f4544 commit 32a3965
Show file tree
Hide file tree
Showing 7 changed files with 194 additions and 92 deletions.
56 changes: 48 additions & 8 deletions src/pages/ChatList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@ import {
userNameStyle,
} from '@/pages/ChatList/styles';

const formatDate = (dateString: string): string => {
const date = new Date(dateString);
return date.toLocaleString('ko-KR', {
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
});
};
// 채팅 리스트 아이템 컴포넌트
const ChatItem = ({
chatRoomId,
Expand All @@ -29,20 +38,26 @@ const ChatItem = ({
}: ChatData) => {
const navigate = useNavigate();

// 채팅방 클릭 시 해당 채팅방으로 이동
const handleClick = () => {
navigate(`/chatroom/${chatRoomId}`); // 클릭 시 채팅방으로 이동
};

return (
<div css={chatItemStyle} onClick={handleClick}>
{/* 프로필 이미지 */}
<ProfileImageCon src={otherUserProfile || ''} size={60} />
<div css={chatContentStyle}>
<div css={userNameStyle}>
{/* 유저 닉네임 */}
<span>{otherUserNickname}</span>
<span css={timeStyle}>{lastMessageCreatedAt}</span>
{/* 마지막 메시지 시간 */}
<span css={timeStyle}>{formatDate(lastMessageCreatedAt)}</span>
</div>
<div css={lastMessageStyle}>
{/* 마지막 메시지 내용 */}
<span>{lastMessageContent}</span>
{/* 읽지 않은 메시지 수 */}
{unreadMessageCount && unreadMessageCount > 0 ? (
<span css={unreadCountStyle}>{unreadMessageCount}</span>
) : null}
Expand All @@ -55,37 +70,62 @@ const ChatItem = ({
// 채팅 리스트 메인 컴포넌트
const ChatList = () => {
const [searchTerm, setSearchTerm] = useState(''); // 검색어 상태
const { data: chatData, isLoading } = useQuery({
queryKey: ['chatList'],
queryFn: fetchChatList,
refetchOnWindowFocus: false,
staleTime: 5 * 60 * 1000,
const {
data: chatData,
isLoading,
refetch,
} = useQuery({
queryKey: ['chatList'], // React Query 키
queryFn: fetchChatList, // 데이터를 가져오는 함수
refetchOnWindowFocus: true, // 창 포커스 시 자동 리페치
staleTime: 5 * 60 * 1000, // 캐시 데이터 유효 시간
});

const navigate = useNavigate();

// 채팅방 클릭 핸들러
const handleChatRoomClick = (chatRoomId: string, otherUserNickname: string) => {
console.log('ChatRoomId:', chatRoomId); // 확인
console.log('OtherUserNickname:', otherUserNickname); // 확인

navigate(`/chatroom/${chatRoomId}`, {
state: { otherUserNickname, refetchChatList: refetch }, // 닉네임 전달
});
};

// 검색어를 기준으로 채팅 리스트 필터링
const filteredChatData = Array.isArray(chatData)
? chatData.filter((chat) =>
chat.otherUserNickname.toLowerCase().includes(searchTerm.toLowerCase())
)
: [];

// 검색어 입력 핸들러
const handleSearchChange = (value: string) => {
setSearchTerm(value); // 검색어 상태 업데이트
};

// 데이터 로딩 중 처리
if (isLoading) {
return <div>Loading...</div>;
}

return (
<div css={chatListContainerStyle}>
{/* 검색 인풋 */}
{/* 상단 헤더 */}
<Header />
{/* 검색 인풋 */}
<InputBar placeholder="검색어를 입력하세요" onSearch={handleSearchChange} />
{/* 채팅 리스트 */}
<div css={chatListStyle}>
{filteredChatData.map((chat) => (
<ChatItem key={chat.chatRoomId} {...chat} />
<div
key={chat.chatRoomId}
onClick={() => handleChatRoomClick(chat.chatRoomId, chat.otherUserNickname)} // 채팅방 클릭 이벤트 추가
>
<ChatItem {...chat}
/>
</div>
))}
</div>
</div>
Expand Down
13 changes: 13 additions & 0 deletions src/pages/ChatRoom/api/fetchChatRoom.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,16 @@ export const fetchMessages = async (chatRoomId: string): Promise<MessageType[]>
return [];
}
};

export const markAsRead = async (chatRoomId: string): Promise<void> => {
try {
const response = await apiClient.put(`/chats/${chatRoomId}/markasread`);
if (response.status === 200) {
console.log('읽음 처리 완료');
} else {
console.error('읽음 처리 실패', response);
}
} catch (error) {
console.error('읽음 처리 중 오류 발생:', error);
}
};
19 changes: 4 additions & 15 deletions src/pages/ChatRoom/api/socket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,22 @@ const SOCKET_URL = 'wss://q-feed.n-e.kr/ws';

// STOMP 클라이언트 생성
export const stompClient = new Client({
brokerURL: SOCKET_URL, // WebSocket URL
reconnectDelay: 5000, // 재연결 대기 시간 (ms)
brokerURL: SOCKET_URL,
reconnectDelay: 5000,
debug: (str) => {
console.log('STOMP Debug:', str);
},
connectHeaders: {
Authorization: 'Token', // 토큰 인증 (필요한 경우)
Authorization: 'Bearer token',
},
});

// STOMP 연결 함수
export const connectStomp = () => {
stompClient.onConnect = (frame) => {
console.log('STOMP 연결 성공:', frame);
};

stompClient.onStompError = (frame) => {
console.error('STOMP 에러:', frame.headers['message']);
};

stompClient.activate(); // STOMP 활성화
stompClient.activate();
};

// STOMP 연결 해제 함수
export const disconnectStomp = () => {
if (stompClient.active) {
stompClient.deactivate();
console.log('STOMP 연결 해제');
}
};
13 changes: 7 additions & 6 deletions src/pages/ChatRoom/component/InputBar.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
/** @jsxImportSource @emotion/react */
import {
iconButtonStyle,
iconStyle,
/* iconButtonStyle, */
/* iconStyle, */
inputContainerStyle,
inputStyle,
inputWrap,
sendButtonStyle,
} from '@/pages/ChatRoom/component/InputBar.styles';
import { useState } from 'react';
import { MdOutlineAddAPhoto } from 'react-icons/md';

/* import { MdOutlineAddAPhoto } from 'react-icons/md'; */
import { SendButton } from '@/components/ui/SendButton/SendButton';

interface InputBarProps {
Expand Down Expand Up @@ -54,9 +55,9 @@ const ChatInputBar: React.FC<InputBarProps> = ({
<div css={inputWrap}>
<div css={inputContainerStyle}>
{/* 카메라 아이콘 */}
<button css={iconButtonStyle}>
<MdOutlineAddAPhoto css={iconStyle} />
</button>
{/* <button css={iconButtonStyle}> */}
{/* <MdOutlineAddAPhoto css={iconStyle} /> */}
{/* </button> */}
{/* 텍스트 입력 */}
<input
type="text"
Expand Down
Loading

0 comments on commit 32a3965

Please sign in to comment.