diff --git a/src/pages/challenge-detail/components/challenge/index.tsx b/src/pages/challenge-detail/components/challenge/index.tsx index 7ab5527..af8821b 100644 --- a/src/pages/challenge-detail/components/challenge/index.tsx +++ b/src/pages/challenge-detail/components/challenge/index.tsx @@ -38,39 +38,43 @@ const Challenge = ({ challenge, maxDifficulty }: Props) => { return ( - - - 난이도 - 최대 난이도 - - - - - {challenge.difficulty} - - - - {maxDifficulty} - - - + + + 난이도 + 최대 난이도 + + + + + {challenge.difficulty} + + + + {maxDifficulty} + + + + 참여 횟수 및 기간 - {challenge.count}회/{challenge.period}일 + {challenge.count}회 / {challenge.period}일 + 참여 경험치 {challenge.onceExp} 포인트 + 완료 경험치 {challenge.successExp} 포인트 - 참여하기 + + 참여하기 ); }; diff --git a/src/pages/challenge-detail/components/challenge/styles.ts b/src/pages/challenge-detail/components/challenge/styles.ts index 4bc366a..5ba9bb7 100644 --- a/src/pages/challenge-detail/components/challenge/styles.ts +++ b/src/pages/challenge-detail/components/challenge/styles.ts @@ -11,7 +11,6 @@ export const Wrapper = styled.div` display: flex; flex-direction: column; gap: 4px; - padding-bottom: 16px; `; export const RowWrapper = styled.div` @@ -65,13 +64,15 @@ export const ExpContent = styled.div` padding: 2px 6px; `; -export const Btn = styled.button` - border-radius: 20px; +export const CTA = styled.button` + width: calc(100% - 16px); // 부모 요소의 좌우 padding 빼고 + padding: 10px 8px; + margin: auto; + border-radius: 10px; background-color: var(--color-green-01); color: var(--color-white); font-weight: bold; font-size: var(--font-size-md); - width: 100%; - height: 45px; - border: none; + + margin-top: 16px; `; diff --git a/src/pages/challenge-detail/description-section/index.tsx b/src/pages/challenge-detail/description-section/index.tsx index 17b2de4..8a15342 100644 --- a/src/pages/challenge-detail/description-section/index.tsx +++ b/src/pages/challenge-detail/description-section/index.tsx @@ -32,7 +32,7 @@ export const DescriptionSection = ({ {data.guide} - + {challenges.map((item) => ( diff --git a/src/pages/challenge-detail/description-section/styles.ts b/src/pages/challenge-detail/description-section/styles.ts index 6b8cfb6..f8cc19f 100644 --- a/src/pages/challenge-detail/description-section/styles.ts +++ b/src/pages/challenge-detail/description-section/styles.ts @@ -53,6 +53,5 @@ export const RowList = styled.div` display: none; } gap: 16px; - margin: 0 0 3.44rem; // 하단 내브 바 높이 padding: 0 16px 16px; `; diff --git a/src/pages/challenge-detail/index.tsx b/src/pages/challenge-detail/index.tsx index 346baaf..ade7368 100644 --- a/src/pages/challenge-detail/index.tsx +++ b/src/pages/challenge-detail/index.tsx @@ -25,6 +25,18 @@ const ChallengeDetailPage = () => { }); const [data, setData] = useState(undefined); + const categoryList = [ + { label: '건강', data: 'HEALTH' }, + { label: '에코', data: 'ECHO' }, + { label: '나눔', data: 'SHARE' }, + { label: '봉사', data: 'VOLUNTEER' }, + { label: '기타', data: 'ETC' }, + ]; + + // data.category에 맞는 label 찾기 + const categoryLabel = + categoryList.find((c) => c.data === data?.category)?.label || ''; + const tabsList = [ { label: '설명', @@ -66,33 +78,39 @@ const ChallengeDetailPage = () => { }, [data?.title]); return ( - - - - {data?.imageUrls?.length ? ( - data.imageUrls.map((img, index) => ) - ) : ( - - )} - - - {data?.category} - {data?.title} - + <> + + + + {data?.imageUrls?.length ? ( + data.imageUrls.map((img, index) => ( + + )) + ) : ( + + + + )} + + + {categoryLabel} + {data?.title} + - - {tabsList.map((t, index) => ( - - ))} - - - {tabsList.map((t, index) => ( - - {t.panel ?? undefined} - - ))} - - + + {tabsList.map((t, index) => ( + + ))} + + + {tabsList.map((t, index) => ( + + {t.panel ?? undefined} + + ))} + + + ); }; diff --git a/src/pages/challenge-detail/ranking-section/index.tsx b/src/pages/challenge-detail/ranking-section/index.tsx index 35505d8..90bdcb6 100644 --- a/src/pages/challenge-detail/ranking-section/index.tsx +++ b/src/pages/challenge-detail/ranking-section/index.tsx @@ -59,7 +59,7 @@ export const RankingSection = ({ id }: RankingSectionProps) => {
{index < rankingList.length - 1 && ( - + )} {/* 마지막 요소 뒤에는 Line을 넣지 않음 */}
diff --git a/src/pages/challenge-detail/ranking-section/styles.ts b/src/pages/challenge-detail/ranking-section/styles.ts index b80b4a5..18e486c 100644 --- a/src/pages/challenge-detail/ranking-section/styles.ts +++ b/src/pages/challenge-detail/ranking-section/styles.ts @@ -8,7 +8,6 @@ export const Text = styled.span<{ fontWeight?: string; color?: string }>` export const RankingWrapper = styled.div` padding: 16px 16px; - margin: 0 0 3.44rem; // 하단 내브 바 높이 display: flex; flex-direction: column; `; diff --git a/src/pages/challenge-detail/review-section/index.tsx b/src/pages/challenge-detail/review-section/index.tsx index e6497fd..0737e31 100644 --- a/src/pages/challenge-detail/review-section/index.tsx +++ b/src/pages/challenge-detail/review-section/index.tsx @@ -17,21 +17,25 @@ export const ReviewSection = ({ id }: Props) => { const DATA_SIZE = 5; // 가져올 리뷰 개수 const [reviewList, setReviewList] = useState([]); const [avgRating, setAvgRating] = useState(); - const [totalRatings, setTotalRatings] = useState(0); // 별점(리뷰) 개수 + const [formattedAvgRating, setFormattedAvgRating] = useState('0.0'); // 소수점 한 자리까지 포맷팅된 별점 평균 + const [formattedTotalRatings, setFormattedTotalRatings] = useState(''); // 쉼표 포맷팅된 별점(리뷰) 개수 const navigate = useNavigate(); useEffect(() => { // 평균 별점 가져오기 getChallegeAvgScore({ challengeGroupId: id }) .then((res) => { - setAvgRating(Number(res.averageRating.toFixed(1))); // 소수점 아래 한 자리 + // 별점 평균 저장 + const average = Number(res.averageRating.toFixed(1)); // 소수점 아래 한 자리까지 + setAvgRating(average); + setFormattedAvgRating(average.toFixed(1)); // 소수점 한 자리까지 나오게 포맷팅 // 모든 별점 개수 합 구하기 const total = Object.values(res.ratingCount).reduce( (acc, value) => acc + value, 0 ); - setTotalRatings(total); + setFormattedTotalRatings(total.toLocaleString()); // 쉼포 포맷팅하여 저장 }) .catch((error) => { console.error('Error fetching average score:', error); @@ -42,7 +46,6 @@ export const ReviewSection = ({ id }: Props) => { .then((res) => { if (Array.isArray(res.data) && res.data.length > 0) { setReviewList((prevReviewList) => [...prevReviewList, ...res.data]); - // console.log(`리뷰 리스트: `, reviewList); // test } else { console.log('리뷰 데이터 없음'); } @@ -58,12 +61,12 @@ export const ReviewSection = ({ id }: Props) => { // 리뷰 있을 때 <> - {avgRating} + {formattedAvgRating} {avgRating && } navigate(`/challenge/${id}/review`)} > - {totalRatings}개 모두 보기{' '} + {formattedTotalRatings}개 모두 보기{' '} @@ -71,7 +74,7 @@ export const ReviewSection = ({ id }: Props) => {
{index < reviewList.length - 1 && ( - + )} {/* 마지막 요소 뒤에는 Line을 넣지 않음 */}
diff --git a/src/pages/challenge-detail/review-section/styles.ts b/src/pages/challenge-detail/review-section/styles.ts index ea3c2b5..5dfa24f 100644 --- a/src/pages/challenge-detail/review-section/styles.ts +++ b/src/pages/challenge-detail/review-section/styles.ts @@ -17,7 +17,6 @@ export const Text = styled.span<{ fontWeight?: string; color?: string }>` export const Wrapper = styled.div` padding: 16px 16px; - margin: 0 0 3.44rem; // 하단 내브 바 높이 display: flex; flex-direction: column; height: auto; diff --git a/src/pages/challenge-detail/styles.ts b/src/pages/challenge-detail/styles.ts index 1f7c8fa..4a701b0 100644 --- a/src/pages/challenge-detail/styles.ts +++ b/src/pages/challenge-detail/styles.ts @@ -1,21 +1,41 @@ import styled from '@emotion/styled'; -export const Wrapper = styled.div``; +export const Wrapper = styled.div` + width: 100%; + margin-bottom: 3.44rem; // 하단 내브 바 높이 +`; -export const ImageMask = styled.div` - background-color: var(--color-green-06); - position: relative; +export const ImageList = styled.div` margin: 0 0 16px; + height: 100vw; + max-height: 480px; // 최대 너비가 480px라서 고정값으로 설정한 것임 + display: flex; + overflow-x: scroll; `; export const Image = styled.img` position: relative; margin: auto; + align-self: center; + display: block; + object-fit: cover; + width: 100%; +`; + +export const DefaultImageMask = styled.div` + background-color: var(--color-green-06); + position: relative; + width: 100vw; + display: flex; +`; + +export const DefaultImage = styled.img` + position: relative; + margin: auto; + align-self: center; display: block; - height: 40%; - opacity: 20%; object-fit: cover; - filter: grayscale(100%); + opacity: 50%; `; export const ChallengeTitleWrapper = styled.div` diff --git a/src/pages/review/components/review-rating/index.tsx b/src/pages/review/components/review-rating/index.tsx index 5f1e275..54b7306 100644 --- a/src/pages/review/components/review-rating/index.tsx +++ b/src/pages/review/components/review-rating/index.tsx @@ -18,20 +18,27 @@ const ReviewRating = ({ challengeGroupId }: ReviewDataProps) => { 2: 0, 1: 0, }); - const [avgRating, setAvgRating] = useState(0); + const [avgRating, setAvgRating] = useState(0); + const [formattedAvgRating, setFormattedAvgRating] = useState('0.0'); // 소수점 한 자리까지 포맷팅된 별점 평균 const [totalRatings, setTotalRatings] = useState(0); // 별점(리뷰) 개수 + const [formattedTotalRatings, setFormattedTotalRatings] = useState(''); // 쉼표 포맷팅된 별점(리뷰) 개수 useEffect(() => { getChallegeAvgScore({ challengeGroupId: challengeGroupId }).then((res) => { setRatingCount(res.ratingCount); - setAvgRating(Number(res.averageRating.toFixed(1))); // 소수점 아래 한 자리 - // 모든 별점 개수 합 구하기 + // 별점 평균 저장 + const average = Number(res.averageRating.toFixed(1)); // 소수점 아래 한 자리까지 + setAvgRating(average); + setFormattedAvgRating(average.toFixed(1)); // 소수점 한 자리까지 나오게 포맷팅 + + // 모든 별점 개수 합 구하여 저장 const total = Object.values(res.ratingCount).reduce( (acc, value) => acc + value, 0 ); setTotalRatings(total); + setFormattedTotalRatings(total.toLocaleString()); // 쉼표 포맷팅하여 저장 }); }, [challengeGroupId]); @@ -42,10 +49,14 @@ const ReviewRating = ({ challengeGroupId }: ReviewDataProps) => { return ( + + {formattedTotalRatings || 0}개의 리뷰 + + - {avgRating} + {formattedAvgRating} @@ -79,8 +90,6 @@ const ReviewRating = ({ challengeGroupId }: ReviewDataProps) => { ))} - - {totalRatings}개의 리뷰 ); }; @@ -90,7 +99,7 @@ export default ReviewRating; const Wrapper = styled(Box)` display: flex; flex-direction: column; - align-items: flex-end; + align-items: flex-start; margin: 0 16px; gap: 8px; `; diff --git a/src/pages/review/index.tsx b/src/pages/review/index.tsx index 361cf49..de4339c 100644 --- a/src/pages/review/index.tsx +++ b/src/pages/review/index.tsx @@ -63,7 +63,7 @@ const Review = () => {
{index < reviewList.length - 1 && ( - + )} {/* 마지막 요소 뒤에는 Line을 넣지 않음 */}
@@ -71,15 +71,17 @@ const Review = () => { ) : ( // 리뷰 없을 때 - - 아직 리뷰가 없습니다. -
- 챌린지를 완료하고{' '} - - 첫 번째 리뷰어 + + + 아직 리뷰가 없습니다. +
+ 챌린지를 완료하고{' '} + + 첫 번째 리뷰어 + + 가 되어보세요!
- 가 되어보세요! -
+ )} {isFetching ? '로딩 중...' : ' '} @@ -100,6 +102,7 @@ const Wrapper = styled.div` display: flex; flex-direction: column; text-align: center; + margin-bottom: 3.44rem; `; const Title = styled.div` @@ -114,5 +117,9 @@ const ReviewList = styled.div` display: flex; flex-direction: column; padding: 16px 0; - margin: 0 16px 3.44rem 16px; + margin: 0 16px 0 16px; +`; + +const EmptyState = styled.div` + padding: 16px 16px; `; diff --git a/src/styles/baseStyles.ts b/src/styles/baseStyles.ts index 5d7fa15..bca6a1d 100644 --- a/src/styles/baseStyles.ts +++ b/src/styles/baseStyles.ts @@ -109,16 +109,19 @@ export const TextItem = styled.div<{ fontWeight?: string; color: string }>` line-height: normal; `; -export const HorizontalLine = styled.div<{ margin?: number }>` +export const HorizontalLine = styled.div<{ + marginX?: number; + marginY?: number; +}>` border-top: 1px solid var(--color-green-06); - margin: ${({ margin }) => margin && `${margin}px 0`}; + margin: ${({ marginX = 0, marginY = 0 }) => `${marginY}px ${marginX}px`}; `; -export const VerticalLine = styled.div<{ margin?: number }>` +export const VerticalLine = styled.div<{ marginX?: number; marginY?: number }>` border: 1px solid var(--color-green-06); /* flex: 1; */ height: 100px; // 수정 필요 - margin: ${({ margin }) => margin && `0 ${margin}px`}; + margin: ${({ marginX = 0, marginY = 0 }) => `${marginY}px ${marginX}px`}; `; // export const TeerTotal = styled.div`