Skip to content

Commit e406eef

Browse files
authored
Merge pull request #44 from CommitField/89
89
2 parents e83d9ee + c1bcf2d commit e406eef

File tree

4 files changed

+130
-36
lines changed

4 files changed

+130
-36
lines changed

src/components/ChatRoomList.jsx

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import ChatService from '../services/ChatService';
44
import ChatRoom from './ChatRoom';
55
import PasswordModal from './PasswordModal';
66
import './ChatStyles.css';
7+
import { API_BACKEND_URL } from '../config';
78

89
const ChatRoomList = () => {
910
const [rooms, setRooms] = useState([]);
@@ -255,6 +256,16 @@ const ChatRoomList = () => {
255256
// Check if room list is empty
256257
const isRoomsEmpty = rooms.length === 0;
257258

259+
const getImageUrl = (imageUrl) => {
260+
if (!imageUrl) return null;
261+
console.log('Original imageUrl:', imageUrl); // 디버깅용
262+
// API_BACKEND_URL이 이미 슬래시로 끝나지 않는지 확인
263+
const baseUrl = API_BACKEND_URL.endsWith('/') ? API_BACKEND_URL.slice(0, -1) : API_BACKEND_URL;
264+
const fullUrl = `${baseUrl}${imageUrl}`;
265+
console.log('Full imageUrl:', fullUrl); // 디버깅용
266+
return fullUrl;
267+
};
268+
258269
return (
259270
<div className="chat-layout">
260271
{/* 채팅방 목록 컨테이너 */}
@@ -320,8 +331,22 @@ const ChatRoomList = () => {
320331
onClick={() => handleJoinRoom(room.id)}
321332
>
322333
<div className="profile-img">
323-
{/* 프로필 이미지 또는 잠금 아이콘 표시 */}
324-
{room.isPrivate && <i className="fa-solid fa-lock" style={{ color: '#e74c3c' }}></i>}
334+
{room.imageUrl ? (
335+
<img
336+
src={getImageUrl(room.imageUrl)}
337+
alt={room.title}
338+
className="room-image"
339+
onError={(e) => {
340+
console.log('Image load failed:', room.imageUrl);
341+
e.target.onerror = null;
342+
e.target.src = '/default-room.png';
343+
}}
344+
/>
345+
) : (
346+
<div className="default-room-image">
347+
<i className="fa-solid fa-comments"></i>
348+
</div>
349+
)}
325350
</div>
326351
<div className="chat-info">
327352
<div className="chat-name">

src/components/ChatStyles.css

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -138,15 +138,34 @@
138138
}
139139

140140
.chat-room .profile-img {
141-
width: 50px;
142-
height: 50px;
143-
border-radius: 50%;
144-
background-color: var(--pink);
145-
margin-right: 15px;
141+
width: 60px;
142+
height: 60px;
143+
min-width: 60px;
144+
border-radius: 8px;
145+
overflow: hidden;
146+
margin-right: 12px;
147+
background: #f0f0f0;
146148
display: flex;
149+
align-items: center;
147150
justify-content: center;
151+
}
152+
153+
.chat-room .room-image {
154+
width: 100%;
155+
height: 100%;
156+
object-fit: cover;
157+
border-radius: 8px;
158+
}
159+
160+
.chat-room .default-room-image {
161+
width: 100%;
162+
height: 100%;
163+
display: flex;
148164
align-items: center;
149-
overflow: hidden;
165+
justify-content: center;
166+
background-color: #e9ecef;
167+
color: #6c757d;
168+
font-size: 24px;
150169
}
151170

152171
.chat-room .chat-info {

src/components/CreateChatRoom.jsx

Lines changed: 55 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ const CreateChatRoom = () => {
88
const [userCountMax, setUserCountMax] = useState(10);
99
const [password, setPassword] = useState('');
1010
const [isPrivate, setIsPrivate] = useState(false);
11+
const [file, setFile] = useState(null);
12+
const [previewUrl, setPreviewUrl] = useState(null);
1113
const [loading, setLoading] = useState(false);
1214
const [errors, setErrors] = useState({});
1315
const navigate = useNavigate();
@@ -60,40 +62,52 @@ const CreateChatRoom = () => {
6062
return Object.keys(newErrors).length === 0;
6163
};
6264

63-
const handleSubmit = async (e) => {
64-
e.preventDefault();
65+
const handleFileChange = (e) => {
66+
const selectedFile = e.target.files[0];
67+
if (selectedFile) {
68+
// 파일 정보 로깅
69+
console.log('Selected file:', {
70+
name: selectedFile.name,
71+
type: selectedFile.type,
72+
size: selectedFile.size
73+
});
74+
75+
// 파일 크기 검사 (5MB)
76+
if (selectedFile.size > 5 * 1024 * 1024) {
77+
setErrors({ ...errors, file: '파일 크기는 5MB를 초과할 수 없습니다.' });
78+
return;
79+
}
80+
81+
// 이미지 파일 타입 검사
82+
if (!selectedFile.type.startsWith('image/')) {
83+
setErrors({ ...errors, file: '이미지 파일만 업로드 가능합니다.' });
84+
return;
85+
}
6586

66-
if (!validateForm()) {
67-
return;
87+
setFile(selectedFile);
88+
setPreviewUrl(URL.createObjectURL(selectedFile));
89+
setErrors({ ...errors, file: null });
6890
}
91+
};
92+
93+
const handleSubmit = async (e) => {
94+
e.preventDefault();
95+
if (!validateForm()) return;
6996

7097
setLoading(true);
7198
try {
72-
// 비공개방이 아니면 비밀번호 없이 전송
73-
const roomData = {
74-
title,
75-
userCountMax,
76-
...(isPrivate && { password })
77-
};
78-
79-
console.log('Creating room with:', roomData);
80-
const response = await ChatService.createRoom(roomData.title, roomData.userCountMax, roomData.password);
81-
console.log('Create room response:', response);
82-
99+
console.log('Submitting form with file:', file);
100+
const response = await ChatService.createRoom(title, userCountMax, file);
101+
83102
if (response && !response.errorCode) {
84-
// 성공 메시지 표시
85103
alert('채팅방이 성공적으로 생성되었습니다.');
86-
87-
// 로컬 스토리지를 사용하여 상태 갱신 트리거
88104
localStorage.setItem('chatRoomChanged', Date.now().toString());
89-
90-
// 채팅방 목록으로 이동
91105
navigate('/chat-rooms', { replace: true });
92106
} else {
93107
alert(response.message || '채팅방 생성에 실패했습니다.');
94108
}
95109
} catch (err) {
96-
console.error('Error creating room:', err);
110+
console.error('Error in handleSubmit:', err);
97111
alert(err.message || '채팅방 생성에 실패했습니다.');
98112
} finally {
99113
setLoading(false);
@@ -173,6 +187,26 @@ const CreateChatRoom = () => {
173187
</div>
174188
)}
175189

190+
<div className="form-group">
191+
<label className="form-label">채팅방 이미지</label>
192+
<input
193+
type="file"
194+
accept="image/*"
195+
onChange={handleFileChange}
196+
className="form-control"
197+
/>
198+
{errors.file && <p className="error-message">{errors.file}</p>}
199+
{previewUrl && (
200+
<div className="image-preview">
201+
<img
202+
src={previewUrl}
203+
alt="미리보기"
204+
style={{ maxWidth: '200px', maxHeight: '200px' }}
205+
/>
206+
</div>
207+
)}
208+
</div>
209+
176210
<div className="form-actions">
177211
<button
178212
type="button"

src/services/ChatService.js

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -152,27 +152,43 @@ const ChatService = {
152152
}
153153
},
154154

155-
createRoom: async (title, userCountMax) => {
155+
createRoom: async (title, userCountMax, file = null) => {
156156
try {
157157
if (!title || !userCountMax) {
158158
throw new Error('제목과 최대 인원 수는 필수 입력값입니다.');
159159
}
160160

161-
console.log('Creating room with:', { title, userCountMax: parseInt(userCountMax) });
162-
const response = await apiClient.post('/chat/room', {
163-
title,
164-
userCountMax: parseInt(userCountMax)
161+
const formData = new FormData();
162+
formData.append('title', title);
163+
formData.append('userCountMax', parseInt(userCountMax));
164+
165+
// 파일 업로드 디버깅
166+
if (file) {
167+
console.log('Uploading file:', file);
168+
formData.append('file', file);
169+
}
170+
171+
// FormData 내용 확인
172+
for (let pair of formData.entries()) {
173+
console.log(pair[0] + ': ' + pair[1]);
174+
}
175+
176+
console.log('Creating room with:', { title, userCountMax, file });
177+
const response = await apiClient.post('/chat/room', formData, {
178+
headers: {
179+
'Content-Type': 'multipart/form-data',
180+
},
165181
});
182+
166183
console.log('Create room response:', response);
167184

168185
if (response && !response.errorCode) {
169-
// 모든 캐시 초기화
170186
cache.clearCache();
171187
}
172188

173189
return response;
174190
} catch (error) {
175-
console.error('Error creating room:', error);
191+
console.error('Error creating room:', error.response || error);
176192
throw error;
177193
}
178194
},

0 commit comments

Comments
 (0)