From 37ea06abbb0974a2db358334b47b190e33c87220 Mon Sep 17 00:00:00 2001 From: ddingjoo Date: Tue, 6 Jan 2026 15:01:55 +0900 Subject: [PATCH 1/6] =?UTF-8?q?[FIX]=20ChatRoomCard=20=EA=B3=A0=EC=A0=95?= =?UTF-8?q?=20=EB=86=92=EC=9D=B4=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - height: 160px로 모든 카드 크기 통일 - 내용 길이에 관계없이 일정한 카드 크기 유지 Closes #31 --- src/domains/freetalk/components/ChatRoomCard.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/domains/freetalk/components/ChatRoomCard.jsx b/src/domains/freetalk/components/ChatRoomCard.jsx index a513a93..5fe17a3 100644 --- a/src/domains/freetalk/components/ChatRoomCard.jsx +++ b/src/domains/freetalk/components/ChatRoomCard.jsx @@ -34,7 +34,7 @@ const ChatRoomCard = ({ room, onClick }) => { onClick={() => onClick?.(room)} sx={{ width: '100%', - height: '100%', + height: 160, display: 'flex', flexDirection: 'column', cursor: 'pointer', From 440205128e3c255029dcd9cfe4ee3d1376bb004e Mon Sep 17 00:00:00 2001 From: ddingjoo Date: Tue, 6 Jan 2026 15:03:25 +0900 Subject: [PATCH 2/6] =?UTF-8?q?[FIX]=20ChatRoomCard=20=EC=B0=B8=EC=97=AC?= =?UTF-8?q?=EC=9E=90=20=ED=94=84=EB=A1=9C=ED=95=84=20=EC=A0=9C=EA=B1=B0=20?= =?UTF-8?q?=EB=B0=8F=20=EB=84=88=EB=B9=84=20=EA=B3=A0=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 참여자 아바타 그룹 제거 - 너비 300px, 높이 140px로 고정 --- .../freetalk/components/ChatRoomCard.jsx | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/src/domains/freetalk/components/ChatRoomCard.jsx b/src/domains/freetalk/components/ChatRoomCard.jsx index 5fe17a3..05bda05 100644 --- a/src/domains/freetalk/components/ChatRoomCard.jsx +++ b/src/domains/freetalk/components/ChatRoomCard.jsx @@ -1,4 +1,4 @@ -import { Card, CardContent, Box, Typography, Chip, Avatar, AvatarGroup } from '@mui/material' +import { Card, CardContent, Box, Typography, Chip } from '@mui/material' import { AccessTime as TimeIcon, People as PeopleIcon } from '@mui/icons-material' const levelColors = { @@ -33,8 +33,8 @@ const ChatRoomCard = ({ room, onClick }) => { onClick?.(room)} sx={{ - width: '100%', - height: 160, + width: 300, + height: 140, display: 'flex', flexDirection: 'column', cursor: 'pointer', @@ -86,16 +86,8 @@ const ChatRoomCard = ({ room, onClick }) => { - {/* 참여자 아바타 & 생성일 */} - - - {room.participants?.map((participant, index) => ( - - {participant.name?.[0]} - - ))} - - + {/* 생성일 */} + 생성: {formatDate(room.createdAt)} From db07f4599dd94cc1536741222c4340d9ae40ea69 Mon Sep 17 00:00:00 2001 From: ddingjoo Date: Tue, 6 Jan 2026 15:04:50 +0900 Subject: [PATCH 3/6] =?UTF-8?q?[FIX]=20ChatRoomCard=20=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=EC=95=84=EC=9B=83=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 높이 100px로 축소 - 생성일을 마지막 대화 옆으로 이동 - 생성일 날짜만 표시 (시간 제거) --- src/domains/freetalk/components/ChatRoomCard.jsx | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/domains/freetalk/components/ChatRoomCard.jsx b/src/domains/freetalk/components/ChatRoomCard.jsx index 05bda05..43b54fa 100644 --- a/src/domains/freetalk/components/ChatRoomCard.jsx +++ b/src/domains/freetalk/components/ChatRoomCard.jsx @@ -21,9 +21,7 @@ const formatDate = (date) => { const d = new Date(date) const month = d.getMonth() + 1 const day = d.getDate() - const hours = d.getHours() - const minutes = d.getMinutes().toString().padStart(2, '0') - return `${month}/${day} ${hours}:${minutes}` + return `${month}/${day}` } const ChatRoomCard = ({ room, onClick }) => { @@ -34,7 +32,7 @@ const ChatRoomCard = ({ room, onClick }) => { onClick={() => onClick?.(room)} sx={{ width: 300, - height: 140, + height: 100, display: 'flex', flexDirection: 'column', cursor: 'pointer', @@ -65,7 +63,7 @@ const ChatRoomCard = ({ room, onClick }) => { {room.name} - + {/* 인원 */} @@ -84,12 +82,10 @@ const ChatRoomCard = ({ room, onClick }) => { {formatTimeAgo(room.lastMessageAt)} - - {/* 생성일 */} - + {/* 생성일 */} - 생성: {formatDate(room.createdAt)} + · {formatDate(room.createdAt)} From f06bfae34eea43edca7b8a2a4c24427dc3334a1f Mon Sep 17 00:00:00 2001 From: ddingjoo Date: Tue, 6 Jan 2026 15:05:12 +0900 Subject: [PATCH 4/6] =?UTF-8?q?[FIX]=20=EC=83=9D=EC=84=B1=EC=9D=BC=20?= =?UTF-8?q?=EB=9D=BC=EB=B2=A8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/domains/freetalk/components/ChatRoomCard.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/domains/freetalk/components/ChatRoomCard.jsx b/src/domains/freetalk/components/ChatRoomCard.jsx index 43b54fa..7b128b5 100644 --- a/src/domains/freetalk/components/ChatRoomCard.jsx +++ b/src/domains/freetalk/components/ChatRoomCard.jsx @@ -85,7 +85,7 @@ const ChatRoomCard = ({ room, onClick }) => { {/* 생성일 */} - · {formatDate(room.createdAt)} + · 생성: {formatDate(room.createdAt)} From 34dc7ddeeb7f94236039b72c5fc4fdd870e9625d Mon Sep 17 00:00:00 2001 From: ddingjoo Date: Tue, 6 Jan 2026 15:10:48 +0900 Subject: [PATCH 5/6] =?UTF-8?q?[FEAT]=20ChatRoomCard=20UI=20=EA=B0=9C?= =?UTF-8?q?=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 입장 버튼 추가 (우측 상단, outlined 스타일) - 비밀방 자물쇠 아이콘 표시 - 간단한 소개 표시 추가 - 생성일자 하단에 표시 - 카드 높이 140px로 조정 - 더미 데이터에 description, createdAt, isPrivate 추가 --- .../freetalk/components/ChatRoomCard.jsx | 107 ++++++++++++------ .../freetalk/pages/FreetalkPeoplePage.jsx | 57 ++++------ 2 files changed, 93 insertions(+), 71 deletions(-) diff --git a/src/domains/freetalk/components/ChatRoomCard.jsx b/src/domains/freetalk/components/ChatRoomCard.jsx index 7b128b5..e66f137 100644 --- a/src/domains/freetalk/components/ChatRoomCard.jsx +++ b/src/domains/freetalk/components/ChatRoomCard.jsx @@ -1,5 +1,5 @@ -import { Card, CardContent, Box, Typography, Chip } from '@mui/material' -import { AccessTime as TimeIcon, People as PeopleIcon } from '@mui/icons-material' +import { Card, CardContent, Box, Typography, Chip, Button } from '@mui/material' +import { AccessTime as TimeIcon, People as PeopleIcon, Lock as LockIcon } from '@mui/icons-material' const levelColors = { beginner: { bg: '#e8f5e9', color: '#2e7d32', label: '초급' }, @@ -27,15 +27,18 @@ const formatDate = (date) => { const ChatRoomCard = ({ room, onClick }) => { const level = levelColors[room.level] || levelColors.beginner + const handleEnterClick = (e) => { + e.stopPropagation() + onClick?.(room) + } + return ( onClick?.(room)} sx={{ width: 300, - height: 100, + height: 140, display: 'flex', flexDirection: 'column', - cursor: 'pointer', transition: 'all 0.2s ease-in-out', '&:hover': { transform: 'translateY(-4px)', @@ -43,9 +46,9 @@ const ChatRoomCard = ({ room, onClick }) => { }, }} > - - - {/* 레벨 뱃지 */} + + {/* 상단: 레벨 뱃지 + 방 이름 + 입장 버튼 */} + { backgroundColor: level.bg, color: level.color, fontWeight: 600, - minWidth: 48, + fontSize: 11, + height: 24, }} /> - {/* 채팅방 정보 */} - - + + {room.isPrivate && ( + + )} + {room.name} + - - {/* 인원 */} - - - - - {room.currentMembers} - - /{room.maxMembers} - - + + - {/* 마지막 대화 */} - - - - {formatTimeAgo(room.lastMessageAt)} - + {/* 중단: 소개 */} + {room.description && ( + + {room.description} + + )} + + {/* 하단: 인원, 마지막 대화, 생성일 */} + + + + + + {room.currentMembers} + /{room.maxMembers} + + - {/* 생성일 */} - - · 생성: {formatDate(room.createdAt)} - - + + + + {formatTimeAgo(room.lastMessageAt)} + + + + · 생성: {formatDate(room.createdAt)} + diff --git a/src/domains/freetalk/pages/FreetalkPeoplePage.jsx b/src/domains/freetalk/pages/FreetalkPeoplePage.jsx index fd90813..99c1e64 100644 --- a/src/domains/freetalk/pages/FreetalkPeoplePage.jsx +++ b/src/domains/freetalk/pages/FreetalkPeoplePage.jsx @@ -24,74 +24,57 @@ const mockRooms = [ { id: 1, name: '영어 일상 대화방', + description: '편하게 일상 영어로 대화해요', level: 'beginner', currentMembers: 3, maxMembers: 6, - lastMessageAt: new Date(Date.now() - 5 * 60 * 1000), // 5분 전 - createdAt: new Date(Date.now() - 2 * 24 * 60 * 60 * 1000), // 2일 전 - participants: [ - { name: '김철수', avatar: '' }, - { name: '이영희', avatar: '' }, - { name: 'John', avatar: '' }, - ], + lastMessageAt: new Date(Date.now() - 5 * 60 * 1000), + createdAt: new Date(Date.now() - 2 * 24 * 60 * 60 * 1000), + isPrivate: false, }, { id: 2, name: '비즈니스 영어 연습', + description: '회의, 이메일, 프레젠테이션 영어', level: 'intermediate', currentMembers: 4, maxMembers: 5, - lastMessageAt: new Date(Date.now() - 30 * 60 * 1000), // 30분 전 - createdAt: new Date(Date.now() - 5 * 24 * 60 * 60 * 1000), // 5일 전 - participants: [ - { name: 'Mike', avatar: '' }, - { name: '박지성', avatar: '' }, - { name: 'Emma', avatar: '' }, - { name: '최민수', avatar: '' }, - ], + lastMessageAt: new Date(Date.now() - 30 * 60 * 1000), + createdAt: new Date(Date.now() - 5 * 24 * 60 * 60 * 1000), + isPrivate: true, }, { id: 3, name: '고급 토론방', + description: '시사 이슈로 깊이 있는 토론', level: 'advanced', currentMembers: 2, maxMembers: 4, - lastMessageAt: new Date(Date.now() - 2 * 60 * 60 * 1000), // 2시간 전 - createdAt: new Date(Date.now() - 1 * 24 * 60 * 60 * 1000), // 1일 전 - participants: [ - { name: 'Sarah', avatar: '' }, - { name: '정유진', avatar: '' }, - ], + lastMessageAt: new Date(Date.now() - 2 * 60 * 60 * 1000), + createdAt: new Date(Date.now() - 1 * 24 * 60 * 60 * 1000), + isPrivate: true, }, { id: 4, name: '영어 초보 환영', + description: '틀려도 괜찮아요! 함께 성장해요', level: 'beginner', currentMembers: 5, maxMembers: 8, - lastMessageAt: new Date(Date.now() - 10 * 60 * 1000), // 10분 전 - createdAt: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000), // 7일 전 - participants: [ - { name: '홍길동', avatar: '' }, - { name: 'Tom', avatar: '' }, - { name: '김미나', avatar: '' }, - { name: 'Lisa', avatar: '' }, - { name: '박준호', avatar: '' }, - ], + lastMessageAt: new Date(Date.now() - 10 * 60 * 1000), + createdAt: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000), + isPrivate: false, }, { id: 5, name: '프리토킹 중급반', + description: '자유 주제로 스피킹 연습', level: 'intermediate', currentMembers: 3, maxMembers: 6, - lastMessageAt: new Date(Date.now() - 45 * 60 * 1000), // 45분 전 - createdAt: new Date(Date.now() - 3 * 24 * 60 * 60 * 1000), // 3일 전 - participants: [ - { name: '이수진', avatar: '' }, - { name: 'David', avatar: '' }, - { name: '김태희', avatar: '' }, - ], + lastMessageAt: new Date(Date.now() - 45 * 60 * 1000), + createdAt: new Date(Date.now() - 3 * 24 * 60 * 60 * 1000), + isPrivate: false, }, ] From c758b49f68a098a0d0b1bb198ec3e948fc4f9f15 Mon Sep 17 00:00:00 2001 From: ddingjoo Date: Tue, 6 Jan 2026 15:13:48 +0900 Subject: [PATCH 6/6] =?UTF-8?q?[FEAT]=20=EC=B1=84=ED=8C=85=EB=B0=A9=20?= =?UTF-8?q?=EC=9E=85=EC=9E=A5=20=EB=AA=A8=EB=8B=AC=20=EB=B0=8F=20=ED=95=84?= =?UTF-8?q?=ED=84=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 입장 버튼 클릭 시 모달 팝업 - 일반방: 방 정보 확인 후 입장 - 비밀방: 비밀번호 입력 후 입장 - 참여중 필터 추가 (레벨 필터 옆) - 생성일 형식 변경 (연/월/일) - 더미 데이터에 isJoined 필드 추가 --- .../freetalk/components/ChatRoomCard.jsx | 7 +- .../freetalk/pages/FreetalkPeoplePage.jsx | 138 +++++++++++++++++- 2 files changed, 137 insertions(+), 8 deletions(-) diff --git a/src/domains/freetalk/components/ChatRoomCard.jsx b/src/domains/freetalk/components/ChatRoomCard.jsx index e66f137..f7e1fc9 100644 --- a/src/domains/freetalk/components/ChatRoomCard.jsx +++ b/src/domains/freetalk/components/ChatRoomCard.jsx @@ -19,9 +19,10 @@ const formatTimeAgo = (date) => { const formatDate = (date) => { const d = new Date(date) - const month = d.getMonth() + 1 - const day = d.getDate() - return `${month}/${day}` + const year = d.getFullYear().toString().slice(2) + const month = (d.getMonth() + 1).toString().padStart(2, '0') + const day = d.getDate().toString().padStart(2, '0') + return `${year}/${month}/${day}` } const ChatRoomCard = ({ room, onClick }) => { diff --git a/src/domains/freetalk/pages/FreetalkPeoplePage.jsx b/src/domains/freetalk/pages/FreetalkPeoplePage.jsx index 99c1e64..53762db 100644 --- a/src/domains/freetalk/pages/FreetalkPeoplePage.jsx +++ b/src/domains/freetalk/pages/FreetalkPeoplePage.jsx @@ -11,14 +11,26 @@ import { ToggleButton, Button, Fab, + Dialog, + DialogTitle, + DialogContent, + DialogActions, + Chip, } from '@mui/material' import { Search as SearchIcon, Add as AddIcon, - FilterList as FilterIcon, + Lock as LockIcon, + People as PeopleIcon, } from '@mui/icons-material' import ChatRoomCard from '../components/ChatRoomCard' +const levelColors = { + beginner: { bg: '#e8f5e9', color: '#2e7d32', label: '초급' }, + intermediate: { bg: '#fff3e0', color: '#ef6c00', label: '중급' }, + advanced: { bg: '#fce4ec', color: '#c2185b', label: '고급' }, +} + // 더미 데이터 const mockRooms = [ { @@ -31,6 +43,7 @@ const mockRooms = [ lastMessageAt: new Date(Date.now() - 5 * 60 * 1000), createdAt: new Date(Date.now() - 2 * 24 * 60 * 60 * 1000), isPrivate: false, + isJoined: true, }, { id: 2, @@ -42,6 +55,7 @@ const mockRooms = [ lastMessageAt: new Date(Date.now() - 30 * 60 * 1000), createdAt: new Date(Date.now() - 5 * 24 * 60 * 60 * 1000), isPrivate: true, + isJoined: false, }, { id: 3, @@ -53,6 +67,7 @@ const mockRooms = [ lastMessageAt: new Date(Date.now() - 2 * 60 * 60 * 1000), createdAt: new Date(Date.now() - 1 * 24 * 60 * 60 * 1000), isPrivate: true, + isJoined: true, }, { id: 4, @@ -64,6 +79,7 @@ const mockRooms = [ lastMessageAt: new Date(Date.now() - 10 * 60 * 1000), createdAt: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000), isPrivate: false, + isJoined: false, }, { id: 5, @@ -75,6 +91,7 @@ const mockRooms = [ lastMessageAt: new Date(Date.now() - 45 * 60 * 1000), createdAt: new Date(Date.now() - 3 * 24 * 60 * 60 * 1000), isPrivate: false, + isJoined: true, }, ] @@ -82,6 +99,10 @@ const FreetalkPeoplePage = () => { const navigate = useNavigate() const [searchQuery, setSearchQuery] = useState('') const [levelFilter, setLevelFilter] = useState('all') + const [selectedRoom, setSelectedRoom] = useState(null) + const [modalOpen, setModalOpen] = useState(false) + const [password, setPassword] = useState('') + const [passwordError, setPasswordError] = useState('') const handleLevelChange = (event, newLevel) => { if (newLevel !== null) { @@ -90,14 +111,44 @@ const FreetalkPeoplePage = () => { } const handleRoomClick = (room) => { - // TODO: 채팅방 입장 로직 - console.log('Entering room:', room.id) - navigate(`/freetalk/people/room/${room.id}`) + setSelectedRoom(room) + setPassword('') + setPasswordError('') + setModalOpen(true) + } + + const handleCloseModal = () => { + setModalOpen(false) + setSelectedRoom(null) + setPassword('') + setPasswordError('') + } + + const handleEnterRoom = () => { + if (selectedRoom?.isPrivate) { + // 비밀번호 검증 (더미: 1234) + if (password === '1234') { + navigate(`/freetalk/people/room/${selectedRoom.id}`) + handleCloseModal() + } else { + setPasswordError('비밀번호가 일치하지 않습니다') + } + } else { + navigate(`/freetalk/people/room/${selectedRoom.id}`) + handleCloseModal() + } } const filteredRooms = mockRooms.filter((room) => { const matchesSearch = room.name.toLowerCase().includes(searchQuery.toLowerCase()) - const matchesLevel = levelFilter === 'all' || room.level === levelFilter + let matchesLevel = false + if (levelFilter === 'all') { + matchesLevel = true + } else if (levelFilter === 'joined') { + matchesLevel = room.isJoined + } else { + matchesLevel = room.level === levelFilter + } return matchesSearch && matchesLevel }) @@ -142,6 +193,7 @@ const FreetalkPeoplePage = () => { 초급 중급 고급 + 참여중 @@ -182,6 +234,82 @@ const FreetalkPeoplePage = () => { > + + {/* 입장 모달 */} + + {selectedRoom && ( + <> + + + {selectedRoom.isPrivate && ( + + )} + + {selectedRoom.name} + + + + + {/* 방 정보 */} + + + + + + + {selectedRoom.currentMembers}/{selectedRoom.maxMembers}명 + + + + {selectedRoom.description && ( + + {selectedRoom.description} + + )} + + + {/* 비밀번호 입력 (비밀방인 경우) */} + {selectedRoom.isPrivate && ( + { + setPassword(e.target.value) + setPasswordError('') + }} + error={!!passwordError} + helperText={passwordError} + size="small" + autoFocus + /> + )} + + + + + + + )} + ) }