Skip to content

Commit

Permalink
Merge pull request #21 from DS-UMC-7th/feature/#3-review
Browse files Browse the repository at this point in the history
feat: 필터링, 페이지네이션 추가
  • Loading branch information
seunghyeonKang authored Dec 6, 2024
2 parents 5bd88c8 + c977eda commit 06df09d
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 59 deletions.
21 changes: 0 additions & 21 deletions review/src/components/main/LatestReviews.jsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,11 @@
import { useEffect } from "react";
import { useNavigate } from "react-router-dom";
import styled from "styled-components";
import axios from "axios";
import ReviewList from "../review/review-all/ReviewList";
import more from "../../assets/image/arrow.png";

export default function LatestReviews() {
const navigate = useNavigate();

// api 연결
const api = axios.create({
baseURL: "http://3.38.66.123:3000",
});

async function getReviewsLatest() {
try {
const response = await api.get("/reviews/latest");

console.log("메인: ", response.data.result.reviews); // 로그인 성공
// console.log(response.data.message); // 로그인 성공
} catch (error) {
console.error("로그인 실패:", error.response?.data || error.message);
}
}
useEffect(() => {
getReviewsLatest();
}, []);

const handleArrowClick = () => {
navigate("/review/list");
};
Expand Down
70 changes: 57 additions & 13 deletions review/src/components/review/review-detail/FilterComp.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,40 @@ import * as S from "./ReviewDetail.style";
import DropdownDownSvg from "../../../assets/icon/dropdown-down-14x8.svg";
import DropdownUpSvg from "../../../assets/icon/dropdown-up-14x8.svg";
import CheckSvg from "../../../assets/icon/check-11x10.svg";
import StarPng from "../../../assets/icon/star-filled-25x26.png";

export default function FilterComp({ dropdownTitle, btnWidth }) {
export default function FilterComp({
ratingCount,
isChecked,
setIsChecked,
dropdownTitle,
btnWidth,
}) {
const [isSelected, setIsSelected] = useState(false);

// 추천순|최신순 정렬
const handleClickBtn = () => {
setIsSelected(!isSelected);
};

// 별 필터
const handleCheck = (num) => {
setIsChecked((prevData) => ({
...prevData,
[num]: !isChecked[num],
}));
};
const handleCheckAll = (num) => {
setIsChecked({
[1]: !isChecked[num],
[2]: !isChecked[num],
[3]: !isChecked[num],
[4]: !isChecked[num],
[5]: !isChecked[num],
[6]: !isChecked[num],
});
};

return (
<>
<S.DropdownContainer>
Expand All @@ -22,21 +48,39 @@ export default function FilterComp({ dropdownTitle, btnWidth }) {
{/* 목록 */}
{isSelected && (
<S.CheckListContainer $width={btnWidth}>
<S.CheckItem>
입문자
<S.CheckBox $isChecked={true} $imgUrl={CheckSvg}></S.CheckBox>
<S.CheckItem onClick={() => handleCheckAll(6)}>
전체
<S.CheckBox $isChecked={isChecked[6]} $imgUrl={CheckSvg}></S.CheckBox>
</S.CheckItem>

<S.CheckItem onClick={() => handleCheck(5)}>
<S.StarIcon src={StarPng}></S.StarIcon>
5({ratingCount[5]})
<S.CheckBox $isChecked={isChecked[5]} $imgUrl={CheckSvg}></S.CheckBox>
</S.CheckItem>
<S.CheckItem>
초급자
<S.CheckBox $isChecked={false} $imgUrl={CheckSvg}></S.CheckBox>

<S.CheckItem onClick={() => handleCheck(4)}>
<S.StarIcon src={StarPng}></S.StarIcon>
4({ratingCount[4]})
<S.CheckBox $isChecked={isChecked[4]} $imgUrl={CheckSvg}></S.CheckBox>
</S.CheckItem>
<S.CheckItem>
중급자
<S.CheckBox $isChecked={false} $imgUrl={CheckSvg}></S.CheckBox>

<S.CheckItem onClick={() => handleCheck(3)}>
<S.StarIcon src={StarPng}></S.StarIcon>
3({ratingCount[3]})
<S.CheckBox $isChecked={isChecked[3]} $imgUrl={CheckSvg}></S.CheckBox>
</S.CheckItem>
<S.CheckItem>
상급자
<S.CheckBox $isChecked={false} $imgUrl={CheckSvg}></S.CheckBox>

<S.CheckItem onClick={() => handleCheck(2)}>
<S.StarIcon src={StarPng}></S.StarIcon>
2({ratingCount[2]})
<S.CheckBox $isChecked={isChecked[2]} $imgUrl={CheckSvg}></S.CheckBox>
</S.CheckItem>

<S.CheckItem onClick={() => handleCheck(1)}>
<S.StarIcon src={StarPng}></S.StarIcon>
1({ratingCount[1]})
<S.CheckBox $isChecked={isChecked[1]} $imgUrl={CheckSvg}></S.CheckBox>
</S.CheckItem>
</S.CheckListContainer>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,11 @@ export const CheckBox = styled.div`
background-repeat: no-repeat;
background-position: center;
`;
export const StarIcon = styled.img`
margin-right: -1rem;
width: 1.5rem;
height: 1.4rem;
`;
// ReviewFilter - 추천순/최신순
export const AlignText = styled.p`
margin-left: 0.5rem;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import StarOnPng from "../../../assets/icon/star-filled-25x26.png";
import StarOffPng from "../../../assets/icon/star-empty-25x26.png";
import LikeSvg from "../../../assets/icon/like-25x24.svg";
import axios from "axios";
import { useState } from "react";

export default function ReviewDetailCard({
reviewId,
Expand All @@ -12,23 +13,25 @@ export default function ReviewDetailCard({
reviewtTerm,
reviewContent,
}) {
const [reviewLikeNumState, setReviewLikeNumState] = useState(reviewLikeNum);
// api 연결
const api = axios.create({
baseURL: "http://3.38.66.123:3000",
});

async function postReviewRecommend() {
try {
const response = await api.get(`/comments/${reviewId}/recommend`);
const response = await api.post(`/comments/${reviewId}/recommend`);

console.log("따봉: ", response.data); // 성공
// console.log("따봉: ", response.data); // 성공
} catch (error) {
console.error("따봉 실패:", error.response?.data || error.message);
}
}

const handleRecommendBtn = () => {
postReviewRecommend();
setReviewLikeNumState((prev) => prev + 1);
};

return (
Expand All @@ -45,7 +48,7 @@ export default function ReviewDetailCard({
</S.ReviewStarList2>
<S.LikeBtn onClick={handleRecommendBtn}>
<S.LikeImg src={LikeSvg} alt="따봉" />
{reviewLikeNum}
{reviewLikeNumState}
</S.LikeBtn>
</S.ContainerBetween>
<S.ContainerStart>
Expand Down
17 changes: 15 additions & 2 deletions review/src/components/review/review-detail/ReviewDetailFilter.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import * as S from "./ReviewDetail.style";
import FilterComp from "./FilterComp";

export default function ReviewDetailFilter({ alignSelected, setAlignSelected }) {
export default function ReviewDetailFilter({
ratingCount,
isFilterChecked,
setIsFilterChecked,
alignSelected,
setAlignSelected,
}) {
const handleClickAlignBtn = (num) => {
setAlignSelected(num);
};
Expand All @@ -10,8 +16,15 @@ export default function ReviewDetailFilter({ alignSelected, setAlignSelected })
<>
<S.ReviewFilterContainer>
<S.FlexContainer>
<FilterComp dropdownTitle="전체" btnWidth="11.2rem" />
<FilterComp
ratingCount={ratingCount}
isChecked={isFilterChecked}
setIsChecked={setIsFilterChecked}
dropdownTitle="전체"
btnWidth="11.2rem"
/>
</S.FlexContainer>

<S.FlexContainer>
<S.AlignText onClick={() => handleClickAlignBtn(1)} $isSelected={alignSelected === 1}>
추천순
Expand Down
78 changes: 59 additions & 19 deletions review/src/components/review/review-detail/ReviewDetailList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,20 @@ import ArrowLeftSvg from "../../../assets/icon/arrow-left-10x16.svg";
import ArrowRightSvg from "../../../assets/icon/arrow-right-10x16.svg";

export default function ReviewDetailList() {
const [pageSelected, setPageSelected] = useState(1);
const [isFilterChecked, setIsFilterChecked] = useState({
6: true,
5: true,
4: true,
3: true,
2: true,
1: true,
});
const [ratingCount, setRatingCount] = useState({ 1: 0, 2: 0, 3: 0, 4: 0, 5: 0 });
const [reviewArray, setReviewArray] = useState(1);
const [reviewList, setReviewList] = useState([]);
const [reviewList1, setReviewList1] = useState([]);
const [reviewList2, setReviewList2] = useState([]);
const [reviewList, setReviewList] = useState({ reviews: [], totalPages: 0 });
const [reviewList1, setReviewList1] = useState({ reviews: [], totalPages: 0 });
const [reviewList2, setReviewList2] = useState({ reviews: [], totalPages: 0 });

// api 연결
const api = axios.create({
Expand All @@ -22,12 +32,13 @@ export default function ReviewDetailList() {
try {
const response = await api.get("/lectures/1/reviews/recommended", {
params: {
limit: 10,
page: pageNum,
},
});

await setReviewList1(response.data.result.reviews);
console.log("추천순: ", response.data.result); // 성공
await setReviewList1(response.data.result);
// console.log("추천순: ", response.data.result); // 성공
} catch (error) {
console.error("추천순 실패:", error.response?.data || error.message);
}
Expand All @@ -36,21 +47,22 @@ export default function ReviewDetailList() {
try {
const response = await api.get("/lectures/1/reviews/latest", {
params: {
limit: 10,
page: pageNum,
},
});

await setReviewList2(response.data.result.reviews);
console.log("최신순: ", response.data.result); // 성공
await setReviewList2(response.data.result);
// console.log("최신순: ", response.data.result); // 성공
} catch (error) {
console.error("최신순 실패:", error.response?.data || error.message);
}
}

useEffect(() => {
getReviewsRecommended({ pageNum: 1 });
getReviewsLatest({ pageNum: 1 });
}, []);
getReviewsRecommended({ pageNum: pageSelected });
getReviewsLatest({ pageNum: pageSelected });
}, [pageSelected]);
useEffect(() => {
if (reviewArray === 1) {
setReviewList(reviewList1);
Expand All @@ -59,15 +71,26 @@ export default function ReviewDetailList() {
}
}, [reviewArray, reviewList1, reviewList2]);

// 리뷰 필터링
const filteredReviews = reviewList.reviews.filter((review) => {
return isFilterChecked[review.rating];
});

return (
<>
{/* 별점 통계 */}
<ReviewDetailRating />
<ReviewDetailRating setRatingCount={setRatingCount} />
{/* 필터링 드롭다운&추천순|최신순 */}
<ReviewDetailFilter alignSelected={reviewArray} setAlignSelected={setReviewArray} />
<ReviewDetailFilter
ratingCount={ratingCount}
isFilterChecked={isFilterChecked}
setIsFilterChecked={setIsFilterChecked}
alignSelected={reviewArray}
setAlignSelected={setReviewArray}
/>
{/* 맵함수 */}
<S.ReviewList>
{reviewList.map((data) => (
{filteredReviews.map((data) => (
<>
<ReviewDetailCard
key={data.reviewId}
Expand All @@ -83,12 +106,29 @@ export default function ReviewDetailList() {
</S.ReviewList>

<S.PagenationContainer>
<S.ArrowImg src={ArrowLeftSvg} alt="이전 페이지" />
<S.PageNum $isSelected={true}>1</S.PageNum>
<S.PageNum $isSelected={false}>2</S.PageNum>
<S.PageNum $isSelected={false}>3</S.PageNum>
<S.PageNum $isSelected={false}>4</S.PageNum>
<S.ArrowImg src={ArrowRightSvg} alt="다음 페이지" />
<S.ArrowImg
onClick={() => setPageSelected(pageSelected !== 1 ? pageSelected - 1 : 1)}
src={ArrowLeftSvg}
alt="이전 페이지"
/>

{Array.from({ length: reviewList.totalPages }, (_, index) => (
<S.PageNum
key={index + 1}
$isSelected={index + 1 === pageSelected}
onClick={() => setPageSelected(index + 1)}
>
{index + 1}
</S.PageNum>
))}

<S.ArrowImg
onClick={() =>
setPageSelected(reviewList.totalPages !== pageSelected ? pageSelected + 1 : 3)
}
src={ArrowRightSvg}
alt="다음 페이지"
/>
</S.PagenationContainer>
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import * as S from "./ReviewDetail.style";
import StarOnPng from "../../../assets/icon/star-filled-25x26.png";
import StarOffPng from "../../../assets/icon/star-empty-25x26.png";

export default function ReviewDetailRating() {
export default function ReviewDetailRating({ setRatingCount }) {
const navigate = useNavigate();
const [ratingData, setRatingData] = useState({
averageRating: 0,
Expand Down Expand Up @@ -35,6 +35,7 @@ export default function ReviewDetailRating() {
totalReview: response.data.result.totalReview,
ratingCount: response.data.result.ratingCount,
}));
setRatingCount(response.data.result.ratingCount);
// console.log("별점 통계 조회: ", response.data.result); // 성공
} catch (error) {
console.error("별점 통계 조회 실패:", error.response?.data || error.message);
Expand Down

0 comments on commit 06df09d

Please sign in to comment.