Skip to content

Commit bb3a870

Browse files
authored
Merge pull request #190 from CampingOn/style/#188-camp-details
Style: #188 캠핑장 상세 페이지 일부 수정
2 parents ea2986a + 8f333c1 commit bb3a870

File tree

5 files changed

+188
-88
lines changed

5 files changed

+188
-88
lines changed

src/components/Review/ReviewList.js

+59-25
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import { Box, Typography, CircularProgress, Snackbar, Alert } from "@mui/materia
33
import { useNavigate } from "react-router-dom";
44
import { reviewService } from "../../api/services/reviewService";
55
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
6+
import RateReviewOutlinedIcon from '@mui/icons-material/RateReviewOutlined';
7+
68

79
const DEFAULT_IMAGE = "/default/reviewImage.jpg";
810

@@ -71,51 +73,51 @@ const ReviewList = ({ campId }) => {
7173
<Box
7274
key={review.reviewId}
7375
sx={{
76+
display: "flex",
77+
flexDirection: "row",
78+
justifyContent: "space-between",
79+
alignItems: "center",
7480
border: "1px solid #ddd",
7581
borderRadius: "8px",
7682
boxShadow: "0px 4px 8px rgba(0, 0, 0, 0.1)",
77-
display: "flex",
78-
flexDirection: "column",
7983
overflow: "hidden",
8084
background: "#fff",
85+
padding: 2,
8186
cursor: "pointer",
8287
transition: "transform 0.3s",
8388
"&:hover": {
8489
transform: "scale(1.02)",
8590
},
91+
gap: 3, // 사진과 내용 사이 간격 추가
8692
}}
8793
onClick={() => navigate(`/camps/reviews/${review.reviewId}`)}
8894
>
8995
<Box
9096
sx={{
91-
height: "200px",
92-
overflow: "hidden",
93-
}}
94-
>
95-
<img
96-
src={review.images && review.images.length > 0 ? review.images[0] : DEFAULT_IMAGE}
97-
alt="리뷰 이미지"
98-
style={{
99-
width: "100%",
100-
height: "100%",
101-
objectFit: "cover",
102-
}}
103-
/>
104-
</Box>
105-
<Box
106-
sx={{
107-
padding: 2,
10897
display: "flex",
10998
flexDirection: "column",
110-
justifyContent: "space-between",
99+
justifyContent: "flex-start",
100+
gap: 2,
101+
flex: 1, // 부모 컨테이너의 크기를 차지
102+
minHeight: "140px", // 전체 최소 높이 설정
111103
}}
112104
>
105+
{/* 제목 */}
113106
<Typography
114107
variant="subtitle1"
115-
sx={{ fontWeight: "bold", marginBottom: "8px" }}
108+
sx={{
109+
fontWeight: "bold",
110+
height: "24px", // 고정 높이
111+
overflow: "hidden",
112+
textOverflow: "ellipsis",
113+
whiteSpace: "nowrap",
114+
marginBottom: "4px", // 아래 여백 추가
115+
}}
116116
>
117117
{review.title}
118118
</Typography>
119+
120+
{/* 본문 */}
119121
<Typography
120122
variant="body2"
121123
sx={{
@@ -124,22 +126,50 @@ const ReviewList = ({ campId }) => {
124126
overflow: "hidden",
125127
textOverflow: "ellipsis",
126128
display: "-webkit-box",
127-
WebkitLineClamp: 3,
129+
WebkitLineClamp: 3, // 최대 3줄까지 표시
128130
WebkitBoxOrient: "vertical",
131+
marginBottom: "8px", // 추가 여백
129132
}}
130133
>
131134
{review.content}
132135
</Typography>
136+
137+
{/* 추천 여부 */}
133138
<Typography
134139
variant="caption"
135140
sx={{
136141
color: review.recommended ? "#4caf50" : "#f44336",
137-
marginTop: "8px",
142+
visibility: review.recommended ? "visible" : "hidden", // "추천"이 아닐 때 숨김
143+
marginTop: "auto", // 추천 여부를 항상 아래에 배치
138144
}}
139145
>
140-
{review.recommended ? "추천" : "비추천"}
146+
{review.recommended ? "추천해요! 👍" : "비추천"}
141147
</Typography>
142148
</Box>
149+
{/* Right Side: Image */}
150+
<Box
151+
sx={{
152+
width: "140px", // Fixed image size
153+
height: "140px",
154+
borderRadius: "8px",
155+
overflow: "hidden",
156+
border: "1px solid #f5f5f5", // Border matching the screenshot
157+
boxShadow: "0px 4px 8px rgba(0, 0, 0, 0.1)",
158+
display: "flex",
159+
alignItems: "center",
160+
justifyContent: "center",
161+
}}
162+
>
163+
<img
164+
src={review.images && review.images.length > 0 ? review.images[0] : DEFAULT_IMAGE}
165+
alt="리뷰 이미지"
166+
style={{
167+
width: "100%",
168+
height: "100%",
169+
objectFit: "cover",
170+
}}
171+
/>
172+
</Box>
143173
</Box>
144174
))}
145175
</Box>
@@ -150,13 +180,17 @@ const ReviewList = ({ campId }) => {
150180
borderRadius: "8px",
151181
height: "400px",
152182
display: "flex",
183+
flexDirection: "column",
153184
alignItems: "center",
154185
justifyContent: "center",
155186
color: "#999",
156187
marginTop: 4,
157188
}}
158189
>
159-
리뷰가 없습니다. 첫 번째 리뷰를 작성해보세요!
190+
<RateReviewOutlinedIcon sx={{ fontSize: 48, marginBottom: 2, color: "#ccc" }} />
191+
<Typography variant="body1">
192+
리뷰가 없습니다. 첫 번째 리뷰를 작성해보세요!
193+
</Typography>
160194
</Box>
161195
)}
162196

src/components/camp/AddressInfo.js

+49-30
Original file line numberDiff line numberDiff line change
@@ -3,35 +3,54 @@ import WebIcon from "@mui/icons-material/Web";
33
import CallIcon from "@mui/icons-material/Call";
44
import LocationOnIcon from "@mui/icons-material/LocationOn";
55

6-
const AddressInfo = ({ address, tel, homepage }) => (
7-
<div className="camp-detail-info-bar">
8-
{/* 도로명 주소 */}
9-
<div className="info-bar-section">
10-
<LocationOnIcon style={{ verticalAlign: "middle", marginRight: "8px" }} />
11-
<span>{address || "도로명 주소 정보 없음"}</span>
12-
</div>
13-
{/* 연락처 */}
14-
<div className="info-bar-section">
15-
<CallIcon style={{ verticalAlign: "middle", marginRight: "8px" }} />
16-
<span>{tel || "연락처 정보 없음"}</span>
17-
</div>
18-
{/* 홈페이지 */}
19-
<div className="info-bar-section">
20-
<WebIcon style={{ verticalAlign: "middle", marginRight: "8px" }} />
21-
{homepage ? (
22-
<a
23-
href={homepage}
24-
target="_blank"
25-
rel="noopener noreferrer"
26-
className="homepage-link"
27-
>
28-
홈페이지 바로가기
29-
</a>
30-
) : (
31-
"홈페이지 정보 없음"
32-
)}
6+
7+
const AddressInfo = ({ address, tel, homepage }) => {
8+
// 전화번호 가공: '-' 제거
9+
const formatTel = (tel) => {
10+
if (!tel) return null;
11+
return tel.replace(/-/g, ''); // '-' 제거
12+
};
13+
14+
const formattedTel = formatTel(tel);
15+
return (
16+
<div className="camp-detail-info-bar">
17+
{/* 도로명 주소 */}
18+
<div className="info-bar-section address">
19+
<LocationOnIcon style={{ verticalAlign: "middle", marginRight: "8px" }} />
20+
<span>{address || "도로명 주소 정보 없음"}</span>
21+
</div>
22+
{/* 연락처 */}
23+
<div className="info-bar-section contact">
24+
<CallIcon style={{ verticalAlign: "middle", marginRight: "8px" }} />
25+
{formattedTel ? (
26+
<a
27+
href={`tel:${formattedTel}`}
28+
>
29+
{tel}
30+
</a>
31+
) : (
32+
"연락처 정보 없음"
33+
)}
34+
</div>
35+
{/* 홈페이지 */}
36+
<div className="info-bar-section homepage">
37+
<WebIcon style={{ verticalAlign: "middle", marginRight: "8px" }} />
38+
{homepage ? (
39+
<a
40+
href={homepage}
41+
target="_blank"
42+
rel="noopener noreferrer"
43+
className="homepage-link"
44+
>
45+
홈페이지 바로가기
46+
</a>
47+
) : (
48+
"홈페이지 정보 없음"
49+
)}
50+
</div>
3351
</div>
34-
</div>
35-
);
52+
);
53+
};
54+
3655

37-
export default AddressInfo;
56+
export default AddressInfo;

src/components/camp/CampInfo.js

+8-6
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
11
import React from "react";
2-
import ThumbUpIcon from "@mui/icons-material/ThumbUp";
32
import FavoriteIcon from "@mui/icons-material/Favorite";
43
import PropTypes from "prop-types";
4+
import ThumbUpIcon from '@mui/icons-material/ThumbUp';
55

66
const CampInfo = ({ recommend, bookmark }) => {
77
return (
8-
<div className="flex items-center space-x-6"> {/* space-x-6 클래스를 사용하여 요소 간의 간격을 넓힘 */}
8+
<div className="flex items-center space-x-6"
9+
style={{ marginTop: 'auto' }} // 하단으로 밀어내기
10+
> {/* space-x-6 클래스를 사용하여 요소 간의 간격을 넓힘 */}
911
{/* 추천 수 */}
1012
<div className="flex items-center space-x-2"> {/* space-x-2 클래스를 사용하여 아이콘과 텍스트 간의 간격을 설정 */}
11-
<ThumbUpIcon className="text-blue-600" style={{ fontSize: '24px' }} />
12-
<span className="text-lg font-bold">+{recommend}</span>
13+
<ThumbUpIcon style={{ fontSize: '24px', color: "#5c6bc0"}} />
14+
<span className="text-lg font-bold"> {recommend}</span>
1315
</div>
1416

1517
{/* 찜 수 */}
1618
<div className="flex items-center space-x-2"> {/* space-x-2 클래스를 사용하여 아이콘과 텍스트 간의 간격을 설정 */}
17-
<FavoriteIcon className="text-red-500" style={{ fontSize: '24px' }} />
18-
<span className="text-lg font-bold">+{bookmark}</span>
19+
<FavoriteIcon style={{ fontSize: '24px', color: "#ff7961" }} />
20+
<span className="text-lg font-bold"> {bookmark}</span>
1921
</div>
2022
</div>
2123
);

src/pages/camp/CampDetail.js

+31-17
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import "../../style/available-list.css";
2121
import CampInfo from "../../components/camp/CampInfo";
2222
import ReviewList from "../../components/Review/ReviewList";
2323
import { Box, Typography } from "@mui/material";
24+
import EventOutlinedIcon from '@mui/icons-material/EventOutlined';
2425

2526

2627
function calculateNights(checkin, checkout) {
@@ -86,15 +87,24 @@ function CampDetail() {
8687
console.log('🔍 checkin:', checkin, 'checkout:', checkout, '박 수 (nights):', nights); // 디버깅 로그
8788

8889
return (
89-
<div className="camp-detail-container" style={{ padding: '0', marginTop: '60px' }}>
90+
<div className="camp-detail-container" style={{padding: '0', marginTop: '60px'}}>
9091
<div className="camp-detail-header"
91-
style={{display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: '20px'}}
92+
style={{
93+
display: "flex",
94+
justifyContent: "space-between",
95+
alignItems: "center",
96+
marginBottom: '20px'
97+
}}
9298
>
93-
<h1 className="camp-detail-title">{name || "캠핑장 이름 없음"}</h1>
99+
<div style={{display: "flex", flexDirection: "column", alignItems: "flex-start"}}>
100+
<p className="camp-detail-small-address">{campAddr?.city} {campAddr?.state}</p>
101+
<h1 className="camp-detail-title">{name || "캠핑장 이름 없음"}</h1>
102+
</div>
94103
<CampInfo
95104
recommend={campInfo.recommendCnt} // 추천 수
96105
bookmark={campInfo.bookmarkCnt} // 찜 수
97-
/></div>
106+
/>
107+
</div>
98108

99109
{/* images가 빈 배열일 경우 랜덤 썸네일로 채우기 */}
100110
{(!images || images.length === 0) ? (
@@ -118,9 +128,9 @@ function CampDetail() {
118128
<AddressInfo address={campAddr?.streetAddr} tel={tel} homepage={homepage}/>
119129
<CampDetailIntro intro={intro}/>
120130
<div style={{
121-
display: 'flex',
122-
gap: '16px',
123-
width: '100%',
131+
display: 'flex',
132+
gap: '16px',
133+
width: '100%',
124134
marginTop: '30px',
125135
alignItems: 'stretch'
126136
}}>
@@ -129,7 +139,7 @@ function CampDetail() {
129139
display: 'flex',
130140
}}>
131141
<OperationPolicy
132-
style={{ flex: '1' }}
142+
style={{flex: '1'}}
133143
industries={campDetails.indutys || []}
134144
outdoorFacility={campDetails.outdoorFacility || "부대시설 정보 없음"}
135145
animalAdmission={campDetails.animalAdmission}
@@ -143,7 +153,7 @@ function CampDetail() {
143153
border: '1px solid #000000'
144154
}}>
145155
<KakaoMap
146-
style={{ flex: '1' }}
156+
style={{flex: '1'}}
147157
latitude={campAddr?.latitude}
148158
longitude={campAddr?.longitude}
149159
locationName={name}
@@ -152,10 +162,10 @@ function CampDetail() {
152162
</Box>
153163
</div>
154164

155-
<div className="camp-date-picker-container" style={{ marginTop: '80px' }}>
165+
<div className="camp-date-picker-container" style={{marginTop: '80px'}}>
156166
<h2 style={{fontSize: '1.1rem', fontWeight: 'initial'}}>
157-
<span>🏕️ 캠핑을 원하시는 날짜를 선택하고,</span>
158-
<span>특별한 여행을 시작하세요! 🏕</span>
167+
<span>🏕️ 원하시는 날짜를 선택하고,</span>
168+
<span>특별한 캠핑을 시작하세요! 🏕</span>
159169
</h2>
160170
<CampDatePicker
161171
checkin={checkin}
@@ -165,7 +175,7 @@ function CampDetail() {
165175
</div>
166176

167177
<div className="camp-site-list-available">
168-
<h1 style={{fontSize: '1.8rem', fontWeight: 'bold', marginBottom: '20px'}}>예약 가능한 캠핑지 목록</h1>
178+
<h1 style={{fontSize: '1.5rem', fontWeight: 'bold', marginBottom: '20px'}}>예약 가능한 캠핑지 목록</h1>
169179
{/* 캠핑지가 없을 때 빈 카드 표시 */}
170180
{!localAvailableSites || localAvailableSites.length === 0 ? (
171181
<div
@@ -176,17 +186,21 @@ function CampDetail() {
176186
height: "370px",
177187
display: "flex",
178188
alignItems: "center",
189+
flexDirection: "column",
179190
justifyContent: "center",
180191
margin: "20px 0",
181192
color: "#999",
182193
}}
183194
>
184-
날짜를 선택하여 캠핑지를 확인하세요.
195+
<EventOutlinedIcon sx={{fontSize: 48, marginBottom: 2, color: "#ccc"}}/>
196+
<Typography variant="body1">
197+
날짜를 선택하여 캠핑지를 확인하세요.
198+
</Typography>
185199
</div>
186200
) : (
187-
<div style={{ marginBottom: '40px' }}>
201+
<div style={{marginBottom: '40px'}}>
188202
{localAvailableSites.map((site, index) => (
189-
<div key={index} style={{ marginBottom: '20px' }}>
203+
<div key={index} style={{marginBottom: '20px'}}>
190204
<CampSiteCard
191205
locale={ko}
192206
campId={campId}
@@ -207,7 +221,7 @@ function CampDetail() {
207221
/>
208222
</div>
209223
<Box sx={{paddingTop: 4}}>
210-
<Typography gutterBottom sx={{fontSize: '1.8rem', fontWeight: "bold", marginBottom: '20px'}}>
224+
<Typography gutterBottom sx={{fontSize: '1.5rem', fontWeight: "bold", marginBottom: '20px'}}>
211225
후기
212226
</Typography>
213227
<ReviewList campId={campId}/>

0 commit comments

Comments
 (0)