Skip to content

Commit 105c473

Browse files
authored
roomCreation (#25)
1 parent 4745b53 commit 105c473

File tree

9 files changed

+258
-51
lines changed

9 files changed

+258
-51
lines changed

src/App.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useSetAtom } from 'jotai';
22
import { useEffect } from 'react';
3-
import { getMe } from './api/auth';
3+
import { User, getMe } from './api/auth';
44
import {
55
emailAtom,
66
isLoggedInAtom,
@@ -18,7 +18,7 @@ const App = () => {
1818
useEffect(() => {
1919
const checkUser = async () => {
2020
try {
21-
const user = await getMe();
21+
const user: User = await getMe();
2222
setIsLoggedIn(true);
2323
setEmail(user.email);
2424
setNickname(user.username);

src/api/auth.ts

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
1-
// import apiClient from './index';
1+
import apiClient from './index';
22

3-
// export interface User {
4-
// email: string;
5-
// username: string;
6-
// profileImageUrl: string | null;
7-
// role: 'USER';
8-
// }
3+
export interface User {
4+
email: string;
5+
username: string;
6+
profileImageUrl: string | null;
7+
role: 'USER';
8+
}
99

10-
// export const getMe = async (): Promise<User> => {
11-
// const response = await apiClient.get<User>('/user/profile');
12-
// return response.data;
13-
// };
14-
15-
// export const logout = async () => {
16-
// await apiClient.post('/logout');
17-
// };
10+
export const getMe = async (): Promise<User> => {
11+
const response = await apiClient.get<User>('/user/profile');
12+
return response.data;
13+
};

src/api/room.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,19 @@ interface RoomCreationResponse {
1313
createdPotId: number;
1414
}
1515

16+
export interface Pot {
17+
id: number;
18+
ownerId: number;
19+
departureId: number;
20+
destinationId: number;
21+
departureTime: string;
22+
minCapacity: number;
23+
maxCapacity: number;
24+
currentCount: number;
25+
estimatedFee: number;
26+
status: 'RECRUITING' | 'WAITING' | 'DEPARTED' | 'COMPLETED' | 'CANCELLED';
27+
}
28+
1629
export const createRoom = async (
1730
roomDetails: RoomCreationRequest
1831
): Promise<RoomCreationResponse> => {
@@ -22,3 +35,12 @@ export const createRoom = async (
2235
);
2336
return response.data;
2437
};
38+
39+
export const getCurrentPot = async (): Promise<Pot> => {
40+
const response = await apiClient.get<Pot>('/users/me/pot');
41+
return response.data;
42+
};
43+
44+
export const deleteRoom = async (roomId: number): Promise<void> => {
45+
await apiClient.delete(`/rooms/${roomId}`);
46+
};

src/api/user.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import apiClient from './index';
22

3+
interface UsernameUpdateRequest {
4+
username: string;
5+
}
6+
37
export const updateProfilePicture = async (file: File) => {
48
const formData = new FormData();
59
formData.append('picture', file);
@@ -12,3 +16,11 @@ export const updateProfilePicture = async (file: File) => {
1216

1317
return response.data;
1418
};
19+
20+
export const updateUsername = async (username: string) => {
21+
const response = await apiClient.patch<UsernameUpdateRequest>(
22+
'/user/profile',
23+
{ username }
24+
);
25+
return response.data;
26+
};

src/components/NavBar/index.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { useAtom } from 'jotai';
22
import { FaComment, FaPlus, FaSearch, FaUser } from 'react-icons/fa';
33
import { Link, useLocation } from 'react-router-dom';
4-
// import { logout } from '../../api/auth';
54
import { BACKEND_URL } from '../../api/constants';
65
import {
76
emailAtom,

src/pages/CreateRoom/index.tsx

Lines changed: 46 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,33 @@
1+
import { isAxiosError } from 'axios';
12
import { useAtom } from 'jotai';
23
import { useState } from 'react';
34
import { useNavigate } from 'react-router-dom';
45
import { createRoom } from '../../api/room';
56
import { isLoggedInAtom } from '../../common/user';
67
import './CreateRoom.css';
78

8-
const landmarks = {
9-
서울대입구역: 1,
10-
낙성대역: 2,
11-
자연대: 3,
12-
행정관: 4,
13-
};
9+
const LANDMARKS = [
10+
{ id: 1, name: '서울대입구역 3번 출구' },
11+
{ id: 2, name: '낙성대역 버스정류장' },
12+
{ id: 3, name: '낙성대입구 버스정류장' },
13+
{ id: 4, name: '대학동고시촌입구(녹두)' },
14+
{ id: 5, name: '사당역 4번 출구' },
15+
{ id: 6, name: '경영대.행정대학원' },
16+
{ id: 7, name: '자연대.행정관입구' },
17+
{ id: 8, name: '법대.사회대입구' },
18+
{ id: 9, name: '농생대' },
19+
{ id: 10, name: '공대입구(글로벌공학)' },
20+
{ id: 11, name: '제2공학관(302동)' },
21+
{ id: 12, name: '학부생활관' },
22+
{ id: 13, name: '수의대입구.보건대학원' },
23+
{ id: 14, name: '기숙사 삼거리' },
24+
{ id: 15, name: '국제대학원' },
25+
];
1426

1527
const CreateRoom = () => {
1628
const navigate = useNavigate();
17-
const [start, setStart] = useState('');
18-
const [end, setEnd] = useState('');
29+
const [start, setStart] = useState('1');
30+
const [end, setEnd] = useState('2');
1931
const [departureTime, setDepartureTime] = useState('');
2032
const [minCapacity, setMinCapacity] = useState(2);
2133
const [isLoggedIn] = useAtom(isLoggedInAtom);
@@ -44,25 +56,31 @@ const CreateRoom = () => {
4456
return;
4557
}
4658

47-
const departureId = landmarks[start as keyof typeof landmarks];
48-
const destinationId = landmarks[end as keyof typeof landmarks];
59+
const departureId = parseInt(start, 10);
60+
const destinationId = parseInt(end, 10);
4961

5062
const departureTimeISO = new Date(departureTime).toISOString();
5163

64+
const roomDetails = {
65+
departureId,
66+
destinationId,
67+
departureTime: departureTimeISO,
68+
minCapacity,
69+
maxCapacity: 4, // Hardcoded
70+
estimatedFee: 0, // Hardcoded
71+
};
72+
5273
try {
53-
await createRoom({
54-
departureId,
55-
destinationId,
56-
departureTime: departureTimeISO,
57-
minCapacity,
58-
maxCapacity: 4, // Hardcoded
59-
estimatedFee: 0, // Hardcoded
60-
});
61-
62-
alert('방이 성공적으로 개설되었습니다!');
74+
const _response = await createRoom(roomDetails);
75+
76+
alert('방이 성공적으로 개설되었습니다! ID: ' + _response.createdPotId);
6377
navigate('/search-room');
64-
} catch (error) {
65-
console.error('Error creating room:', error);
78+
} catch (error: unknown) {
79+
if (isAxiosError(error)) {
80+
console.error('Error creating room:', error.response?.data);
81+
} else {
82+
console.error('An unexpected error occurred:', error);
83+
}
6684
alert('방 개설 중 오류가 발생했습니다.');
6785
}
6886
};
@@ -75,9 +93,9 @@ const CreateRoom = () => {
7593
<div className="location-select">
7694
<select value={start} onChange={(e) => setStart(e.target.value)}>
7795
<option value="">출발지</option>
78-
{Object.keys(landmarks).map((landmark) => (
79-
<option key={`start-${landmark}`} value={landmark}>
80-
{landmark}
96+
{LANDMARKS.map((landmark) => (
97+
<option key={`start-${landmark.id}`} value={landmark.id}>
98+
{landmark.name}
8199
</option>
82100
))}
83101
</select>
@@ -86,9 +104,9 @@ const CreateRoom = () => {
86104
<div className="location-select">
87105
<select value={end} onChange={(e) => setEnd(e.target.value)}>
88106
<option value="">도착지</option>
89-
{Object.keys(landmarks).map((landmark) => (
90-
<option key={`end-${landmark}`} value={landmark}>
91-
{landmark}
107+
{LANDMARKS.map((landmark) => (
108+
<option key={`end-${landmark.id}`} value={landmark.id}>
109+
{landmark.name}
92110
</option>
93111
))}
94112
</select>

src/pages/MyChat/MyChat.css

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
.my-chat-container {
2+
padding: 20px;
3+
}
4+
5+
.current-pot-card {
6+
border: 1px solid #ccc;
7+
border-radius: 8px;
8+
margin-bottom: 10px;
9+
padding: 15px;
10+
transition: background-color 0.2s;
11+
display: flex;
12+
align-items: center;
13+
}
14+
15+
.current-pot-card:hover {
16+
background-color: #f5f5f5;
17+
}
18+
19+
.pot-link {
20+
flex-grow: 1;
21+
text-decoration: none;
22+
color: inherit;
23+
}
24+
25+
.pot-details {
26+
display: flex;
27+
justify-content: space-between;
28+
align-items: center;
29+
}
30+
31+
.pot-info {
32+
font-size: 1.2em;
33+
}
34+
35+
.pot-meta {
36+
display: flex;
37+
flex-direction: column;
38+
align-items: flex-end;
39+
font-size: 0.9em;
40+
color: #666;
41+
}
42+
43+
.delete-button {
44+
background-color: #ff4d4d;
45+
color: white;
46+
border: none;
47+
padding: 8px 12px;
48+
border-radius: 4px;
49+
cursor: pointer;
50+
margin-left: 20px;
51+
}
52+
53+
.delete-button:hover {
54+
background-color: #ff1a1a;
55+
}

src/pages/MyChat/index.tsx

Lines changed: 101 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,105 @@
1+
import { isAxiosError } from 'axios';
2+
import { useCallback, useEffect, useState } from 'react';
3+
import { Link } from 'react-router-dom';
4+
import { Pot, deleteRoom, getCurrentPot } from '../../api/room';
5+
import './MyChat.css';
6+
7+
const landmarks = {
8+
1: '서울대입구역',
9+
2: '낙성대역',
10+
3: '자연대',
11+
4: '행정관',
12+
};
13+
114
const MyChat = () => {
2-
return <div>My Chat</div>;
15+
const [currentPot, setCurrentPot] = useState<Pot | null>(null);
16+
const [loading, setLoading] = useState(true);
17+
18+
const fetchCurrentPot = useCallback(async () => {
19+
setLoading(true);
20+
try {
21+
const pot = await getCurrentPot();
22+
setCurrentPot(pot);
23+
} catch (error: unknown) {
24+
if (isAxiosError(error)) {
25+
console.error('Error fetching current pot:', error.response?.data);
26+
} else {
27+
console.error('An unexpected error occurred:', error);
28+
}
29+
setCurrentPot(null); // Ensure currentPot is null on error
30+
} finally {
31+
setLoading(false);
32+
}
33+
}, []);
34+
35+
useEffect(() => {
36+
fetchCurrentPot();
37+
}, [fetchCurrentPot]);
38+
39+
const handleDelete = async () => {
40+
if (currentPot) {
41+
// eslint-disable-next-line no-restricted-globals
42+
if (confirm('정말로 현재 방에서 나가시겠습니까?')) {
43+
try {
44+
await deleteRoom(currentPot.id);
45+
alert('방에서 나갔습니다.');
46+
fetchCurrentPot(); // Refresh pot data
47+
} catch (error: unknown) {
48+
if (isAxiosError(error)) {
49+
console.error('Error deleting room:', error.response?.data);
50+
} else {
51+
console.error('An unexpected error occurred:', error);
52+
}
53+
alert('방에서 나가는 중 오류가 발생했습니다.');
54+
}
55+
}
56+
}
57+
};
58+
59+
if (loading) {
60+
return <div>Loading...</div>;
61+
}
62+
63+
return (
64+
<div className="my-chat-container">
65+
<h1>My Current Pot</h1>
66+
{currentPot === null ? (
67+
<p>You are not currently in any pot.</p>
68+
) : (
69+
<div className="current-pot-card">
70+
<Link to={`/chat/${currentPot.id}`} className="pot-link">
71+
<div className="pot-details">
72+
<div className="pot-info">
73+
<span>
74+
{landmarks[currentPot.departureId as keyof typeof landmarks]}
75+
</span>{' '}
76+
{' '}
77+
<span>
78+
{
79+
landmarks[
80+
currentPot.destinationId as keyof typeof landmarks
81+
]
82+
}
83+
</span>
84+
</div>
85+
<div className="pot-meta">
86+
<span>
87+
{new Date(currentPot.departureTime).toLocaleString()}
88+
</span>
89+
<span>
90+
{currentPot.currentCount}/{currentPot.maxCapacity}
91+
</span>
92+
<span>Status: {currentPot.status}</span>
93+
</div>
94+
</div>
95+
</Link>
96+
<button className="delete-button" onClick={handleDelete}>
97+
나가기
98+
</button>
99+
</div>
100+
)}
101+
</div>
102+
);
3103
};
4104

5105
export default MyChat;

0 commit comments

Comments
 (0)