-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
[Design] 1:1 채팅방 페이지, Chatting Input, Message 컴포넌트
- Loading branch information
Showing
8 changed files
with
272 additions
and
76 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,78 +1,141 @@ | ||
'use client' | ||
|
||
import ChattingInput from '@/components/chatting/ChattingInput' | ||
import ChattingProfile from '@/components/chatting/ChattingProfile' | ||
import Profile from '@/components/common/Profile' | ||
import { ChattingProfileI } from '@/model/Chatting' | ||
import { User } from '@/model/User' | ||
import React, { useEffect, useRef, useState } from 'react' | ||
|
||
const Chatting = () => { | ||
// const chatRoomId = 1 | ||
// const member = 1 | ||
// const [messages, setMessages] = useState<string[]>([]) | ||
// const [input, setInput] = useState<string>('') | ||
// const [isConnected, setIsConnected] = useState<boolean>(false) | ||
// const socketRef = useRef<WebSocket | null>(null) | ||
// useEffect(() => { | ||
// const socket = new WebSocket( | ||
// `wss://lc3cc1cnma.execute-api.ap-northeast-2.amazonaws.com/mssaem?chatRoomId=${chatRoomId}&member=${member}`, | ||
// ) | ||
// socket.onopen = () => { | ||
// console.log('WebSocket Opened') | ||
// setIsConnected(true) | ||
// } | ||
// socket.onmessage = (event: MessageEvent<string>) => { | ||
// console.log('WebSocket Message:', event.data) | ||
// setMessages((prev) => [...prev, event.data]) | ||
// } | ||
// socket.onerror = (error: Event) => { | ||
// console.error('WebSocket Error:', error) | ||
// } | ||
// socket.onclose = () => { | ||
// console.log('WebSocket is closed') | ||
// setIsConnected(false) | ||
// } | ||
// socketRef.current = socket | ||
// return () => { | ||
// socket.close() | ||
// } | ||
// }, [chatRoomId, member]) | ||
// const sendMessage = () => { | ||
// if (socketRef.current && input.trim() !== '') { | ||
// const message = { | ||
// action: 'sendMessage', | ||
// chatRoomId: 1, | ||
// message: input, | ||
// } | ||
// socketRef.current.send(JSON.stringify(message)) | ||
// setInput('') | ||
// } | ||
// } | ||
// const disconnect = () => { | ||
// if (socketRef.current) { | ||
// socketRef.current.close() | ||
// socketRef.current = null | ||
// setIsConnected(false) | ||
// } | ||
// } | ||
// return ( | ||
// <div> | ||
// <h1>Chatting</h1> | ||
// <div> | ||
// {messages.map((msg, index) => ( | ||
// <div key={index}>{msg}</div> | ||
// ))} | ||
// </div> | ||
// <input | ||
// type="text" | ||
// value={input} | ||
// onChange={(e) => setInput(e.target.value)} | ||
// onKeyPress={(e) => { | ||
// if (e.key === 'Enter') { | ||
// sendMessage() | ||
// } | ||
// }} | ||
// /> | ||
// {/* <button onClick={sendMessage}>Send</button> | ||
// {isConnected && <button onClick={disconnect}>Disconnect</button>} */} | ||
// </div> | ||
// ) | ||
const [chatRooms] = useState<number[]>([1, 2, 3]) | ||
const [currentChatRoomId, setCurrentChatRoomId] = useState<number>(1) | ||
const [messages, setMessages] = useState<{ [key: number]: string[] }>({}) | ||
const [input, setInput] = useState<string>('') | ||
const [isConnected, setIsConnected] = useState<boolean>(true) | ||
const socketRef = useRef<WebSocket | null>(null) | ||
|
||
const chattProfile: ChattingProfileI = { | ||
nickName: '박빵이', | ||
mbti: 'ENFP', | ||
badge: 'ENFP', | ||
profileImgUrl: '/images/common/default.svg', | ||
recent: '5', | ||
lastMessage: '안녕하세요', | ||
} | ||
|
||
const user: User = { | ||
profileImgUrl: '/images/common/default.svg', | ||
nickName: '유보라', | ||
mbti: 'ENFP', | ||
badge: '엠비티어른', | ||
} | ||
|
||
useEffect(() => { | ||
const socket = new WebSocket( | ||
`wss://lc3cc1cnma.execute-api.ap-northeast-2.amazonaws.com/mssaem?chatRoomId=${currentChatRoomId}&member=1`, | ||
) | ||
socketRef.current = socket | ||
socket.onopen = () => { | ||
setIsConnected(true) | ||
} | ||
socket.onmessage = (event) => { | ||
const receivedMessage = JSON.parse(event.data) | ||
setMessages((prevMessages) => ({ | ||
...prevMessages, | ||
[currentChatRoomId]: [ | ||
...(prevMessages[currentChatRoomId] || []), | ||
receivedMessage.message, | ||
], | ||
})) | ||
} | ||
return () => { | ||
socket.close() | ||
} | ||
}, [currentChatRoomId]) | ||
|
||
const sendMessage = () => { | ||
if (socketRef.current && input.trim() !== '') { | ||
const message = { | ||
action: 'sendMessage', | ||
chatRoomId: currentChatRoomId, | ||
message: input, | ||
} | ||
socketRef.current.send(JSON.stringify(message)) | ||
setMessages((prevMessages) => ({ | ||
...prevMessages, | ||
[currentChatRoomId]: [ | ||
...(prevMessages[currentChatRoomId] || []), | ||
input, | ||
], | ||
})) | ||
setInput('') | ||
} | ||
} | ||
|
||
const disconnect = () => { | ||
if (socketRef.current) { | ||
socketRef.current.close() | ||
socketRef.current = null | ||
setIsConnected(false) | ||
} | ||
} | ||
|
||
const selectChatRoom = (chatRoomId: number) => { | ||
if (isConnected) { | ||
disconnect() | ||
} | ||
setCurrentChatRoomId(chatRoomId) | ||
} | ||
|
||
return ( | ||
<div className="w-full-vw ml-half-vw bg-main3 py-10"> | ||
<div className="flex h-screen-40 border-7.5 mx-2% sm:mx-6% md:mx-13% bg-white rounded-7.5 shadow-custom-light "> | ||
{/* Left Sidebar for 채팅 목록 */} | ||
<div className="border-r flex flex-col overflow-y-scroll scrollbar-hide"> | ||
<div className="flex items-center p-10 border-b text-title3 font-bold h-27.5"> | ||
채팅 목록 | ||
</div> | ||
<ul className=""> | ||
{chatRooms.map((roomId) => ( | ||
<li | ||
key={roomId} | ||
className="border-b last:border-none box-border p-4" | ||
> | ||
<ChattingProfile | ||
chattingProfile={chattProfile} | ||
onClick={() => selectChatRoom(roomId)} | ||
/> | ||
</li> | ||
))} | ||
</ul> | ||
</div> | ||
|
||
{/* Right Content for 채팅 내역 */} | ||
<div className="flex flex-col flex-1 bg-white rounded-7.5"> | ||
<div className="flex items-center border-b p-4 h-27.5"> | ||
<Profile user={user} /> | ||
</div> | ||
|
||
<div className="flex-1 overflow-y-auto box-border"> | ||
{messages[currentChatRoomId]?.map((msg, index) => ( | ||
<div key={index} className="my-2 p-2 box-border"> | ||
{msg} | ||
</div> | ||
)) || <p className="p-4">No messages yet.</p>} | ||
</div> | ||
|
||
return <div>test</div> | ||
<div className="flex items-center p-6"> | ||
<ChattingInput | ||
value={input} | ||
onChange={(e) => setInput(e.target.value)} | ||
onClick={sendMessage} | ||
/> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
) | ||
} | ||
|
||
export default Chatting |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { Meta, StoryFn } from '@storybook/react' | ||
import ChattingInput, { | ||
ChattingInputProps, | ||
} from '@/components/chatting/ChattingInput' | ||
|
||
export default { | ||
title: 'Chatting/ChattingInput', | ||
component: ChattingInput, | ||
} as Meta<ChattingInputProps> | ||
|
||
const Template: StoryFn<ChattingInputProps> = (args: ChattingInputProps) => ( | ||
<ChattingInput {...args} /> | ||
) | ||
|
||
export const Primary = Template.bind({}) | ||
Primary.args = {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
'use client' | ||
|
||
import Button from '../common/Button' | ||
|
||
export interface ChattingInputProps { | ||
value: string | ||
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void | ||
onClick: () => void | ||
} | ||
|
||
const ChattingInput = ({ value, onChange, onClick }: ChattingInputProps) => { | ||
const handleKeyPress = (e: React.KeyboardEvent<HTMLInputElement>) => { | ||
if (e.key === 'Enter') { | ||
onClick() | ||
} | ||
} | ||
|
||
return ( | ||
<div className="flex w-full gap-3.75"> | ||
<input | ||
type="text" | ||
className="w-full text-gray2 text-headline font-semibold px-4 py-2 border border-main rounded-7.5 focus:outline-none focus:border-main" | ||
value={value} | ||
onChange={onChange} | ||
onKeyPress={handleKeyPress} | ||
/> | ||
<Button text="등록" color="PURPLE" size="small" onClick={onClick} /> | ||
</div> | ||
) | ||
} | ||
|
||
export default ChattingInput |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import { Meta, StoryFn } from '@storybook/react' | ||
import ChattingMessage, { | ||
ChattingMessageProps, | ||
} from '@/components/chatting/ChattingMessage' | ||
|
||
export default { | ||
title: 'Chatting/ChattingMessage', | ||
component: ChattingMessage, | ||
} as Meta<ChattingMessageProps> | ||
|
||
const Template: StoryFn<ChattingMessageProps> = ( | ||
args: ChattingMessageProps, | ||
) => <ChattingMessage {...args} /> | ||
|
||
export const SentMessage = Template.bind({}) | ||
SentMessage.args = { | ||
message: { | ||
content: '안녕하세요 도와주세요 어쩌고 저쩌고 머시라 머시라', | ||
sendAt: '오후 11:32', | ||
}, | ||
isReceived: false, | ||
} | ||
|
||
export const ReceivedMessage = Template.bind({}) | ||
ReceivedMessage.args = { | ||
message: { | ||
content: '안녕하세요 도와주세요 어쩌고 저쩌고 머시라 머시라', | ||
sendAt: '오후 11:32', | ||
}, | ||
isReceived: true, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { ChattingMessageI } from '@/model/Chatting' | ||
import Image from 'next/image' | ||
|
||
export interface ChattingMessageProps { | ||
message: ChattingMessageI | ||
isReceived: boolean | ||
} | ||
|
||
const ChattingMessage = ({ message, isReceived }: ChattingMessageProps) => { | ||
const { content, sendAt } = message | ||
|
||
return ( | ||
<div | ||
className={`flex items-end mb-4 ${isReceived ? 'justify-start' : 'justify-end'}`} | ||
> | ||
<div | ||
className={`flex items-center gap-2.5 ${isReceived ? 'flex-row-reverse' : 'flex-row'}`} | ||
> | ||
<div className="text-caption text-gray2 whitespace-nowrap"> | ||
{sendAt} | ||
</div> | ||
<div | ||
className={`text-headine text-gray2 font-semibold rounded-7.5 px-5 py-4 max-w-90 ${isReceived ? 'bg-main4' : 'bg-white border border-main'}`} | ||
> | ||
{content} | ||
</div> | ||
{isReceived && ( | ||
<Image | ||
src="/images/common/default.svg" | ||
width={56} | ||
height={56} | ||
alt="profile" | ||
/> | ||
)} | ||
</div> | ||
</div> | ||
) | ||
} | ||
|
||
export default ChattingMessage |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,17 @@ | ||
import { MBTI } from '@/components/common/Button' | ||
import { MBTI, Color } from '@/components/common/Button' | ||
|
||
interface ChattingProfileI { | ||
nickName: string | ||
mbti: MBTI | ||
badge?: string | ||
badge?: Color | ||
profileImgUrl: string | ||
recent?: string | ||
lastMessage: string | ||
} | ||
|
||
export default ChattingProfileI | ||
interface ChattingMessageI { | ||
content: string | ||
sendAt: string | ||
} | ||
|
||
export type { ChattingProfileI, ChattingMessageI } |
Oops, something went wrong.