Skip to content

Commit 5c12eba

Browse files
authored
Merge pull request #5 from SPARCS-Service-Hackathon-2024/feature/chat
Feature/chat
2 parents a2cac55 + 5c0051e commit 5c12eba

File tree

11 files changed

+6452
-11392
lines changed

11 files changed

+6452
-11392
lines changed

package-lock.json

Lines changed: 6081 additions & 11387 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@
77
"@testing-library/jest-dom": "^5.17.0",
88
"@testing-library/react": "^13.4.0",
99
"@testing-library/user-event": "^13.5.0",
10+
"date-fns": "^3.3.1",
11+
"moment": "^2.30.1",
1012
"react": "^18.2.0",
13+
"react-calendar": "^4.8.0",
14+
"react-date-range": "^2.0.0-alpha.4",
1115
"react-dom": "^18.2.0",
1216
"react-modal": "^3.16.1",
1317
"react-router-dom": "^6.22.0",

src/App.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import OnBoarding from './pages/OnBoarding';
55
import Register from './pages/Register';
66
import Chat from './pages/Chat';
77
import ListPage from './pages/ListPage';
8+
import DetailPage from './pages/DetailPage'
89
import MyPage from './pages/MyPage';
10+
import RegisterHome from './pages/RegisterHome.js';
911

1012
function App() {
1113
return (
@@ -17,6 +19,8 @@ function App() {
1719
<Route path="chat" element={<Chat />} />
1820
<Route path="list" element={<ListPage />} />
1921
<Route path="mypage" element={<MyPage/>} />
22+
<Route path="registerHome" element={<RegisterHome />} />
23+
<Route path="detail/:house_id" element={<DetailPage />} />
2024
</Routes>
2125
</Router>
2226
</div>

src/components/Calendar.js

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import { DateRange } from 'react-date-range';
2+
import { Component } from 'react';
3+
import styled from 'styled-components';
4+
import CalendarIcon from '../assets/Today.svg';
5+
6+
const Container = styled.div`
7+
width: 100%
8+
display: flex;
9+
flex-direction: column;
10+
justify-content: center;
11+
height: 100vh;
12+
align-items: center;
13+
`;
14+
15+
const CalendarImage = styled.img`
16+
width: 52px;
17+
height: auto;
18+
padding-bottom: 16px;
19+
`;
20+
21+
const Label = styled.label`
22+
font-family: 'Pretendard', sans-serif;
23+
font-weight: 500;
24+
`;
25+
26+
const CalendarLabelContainer = styled.div`
27+
display: flex;
28+
flex-direction: column;
29+
align-items: flex-start;
30+
padding-top: 16px;
31+
padding-left: 27px;
32+
`;
33+
34+
const Button = styled.button`
35+
background-color: #864AE1;
36+
width: 80%;
37+
height: 45px;
38+
color: #fff;
39+
font-family: 'Pretendard', sans-serif;
40+
font-weight: 600;
41+
font-size: 14px;
42+
border: none;
43+
border-radius: 16px;
44+
margin: 4vh auto;
45+
cursor: pointer;
46+
display: flex;
47+
align-items: center;
48+
justify-content: center;
49+
`;
50+
51+
class Calendar extends Component {
52+
constructor(props) {
53+
super(props);
54+
this.state = {
55+
startDate: new Date(),
56+
endDate: new Date(),
57+
key: 'selection'
58+
};
59+
};
60+
61+
onRangeChange = (ranges) => {
62+
this.setState({
63+
startDate: ranges['selection'].startDate,
64+
endDate: ranges['selection'].endDate,
65+
key: ranges['selection'].key,
66+
});
67+
}
68+
69+
render() {
70+
const formatDate = (date) => date.toLocaleDateString();
71+
return (
72+
<Container>
73+
<DateRange
74+
editableDateInputs={true}
75+
onChange={this.onRangeChange}
76+
moveRangeOnFirstSelection={false}
77+
ranges={[this.state]}
78+
/>
79+
<div style={{ marginTop: '20px' }}>
80+
<CalendarLabelContainer>
81+
<CalendarImage src={CalendarIcon} />
82+
<Label>선택한 날짜를 확인해주세요</Label>
83+
{formatDate(this.state.startDate)} ~ {formatDate(this.state.endDate)}
84+
</CalendarLabelContainer>
85+
86+
<Button>
87+
원하는 날짜로 예약하기
88+
</Button>
89+
</div>
90+
</Container>
91+
)
92+
}
93+
}
94+
export default Calendar;

src/components/Header.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
color: black;
44
font-family: 'Pretendard', sans-serif;
55
/*text-align: center;*/
6-
height: 44px;
6+
height: 56px;
77
align-items: center;
88
justify-content: space-between;
99
display: flex;

src/components/RegisterHeader.css

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
.header {
2+
background-color: white;
3+
color: black;
4+
font-family: 'Pretendard', sans-serif;
5+
text-align: center;
6+
height: 56px;
7+
align-items: center;
8+
justify-content: space-between;
9+
display: flex;
10+
padding: 0 16px;
11+
width: 100%;
12+
position: sticky;
13+
z-index: 90;
14+
top: 0;
15+
box-sizing: border-box;
16+
top: constant(safe-area-inset-top);
17+
top: env(safe-area-inset-top);
18+
position: fixed;
19+
}

src/components/RegisterHeader.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import React from 'react';
2+
import './RegisterHeader.css';
3+
import BackIcon from '../assets/chevron.svg'
4+
5+
function RegisterHeader() {
6+
return (
7+
<header className="header">
8+
<a href="/list"><img src={BackIcon} alt="뒤로가기"/></a>
9+
<span>신청하기</span>
10+
<div></div>
11+
</header>
12+
);
13+
}
14+
15+
export default RegisterHeader;

src/pages/DetailPage.js

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
import React, { useEffect, useState } from 'react';
2+
import { useParams } from 'react-router-dom';
3+
import { detail } from '../services/detail';
4+
import map from '../assets/map-pin.svg';
5+
import schoolIcon from '../assets/schoolBuilding.svg';
6+
import styled from 'styled-components';
7+
8+
const Container = styled.div`
9+
width: 100%;
10+
display: flex;
11+
flex-direction: column;
12+
text-align: left;
13+
padding: 0 16px;
14+
`;
15+
16+
const AptImage = styled.img`
17+
width: 100%;
18+
height: 295px;
19+
`;
20+
21+
const SchoolImage = styled.img`
22+
width: 84px;
23+
height: auto;
24+
padding-top: 24px;
25+
`;
26+
27+
const AptName = styled.div`
28+
font-family: 'Pretendard', sans-serif;
29+
font-weight: 700;
30+
font-size: 24px;
31+
white-space: pre-line;
32+
text-align: left;
33+
padding-top: 12px;
34+
`;
35+
36+
const MapContainer = styled.div`
37+
display: flex;
38+
align-items: center;
39+
padding-top: 8px;
40+
`;
41+
42+
const MapImage = styled.img`
43+
width: 16px;
44+
height: auto;
45+
`;
46+
47+
const Address = styled.div`
48+
font-family: 'Pretendard', sans-serif;
49+
font-weight: 700;
50+
font-size: 14px;
51+
padding-left: 4px;
52+
white-space: pre-line;
53+
`;
54+
55+
const SchoolName = styled.div`
56+
font-family: 'Pretendard', sans-serif;
57+
font-weight: 700;
58+
font-size: 19px;
59+
white-space: pre-line;
60+
text-align: left;
61+
height: 56px;
62+
margin-top: 12px;
63+
`;
64+
65+
const Table = styled.div`
66+
display: table;
67+
width: 100%;
68+
margin-top: 8px;
69+
`;
70+
71+
const TableRow = styled.div`
72+
display: table-row;
73+
&:after {
74+
content: '';
75+
display: block;
76+
clear: both;
77+
}
78+
`;
79+
80+
const TableHeader = styled.div`
81+
display: table-cell;
82+
font-family: 'Pretendard', sans-serif;
83+
font-weight: 500;
84+
padding: 8px 0;
85+
text-align: left;
86+
`;
87+
88+
const TableData = styled.div`
89+
display: table-cell;
90+
padding-left: 30px;
91+
font-family: 'Pretendard', sans-serif;
92+
font-weight: 500;
93+
text-align: left;
94+
`;
95+
96+
function DetailPage() {
97+
const { house_id } = useParams();
98+
const [houseDetail, setHouseDetail] = useState(null);
99+
100+
useEffect(() => {
101+
async function fetchDetail() {
102+
const response = await detail(house_id);
103+
if (response.success) {
104+
setHouseDetail(response.data);
105+
console.log(response.data);
106+
} else {
107+
console.error('상세 정보를 불러오는데 실패했습니다.');
108+
}
109+
}
110+
111+
fetchDetail();
112+
}, [house_id]);
113+
114+
if (!houseDetail) {
115+
return <div>Loading...</div>;
116+
}
117+
118+
const renderRow = (label, value) => (
119+
<TableRow>
120+
<TableHeader>{label}</TableHeader>
121+
<TableData>{value}</TableData>
122+
</TableRow>
123+
);
124+
125+
return (
126+
<>
127+
<AptImage src={houseDetail.image_url} alt="아파트 이미지" />
128+
<Container>
129+
<AptName>{houseDetail.aptName}</AptName>
130+
<MapContainer>
131+
<MapImage src={map} alt="지도"/>
132+
<Address>{houseDetail.exposureAddress}</Address>
133+
</MapContainer>
134+
<Table>
135+
{renderRow('면적', `57.96m²`)}
136+
{renderRow('특징', houseDetail.tagList.join(', '))}
137+
{renderRow('보증금', `${houseDetail.aptHouseholdCount}만원`)}
138+
{renderRow('월세', `72만원`)}
139+
{renderRow('난방', `${houseDetail.aptHeatMethodTypeName}`)}
140+
{renderRow('가스', `${houseDetail.aptHeatFuelTypeName}`)}
141+
</Table>
142+
143+
<SchoolImage src={schoolIcon}/>
144+
<SchoolName>근처 학교를 알아봤어요</SchoolName>
145+
<Table>
146+
{renderRow('근처학교', `${houseDetail.schoolName}`)}
147+
{renderRow('학교 종류', `${houseDetail.organizationType}`)}
148+
{renderRow('학교까지 걸어서', `${houseDetail.walkTime}분`)}
149+
</Table>
150+
</Container>
151+
</>
152+
);
153+
}
154+
155+
export default DetailPage;

src/pages/ListPage.js

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import '../css/ListPage.css';
88
import HomeIcon from '../assets/home.svg';
99
import { ReactComponent as LocationIcon } from '../assets/map-pin.svg';
1010
import {like, list, rec_list} from '../services/list';
11+
import { useNavigate } from 'react-router-dom';
1112

1213

1314
const HomeImage = styled.img`
@@ -29,6 +30,8 @@ const NicknameText = styled.h1`
2930
`;
3031

3132
const ListPage = () => {
33+
const navigate = useNavigate();
34+
3235
const [nickname, setNickname] = useState('');
3336
const [items, setItems] = useState([]); // API로부터 받아온 데이터를 저장할 상태
3437
const [items2, setItems2] = useState([]); // API로부터 받아온 데이터를 저장할 상태
@@ -70,6 +73,10 @@ const ListPage = () => {
7073
fetchData();
7174
}, []);
7275

76+
const handleItemClick = (houseId) => {
77+
navigate(`/detail/${houseId}`); // 상세 페이지로 이동합니다.
78+
};
79+
7380
return (
7481
<>
7582
<Header />
@@ -112,10 +119,12 @@ const ListPage = () => {
112119
<div className="content-space">
113120
<img className="content-image2" src={item.image_url} alt={item.aptName}/>
114121
<div className="content-body">
115-
<div className="content-info">
116-
<span className="span-title">{item.aptName}</span>
117-
<span className="span-content"><LocationIcon
118-
className="location-icon"/>{item.exposureAddress}</span>
122+
<div key={index} className="item" onClick={() => handleItemClick(item.house_id)}>
123+
<div className="content-info">
124+
<span className="span-title">{item.aptName}</span>
125+
<span className="span-content"><LocationIcon
126+
className="location-icon"/>{item.exposureAddress}</span>
127+
</div>
119128
</div>
120129
<img
121130
src={item.is_like ? HeartIcon : HeartOffIcon}

0 commit comments

Comments
 (0)