Skip to content

Commit

Permalink
Merge pull request #143 from KNU-HAEDAL/Design/#issue-135
Browse files Browse the repository at this point in the history
챌린지 상세 페이지, 챌린지 리뷰 페이지 UI 개선, 리팩토링 #135
  • Loading branch information
joojjang authored Sep 22, 2024
2 parents 06100a7 + 176ddf1 commit 46ae3a5
Show file tree
Hide file tree
Showing 13 changed files with 152 additions and 90 deletions.
40 changes: 22 additions & 18 deletions src/pages/challenge-detail/components/challenge/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,39 +38,43 @@ const Challenge = ({ challenge, maxDifficulty }: Props) => {

return (
<S.Outer>
<S.RowWrapper>
<S.Wrapper>
<S.BoldText>난이도</S.BoldText>
<S.SubText>최대 난이도</S.SubText>
</S.Wrapper>
<S.Wrapper>
<S.RowWrapper>
<S.Bar width={difficultyRate}></S.Bar>
<S.Text>{challenge.difficulty}</S.Text>
</S.RowWrapper>
<S.RowWrapper>
<S.MaxBar></S.MaxBar>
<S.SubText>{maxDifficulty}</S.SubText>
</S.RowWrapper>
</S.Wrapper>
</S.RowWrapper>
<S.Wrapper>
<S.RowWrapper>
<S.Wrapper>
<S.BoldText>난이도</S.BoldText>
<S.SubText>최대 난이도</S.SubText>
</S.Wrapper>
<S.Wrapper>
<S.RowWrapper>
<S.Bar width={difficultyRate}></S.Bar>
<S.Text>{challenge.difficulty}</S.Text>
</S.RowWrapper>
<S.RowWrapper>
<S.MaxBar></S.MaxBar>
<S.SubText>{maxDifficulty}</S.SubText>
</S.RowWrapper>
</S.Wrapper>
</S.RowWrapper>

<S.RowWrapper>
<S.BoldText>참여 횟수 및 기간</S.BoldText>
<S.Text>
{challenge.count}/{challenge.period}
{challenge.count} / {challenge.period}
</S.Text>
</S.RowWrapper>

<S.RowWrapper>
<S.BoldText>참여 경험치</S.BoldText>
<S.ExpContent>{challenge.onceExp} 포인트</S.ExpContent>
</S.RowWrapper>

<S.RowWrapper>
<S.BoldText>완료 경험치</S.BoldText>
<S.ExpContent>{challenge.successExp} 포인트</S.ExpContent>
</S.RowWrapper>
</S.Wrapper>
<S.Btn onClick={clickJoinChallenge}>참여하기</S.Btn>

<S.CTA onClick={clickJoinChallenge}>참여하기</S.CTA>
</S.Outer>
);
};
Expand Down
13 changes: 7 additions & 6 deletions src/pages/challenge-detail/components/challenge/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ export const Wrapper = styled.div`
display: flex;
flex-direction: column;
gap: 4px;
padding-bottom: 16px;
`;

export const RowWrapper = styled.div`
Expand Down Expand Up @@ -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;
`;
2 changes: 1 addition & 1 deletion src/pages/challenge-detail/description-section/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export const DescriptionSection = ({
<S.Text>{data.guide}</S.Text>
</S.ContentWrapper>

<Base.HorizontalLine margin={16} />
<Base.HorizontalLine marginY={16} marginX={16} />

<S.RowList>
{challenges.map((item) => (
Expand Down
1 change: 0 additions & 1 deletion src/pages/challenge-detail/description-section/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,5 @@ export const RowList = styled.div`
display: none;
}
gap: 16px;
margin: 0 0 3.44rem; // 하단 내브 바 높이
padding: 0 16px 16px;
`;
70 changes: 44 additions & 26 deletions src/pages/challenge-detail/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,18 @@ const ChallengeDetailPage = () => {
});
const [data, setData] = useState<ChallengeDetailData | undefined>(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: '설명',
Expand Down Expand Up @@ -66,33 +78,39 @@ const ChallengeDetailPage = () => {
}, [data?.title]);

return (
<S.Wrapper>
<TopBar type='Page' title={'챌린지 상세정보'} backgroundColor='#fff' />
<S.ImageMask>
{data?.imageUrls?.length ? (
data.imageUrls.map((img, index) => <S.Image key={index} src={img} />)
) : (
<S.Image src={DefaultImage} />
)}
</S.ImageMask>
<S.ChallengeTitleWrapper>
<S.Category>{data?.category}</S.Category>
<S.Title>{data?.title}</S.Title>
</S.ChallengeTitleWrapper>
<>
<TopBar type='Page' title={'챌린지 상세 정보'} backgroundColor='#fff' />
<S.Wrapper>
<S.ImageList>
{data?.imageUrls?.length ? (
data.imageUrls.map((img, index) => (
<S.Image key={index} src={img} />
))
) : (
<S.DefaultImageMask>
<S.DefaultImage src={DefaultImage} />
</S.DefaultImageMask>
)}
</S.ImageList>
<S.ChallengeTitleWrapper>
<S.Category>{categoryLabel}</S.Category>
<S.Title>{data?.title}</S.Title>
</S.ChallengeTitleWrapper>

<Tabs selectedTab={activeTab} onChange={handleSelectedTab}>
{tabsList.map((t, index) => (
<Tab key={t.label} label={t.label} value={index} />
))}
</Tabs>
<TabPanels>
{tabsList.map((t, index) => (
<TabPanel key={index} value={activeTab} selectedIndex={index}>
{t.panel ?? undefined}
</TabPanel>
))}
</TabPanels>
</S.Wrapper>
<Tabs selectedTab={activeTab} onChange={handleSelectedTab}>
{tabsList.map((t, index) => (
<Tab key={t.label} label={t.label} value={index} />
))}
</Tabs>
<TabPanels>
{tabsList.map((t, index) => (
<TabPanel key={index} value={activeTab} selectedIndex={index}>
{t.panel ?? undefined}
</TabPanel>
))}
</TabPanels>
</S.Wrapper>
</>
);
};

Expand Down
2 changes: 1 addition & 1 deletion src/pages/challenge-detail/ranking-section/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export const RankingSection = ({ id }: RankingSectionProps) => {
<div key={item.ranking}>
<RankingItem item={item} />
{index < rankingList.length - 1 && (
<Base.HorizontalLine margin={8} />
<Base.HorizontalLine marginY={8} />
)}
{/* 마지막 요소 뒤에는 Line을 넣지 않음 */}
</div>
Expand Down
1 change: 0 additions & 1 deletion src/pages/challenge-detail/ranking-section/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
`;
17 changes: 10 additions & 7 deletions src/pages/challenge-detail/review-section/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,25 @@ export const ReviewSection = ({ id }: Props) => {
const DATA_SIZE = 5; // 가져올 리뷰 개수
const [reviewList, setReviewList] = useState<ReviewData[]>([]);
const [avgRating, setAvgRating] = useState<number | undefined>();
const [totalRatings, setTotalRatings] = useState(0); // 별점(리뷰) 개수
const [formattedAvgRating, setFormattedAvgRating] = useState<string>('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);
Expand All @@ -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('리뷰 데이터 없음');
}
Expand All @@ -58,20 +61,20 @@ export const ReviewSection = ({ id }: Props) => {
// 리뷰 있을 때
<>
<S.RatingContainer className='RatingContainer'>
<S.AvgRating>{avgRating}</S.AvgRating>
<S.AvgRating>{formattedAvgRating}</S.AvgRating>
{avgRating && <StarRating rating={avgRating} />}
<S.AllReviewButton
onClick={() => navigate(`/challenge/${id}/review`)}
>
{totalRatings}개 모두 보기{' '}
{formattedTotalRatings}개 모두 보기{' '}
<IoIosArrowForward style={{ marginLeft: '4px' }} />
</S.AllReviewButton>
</S.RatingContainer>
{reviewList.map((review, index) => (
<div key={index}>
<ReviewItem item={review} />
{index < reviewList.length - 1 && (
<Base.HorizontalLine margin={8} />
<Base.HorizontalLine marginY={8} />
)}
{/* 마지막 요소 뒤에는 Line을 넣지 않음 */}
</div>
Expand Down
1 change: 0 additions & 1 deletion src/pages/challenge-detail/review-section/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
34 changes: 27 additions & 7 deletions src/pages/challenge-detail/styles.ts
Original file line number Diff line number Diff line change
@@ -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`
Expand Down
23 changes: 16 additions & 7 deletions src/pages/review/components/review-rating/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,27 @@ const ReviewRating = ({ challengeGroupId }: ReviewDataProps) => {
2: 0,
1: 0,
});
const [avgRating, setAvgRating] = useState(0);
const [avgRating, setAvgRating] = useState<number>(0);
const [formattedAvgRating, setFormattedAvgRating] = useState<string>('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]);

Expand All @@ -42,10 +49,14 @@ const ReviewRating = ({ challengeGroupId }: ReviewDataProps) => {

return (
<Wrapper>
<Text fontSize='var(--font-size-md)'>
<strong>{formattedTotalRatings || 0}</strong>개의 리뷰
</Text>

<RatingBox>
<AvgRatingWrapper style={{ alignItems: 'center' }}>
<Text fontSize='var(--font-size-xxl)' fontWeight='600'>
{avgRating}
{formattedAvgRating}
</Text>
<StarRating rating={avgRating} size={20} />
</AvgRatingWrapper>
Expand Down Expand Up @@ -79,8 +90,6 @@ const ReviewRating = ({ challengeGroupId }: ReviewDataProps) => {
))}
</RatingGraphWrapper>
</RatingBox>

<Text fontSize='var(--font-size-sm)'>{totalRatings}개의 리뷰</Text>
</Wrapper>
);
};
Expand All @@ -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;
`;
Expand Down
Loading

0 comments on commit 46ae3a5

Please sign in to comment.