diff --git a/src/App.tsx b/src/App.tsx index 6dc7e6d..a701b87 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -98,10 +98,10 @@ function App() { } /> } /> - } /> }> + } /> } /> } /> } /> diff --git a/src/assets/svg/chat-send-arrow.svg b/src/assets/svg/chat-send-arrow.svg new file mode 100644 index 0000000..929e885 --- /dev/null +++ b/src/assets/svg/chat-send-arrow.svg @@ -0,0 +1,6 @@ + + + diff --git a/src/components/layout/Header/components/ChatHeader.tsx b/src/components/layout/Header/components/ChatHeader.tsx index 3c045f4..c68ab35 100644 --- a/src/components/layout/Header/components/ChatHeader.tsx +++ b/src/components/layout/Header/components/ChatHeader.tsx @@ -21,24 +21,16 @@ function ChatHeader() { return ( <> -
- +
+
+ - {chatRoom?.roomName ?? ''} + {chatRoom?.roomName ?? ''} +
-
diff --git a/src/components/layout/Header/headerConfig.ts b/src/components/layout/Header/headerConfig.ts index a0b8983..82a1f18 100644 --- a/src/components/layout/Header/headerConfig.ts +++ b/src/components/layout/Header/headerConfig.ts @@ -5,6 +5,10 @@ export const HEADER_CONFIGS: HeaderConfig[] = [ type: 'none', match: (pathname) => pathname === '/', }, + { + type: 'default', + match: (pathname) => /^\/clubs\/\d+$/.test(pathname), + }, { type: 'profile', match: (pathname) => pathname === '/mypage', diff --git a/src/components/layout/Header/routeTitles.ts b/src/components/layout/Header/routeTitles.ts index 2fc300b..aacc14c 100644 --- a/src/components/layout/Header/routeTitles.ts +++ b/src/components/layout/Header/routeTitles.ts @@ -48,10 +48,6 @@ export const ROUTE_TITLES: RouteTitle[] = [ match: (pathname) => pathname.startsWith('/clubs/search'), title: '동아리 검색', }, - { - match: (pathname) => pathname === '/chats', - title: '채팅방', - }, { match: (pathname) => pathname === '/council', title: '총동아리연합회', diff --git a/src/pages/Chat/ChatRoom.tsx b/src/pages/Chat/ChatRoom.tsx index f8a7602..6472098 100644 --- a/src/pages/Chat/ChatRoom.tsx +++ b/src/pages/Chat/ChatRoom.tsx @@ -1,9 +1,10 @@ import { useEffect, useRef, useState } from 'react'; -import clsx from 'clsx'; import { useParams } from 'react-router-dom'; -import PaperPlaneIcon from '@/assets/svg/paper-plane.svg'; +import type { ChatMessage } from '@/apis/chat/entity'; +import SendArrowIcon from '@/assets/svg/chat-send-arrow.svg'; import LinkifiedText from '@/components/common/LinkifiedText'; import useKeyboardHeight from '@/utils/hooks/useViewportHeight'; +import { cn } from '@/utils/ts/cn'; import useChat from './hooks/useChat'; import useChatRoomScroll from './hooks/useChatRoomScroll'; @@ -23,6 +24,58 @@ const formatTime = (dateString: string) => { return `${hour}:${minute}`; }; +interface ChatMessageRowProps { + isGroup: boolean; + isSameSender: boolean; + message: ChatMessage; +} + +function ChatMessageRow({ isGroup, isSameSender, message }: ChatMessageRowProps) { + const showSenderName = isGroup && !message.isMine && !isSameSender; + const formattedTime = formatTime(message.createdAt); + const formattedUnreadCount = message.unreadCount > 0 ? String(message.unreadCount) : null; + + if (message.isMine) { + return ( +
+
+ {formattedUnreadCount && ( + {formattedUnreadCount} + )} + {formattedTime} + +
+ +
+
+
+ ); + } + + return ( +
+
+ {showSenderName &&
{message.senderName}
} + +
+
+ +
+ {formattedTime} +
+
+
+ ); +} + function ChatRoom() { const { chatRoomId } = useParams(); const { sendMessage, chatMessages, fetchNextPage, hasNextPage, isFetchingNextPage, chatRoomList, isSendingMessage } = @@ -47,6 +100,16 @@ function ChatRoom() { const isGroup = currentRoom?.chatType === 'GROUP'; const sortedMessages = [...chatMessages].reverse(); + const isSubmitDisabled = isSendingMessage || !value.trim(); + + const resetTextareaHeight = () => { + if (!textareaRef.current) return; + + textareaRef.current.style.height = 'auto'; + const baseHeight = baseTextareaHeightRef.current || textareaRef.current.scrollHeight; + baseTextareaHeightRef.current = baseHeight; + textareaRef.current.style.height = `${baseHeight}px`; + }; const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); @@ -61,8 +124,6 @@ function ChatRoom() { setValue(''); if (textareaRef.current) { - const baseHeight = baseTextareaHeightRef.current || textareaRef.current.scrollHeight; - textareaRef.current.style.height = `${baseHeight}px`; textareaRef.current.focus(); } scrollToBottom(); @@ -81,18 +142,20 @@ function ChatRoom() { }; useEffect(() => { - if (!textareaRef.current) return; - - textareaRef.current.style.height = 'auto'; - baseTextareaHeightRef.current = textareaRef.current.scrollHeight; - textareaRef.current.style.height = `${baseTextareaHeightRef.current}px`; + resetTextareaHeight(); }, []); + useEffect(() => { + if (!value) { + resetTextareaHeight(); + } + }, [value]); + return ( -
+
@@ -106,91 +169,42 @@ function ChatRoom() { const isSameSender = prevMessage?.senderId === message.senderId && !showDateHeader; return ( -
+
{showDateHeader && ( -
- +
+ {formatDate(message.createdAt)}
)} -
- {!message.isMine && ( -
- {isGroup && !isSameSender && ( -
{message.senderName}
- )} - -
- {isGroup && ( -
- {!isSameSender ? ( -
- {message.senderName?.[0]} -
- ) : ( -
- )} -
- )} - -
- -
- -
- {message.unreadCount > 0 && ( - {message.unreadCount} - )} - {formatTime(message.createdAt)} -
-
-
- )} - - {/* ===== RIGHT (내 메시지) ===== */} - {message.isMine && ( -
-
- -
- -
- {message.unreadCount > 0 && ( - {message.unreadCount} - )} - {formatTime(message.createdAt)} -
-
- )} -
+
); })}
-
-