Skip to content

Commit

Permalink
feat: 채팅 리스트 불러오는 로직 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
nim-od committed Aug 20, 2024
1 parent eb699bd commit 85e6d56
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 49 deletions.
6 changes: 5 additions & 1 deletion packages/common/src/components/chat/Message.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ export default function Message({
<p className={cn(textColor, 'text-body-3 truncate font-medium')}>익명 {sender} </p>
{isMyMessage && <p className={cn(textColor, 'text-body-3 font-medium')}>(나)</p>}
</div>
<p className={`flex flex-row justify-between flex-1 text-body-3 truncate ${isMyMessage && 'font-medium'}`}>{children}</p>
<p
className={`text-body-3 flex flex-1 flex-row justify-between truncate ${isMyMessage && 'font-medium'}`}
>
{children}
</p>
</div>
);
}
2 changes: 2 additions & 0 deletions packages/common/src/constants/socket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ export const CHAT_SOCKET_ENDPOINTS = {
PUBLISH: '/app/chat.sendMessage',
BLOCK: '/topic/block',
NOTICE: '/app/chat.sendNotice',
SUBSCRIBE_CHAT_LIST: '/user/queue/chatHistory',
PUBLISH_CHAT_LIST: '/app/chat.getHistory',
} as const;

export const RACING_SOCKET_ENDPOINTS = {
Expand Down
8 changes: 2 additions & 6 deletions packages/common/src/utils/socket.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Client, IFrame, IMessage, StompSubscription } from '@stomp/stompjs';
import SockJS from 'sockjs-client';

export type SocketSubscribeCallbackType = (data: unknown, messageId: string) => void;
export type SocketSubscribeCallbackType = (data: unknown) => void;

export interface SubscriptionProps {
destination: string;
Expand Down Expand Up @@ -88,11 +88,7 @@ export default class Socket {
const subscriptionProps = {
destination,
headers,
callback: (message: IMessage) => {
const messageId = message.headers['message-id'];
const data = JSON.parse(message.body);
callback(data, messageId);
},
callback: (message: IMessage) => callback(JSON.parse(message.body)),
};

const subscription = this.client.subscribe(
Expand Down
2 changes: 1 addition & 1 deletion packages/user/src/components/event/chatting/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { ChatList } from '@softeer/common/components';
import ChatInput from 'src/components/event/chatting/inputArea/input/index.tsx';
import { UseSocketReturnType } from 'src/hooks/socket/index.ts';
import Chat from './Chat.tsx';
import ChatInputArea from './inputArea/index.tsx';
import ChatInput from './inputArea/input/index.tsx';

/** 실시간 기대평 섹션 */

Expand Down
35 changes: 19 additions & 16 deletions packages/user/src/components/event/racing/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,26 @@ import RacingRankingDisplay from './controls/index.tsx';
import RacingDashboard from './dashboard/index.tsx';

/** 실시간 레이싱 섹션 */
const RealTimeRacing = memo(({ racingSocket }: Pick<UseSocketReturnType, 'racingSocket'>) => {
const { ranks, votes, onCarFullyCharged } = racingSocket;
const { isCharged, handleCharge } = useChargeHandler(onCarFullyCharged);
const RealTimeRacing = memo(
({
racingSocket: { ranks, votes, onCarFullyCharged },
}: Pick<UseSocketReturnType, 'racingSocket'>) => {
const { isCharged, handleCharge } = useChargeHandler(onCarFullyCharged);

return (
<section
id={SECTION_ID.RACING}
className="container flex w-[1200px] snap-start flex-col items-center gap-4 pb-[50px] pt-[80px]"
>
<div className="relative h-[685px] w-full">
<RacingDashboard ranks={ranks} isActive={isCharged} />
<ChargeButton onCharge={handleCharge} />
</div>
<RacingRankingDisplay votes={votes} ranks={ranks} isActive={isCharged} />
</section>
);
});
return (
<section
id={SECTION_ID.RACING}
className="container flex w-[1200px] snap-start flex-col items-center gap-4 pb-[50px] pt-[80px]"
>
<div className="relative h-[685px] w-full">
<RacingDashboard ranks={ranks} isActive={isCharged} />
<ChargeButton onCharge={handleCharge} />
</div>
<RacingRankingDisplay votes={votes} ranks={ranks} isActive={isCharged} />
</section>
);
},
);

export default RealTimeRacing;

Expand Down
27 changes: 17 additions & 10 deletions packages/user/src/hooks/socket/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,33 @@ import socketManager from 'src/services/socket.ts';
import useChatSocket from './useChatSocket.ts';
import useRacingSocket from './useRacingSocket.ts';

export type UseSocketReturnType = ReturnType<typeof useSocket>;

export default function useSocket() {
const { token } = useAuth();
const chatSocket = useChatSocket();
const racingSocket = useRacingSocket();

const { onReceiveMessage, onReceiveBlock, ...chatSocketProps } = chatSocket;
const { onReceiveMessage, onReceiveChatList, onReceiveBlock, ...chatSocketProps } = chatSocket;
const { onReceiveStatus, ...racingSocketProps } = racingSocket;

const isSocketInitialized = useRef(false);

useLayoutEffect(() => {
if (!isSocketInitialized.current) {
socketManager.connectSocketClient({
token,
onReceiveMessage,
onReceiveStatus,
onReceiveBlock,
});
isSocketInitialized.current = true;
}
const connetSocket = async () => {
if (!isSocketInitialized.current) {
await socketManager.connectSocketClient({
token,
onReceiveChatList,
onReceiveMessage,
onReceiveStatus,
onReceiveBlock,
});
isSocketInitialized.current = true;
}
};

connetSocket();
}, [token, onReceiveMessage, onReceiveStatus, onReceiveBlock]);

return { chatSocket: chatSocketProps, racingSocket: racingSocketProps };
Expand Down
66 changes: 51 additions & 15 deletions packages/user/src/hooks/socket/useChatSocket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,50 +14,86 @@ export default function useChatSocket() {
const [storedChatList, storeChatList] = useChatListStorage();
const [chatList, setChatList] = useState<ChatProps[]>(storedChatList);

const [isChatListSubscribed, setIsChatListSubscribed] = useState(false);

useEffect(() => storeChatList(chatList), [chatList]);

const handleIncomingMessage: SocketSubscribeCallbackType = useCallback(
(data: unknown, messageId: string) => {
const parsedData = data as Omit<ChatProps, 'id'>;
const parsedMessage = { id: messageId, ...parsedData };
setChatList((prevMessages) => [...prevMessages, parsedMessage] as ChatProps[]);
(data: unknown) => {
setChatList((prevMessages) => [...prevMessages, data] as ChatProps[]);
},
[],
[setChatList],
);

const handleIncomingBlock: SocketSubscribeCallbackType = useCallback(
(data: unknown) => {
const { id, blockId } = data as { id: string; blockId: string };

setChatList((prevMessages) =>
prevMessages.map((message) => (message.id === blockId ? { id, type: 'b' } : message)),
);
},
[setChatList],
);

const handleSendMessage = useCallback((content: string) => {
try {
const socketClient = socketManager.getSocketClient();
const socketClient = socketManager.getSocketClient();

const handleSendMessage = useCallback(
(content: string) => {
try {
const chatMessage = { content };

socketClient.sendMessages({
destination: CHAT_SOCKET_ENDPOINTS.SUBSCRIBE,
body: chatMessage,
});
} catch (error) {
const errorMessage = (error as Error).message;
toast({
description:
errorMessage.length > 0 ? errorMessage : '기대평 전송 중 문제가 발생했습니다.',
});
}
},
[socketClient],
);

const chatMessage = { content };
const handleIncomingChatHistory: SocketSubscribeCallbackType = useCallback(
(data: unknown) => {
setChatList(data as ChatProps[]);
},
[setChatList],
);

socketClient.sendMessages({
destination: CHAT_SOCKET_ENDPOINTS.PUBLISH,
body: chatMessage,
const handleRequestForSendingChatHistory = useCallback(async () => {
try {
await socketClient.sendMessages({
destination: CHAT_SOCKET_ENDPOINTS.PUBLISH_CHAT_LIST,
body: {},
});
setIsChatListSubscribed(true);
} catch (error) {
const errorMessage = (error as Error).message;
toast({
description:
errorMessage.length > 0 ? errorMessage : '기대평을 보내는 중 문제가 발생했습니다.',
errorMessage.length > 0 ? errorMessage : '기대평 내역을 불러오는 중 문제가 발생했습니다.',
});
}
}, []);
}, [setIsChatListSubscribed, socketClient]);

const handleReceiveChatList: SocketSubscribeCallbackType = useCallback(
(data: unknown) => {
if (!isChatListSubscribed) {
handleRequestForSendingChatHistory();
}
handleIncomingChatHistory(data);
},
[isChatListSubscribed],
);

return {
onReceiveMessage: handleIncomingMessage,
onReceiveBlock: handleIncomingBlock,
onReceiveChatList: handleReceiveChatList,
onSendMessage: handleSendMessage,
messages: chatList,
};
Expand Down
13 changes: 13 additions & 0 deletions packages/user/src/services/socket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ class SocketManager {

private onReceiveBlock: SocketSubscribeCallbackType | null = null;

private onReceiveChatList: SocketSubscribeCallbackType | null = null;

private onReceiveStatus: SocketSubscribeCallbackType | null = null;

constructor(token: string | null) {
Expand All @@ -33,18 +35,21 @@ class SocketManager {
onReceiveMessage,
onReceiveBlock,
onReceiveStatus,
onReceiveChatList,
}: {
token: string | null | undefined;
onReceiveMessage: SocketSubscribeCallbackType;
onReceiveBlock: SocketSubscribeCallbackType;
onReceiveStatus: SocketSubscribeCallbackType;
onReceiveChatList: SocketSubscribeCallbackType;
}) {
if (this.socketClient) {
await this.socketClient.disconnect();
}

this.initializeSocketClient(token);

this.onReceiveChatList = onReceiveChatList;
this.onReceiveMessage = onReceiveMessage;
this.onReceiveBlock = onReceiveBlock;
this.onReceiveStatus = onReceiveStatus;
Expand All @@ -63,11 +68,19 @@ class SocketManager {
onReceiveBlock: this.onReceiveBlock!,
onReceiveMessage: this.onReceiveMessage!,
onReceiveStatus: this.onReceiveStatus!,
onReceiveChatList: this.onReceiveChatList!,
});
}

subscribeToTopics() {
if (this.socketClient && this.socketClient.client.connected) {
if (this.onReceiveChatList) {
this.socketClient.subscribe({
destination: CHAT_SOCKET_ENDPOINTS.SUBSCRIBE_CHAT_LIST,
callback: this.onReceiveChatList,
});
}

if (this.onReceiveMessage) {
this.socketClient.subscribe({
destination: CHAT_SOCKET_ENDPOINTS.SUBSCRIBE,
Expand Down

0 comments on commit 85e6d56

Please sign in to comment.