Skip to content

Commit

Permalink
✨ Feat: ProjectPage studies, projects api 연동 (#51)
Browse files Browse the repository at this point in the history
Component 및 Hook 수정
1. useStudiesQuery, useProjectsQuery
2. useHandlePageNumber
3. PaginationButton

버그 수정
- 기술 선택, purpose(project or study),  검색어 입력시 pageNumber가 초기화되지 않는 문제

오타 수정
- TPaginationData 타입명 오타 수정
  • Loading branch information
cgh96 committed Aug 27, 2023
1 parent 787eda9 commit a17484e
Show file tree
Hide file tree
Showing 34 changed files with 770 additions and 135 deletions.
126 changes: 126 additions & 0 deletions src/components/common/button/pagination/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import { matchers } from "@emotion/jest";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { palette } from "styles/palette";

import PaginationButtons from ".";

expect.extend(matchers);
const mockHandleClickNextArrow = jest.fn();
const mockHandleClickPageNumber = jest.fn();
const mockHandleClickPrevArrow = jest.fn();
const mockHandleClickNextDblArrow = jest.fn();
const mockHandleClickPrevDblArrow = jest.fn();

afterEach(() => {
jest.clearAllMocks();
});

describe("pagination button 기능 test", () => {
it("prev, next, prevDbl, nextDbl 버튼 클릭 test", async () => {
const user = userEvent.setup();

render(
<PaginationButtons
totalPages={16}
currentPage={1}
handleClickPageNumber={mockHandleClickPageNumber}
handleClickNextArrow={mockHandleClickNextArrow}
handleClickPrevArrow={mockHandleClickPrevArrow}
handleClickPrevDblArrow={mockHandleClickPrevDblArrow}
handleClickNextDblArrow={mockHandleClickNextDblArrow}
/>,
);

const next = screen.getByTestId("next");
const dblNext = screen.getByTestId("dbl-next");
let prev = screen.queryByTestId("prev");
let dblPrev = screen.queryByTestId("dbl-prev");

expect(next).toBeInTheDocument();
expect(dblNext).toBeInTheDocument();
expect(prev).not.toBeInTheDocument();
expect(dblPrev).not.toBeInTheDocument();
await user.click(next);
await user.click(dblNext);
expect(mockHandleClickNextArrow).toHaveBeenCalled();
expect(mockHandleClickNextDblArrow).toHaveBeenCalled();

const pageButton = screen.getByRole("button", { name: "3" });
await user.click(pageButton);
expect(mockHandleClickPageNumber).toHaveBeenCalled();

jest.clearAllMocks();

render(
<PaginationButtons
totalPages={16}
currentPage={16}
handleClickPageNumber={mockHandleClickPageNumber}
handleClickNextArrow={mockHandleClickNextArrow}
handleClickPrevArrow={mockHandleClickPrevArrow}
handleClickPrevDblArrow={mockHandleClickPrevDblArrow}
handleClickNextDblArrow={mockHandleClickNextDblArrow}
/>,
);

prev = screen.getByTestId("prev");
dblPrev = screen.getByTestId("dbl-prev");
await user.click(prev);
await user.click(dblPrev);
expect(mockHandleClickPrevArrow).toHaveBeenCalled();
expect(mockHandleClickPrevDblArrow).toHaveBeenCalled();
});
it("totalPage에 0이 전달된 경우, 페이지는 1개가 생성된다.", () => {
render(
<PaginationButtons
totalPages={0}
currentPage={1}
handleClickPageNumber={mockHandleClickPageNumber}
handleClickNextArrow={mockHandleClickNextArrow}
handleClickPrevArrow={mockHandleClickPrevArrow}
handleClickPrevDblArrow={mockHandleClickPrevDblArrow}
handleClickNextDblArrow={mockHandleClickNextDblArrow}
/>,
);

const pageButton = screen.getByRole("button", { name: "1" });
expect(pageButton).toBeInTheDocument();
});

it("현재 페이지 번호를 표시하는 버튼의 색은 bgMainOrange이다.", () => {
render(
<PaginationButtons
totalPages={10}
currentPage={3}
handleClickPageNumber={mockHandleClickPageNumber}
handleClickNextArrow={mockHandleClickNextArrow}
handleClickPrevArrow={mockHandleClickPrevArrow}
handleClickPrevDblArrow={mockHandleClickPrevDblArrow}
handleClickNextDblArrow={mockHandleClickNextDblArrow}
/>,
);

const currentNumberBtn = screen.getByRole("button", { name: "3" });
expect(currentNumberBtn).toHaveStyleRule(
"background-color",
`${palette.bgMainOrange}`,
);
});
it("현재 페이지 번호가 아닌 버튼의 색은 transparent이다.", () => {
render(
<PaginationButtons
totalPages={10}
currentPage={3}
handleClickPageNumber={mockHandleClickPageNumber}
handleClickNextArrow={mockHandleClickNextArrow}
handleClickPrevArrow={mockHandleClickPrevArrow}
handleClickPrevDblArrow={mockHandleClickPrevDblArrow}
handleClickNextDblArrow={mockHandleClickNextDblArrow}
/>,
);

const currentNumberBtn = screen.getByRole("button", { name: "1" });
expect(currentNumberBtn).toHaveStyleRule("background-color", "transparent");
});
});
27 changes: 22 additions & 5 deletions src/components/common/button/pagination/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,21 +33,31 @@ const PaginationButtons: FC<IPaginationButtonsProps> = ({
handleClickPrevDblArrow,
handleClickNextDblArrow,
}) => {
totalPages = totalPages === 0 ? 1 : totalPages;

const pageNumberList = createPageNumberRenderingList(currentPage, totalPages);
const activePrevArrow = currentPage > 6;
const activeNextArrow = currentPage < Math.floor(totalPages / 6) * 6 + 1;

return (
<PaginationWrapper>
{activePrevArrow ? (
<PrevDblArrowBtn type="button" onClick={handleClickPrevDblArrow}>
<PrevDblArrowBtn
type="button"
onClick={handleClickPrevDblArrow}
data-testid="dbl-prev"
>
<DblArrowSVG />
</PrevDblArrowBtn>
) : (
<Blank aria-hidden="true" />
)}
{activePrevArrow ? (
<PrevArrowBtn type="button" onClick={handleClickPrevArrow}>
<PrevArrowBtn
type="button"
onClick={handleClickPrevArrow}
data-testid="prev"
>
<ArrowSVG width={36} color={`${palette.fontGray100}`} />
</PrevArrowBtn>
) : (
Expand All @@ -59,21 +69,28 @@ const PaginationButtons: FC<IPaginationButtonsProps> = ({
key={num}
isCurrentPage={currentPage === num}
onClick={() => handleClickPageNumber(Number(num))}
className={`${currentPage === num ? "activeBtn" : "non-activeBtn"}`}
>
{num}
</PageNumberBtn>
);
})}
{activeNextArrow ? (
<NextArrowBtn type="button" onClick={handleClickNextArrow}>
<NextArrowBtn
type="button"
onClick={handleClickNextArrow}
data-testid="next"
>
<ArrowSVG width={36} color={`${palette.fontGray100}`} />
</NextArrowBtn>
) : (
<Blank aria-hidden="true" />
)}
{activeNextArrow ? (
<NextDblArrowBtn type="button" onClick={handleClickNextDblArrow}>
<NextDblArrowBtn
type="button"
onClick={handleClickNextDblArrow}
data-testid="dbl-next"
>
<DblArrowSVG />
</NextDblArrowBtn>
) : (
Expand Down
6 changes: 4 additions & 2 deletions src/components/common/card/projects/index.styles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ export const Title = styled.h2`
-webkit-line-clamp: 2;
`;

export const Description = styled.p`
export const Description = styled.div`
height: 72px;
font-size: 1rem;
line-height: 1.5rem;
font-weight: 400;
Expand All @@ -53,7 +55,7 @@ export const Description = styled.p`
margin-bottom: 1.5rem;
img {
max-width: 100px;
display: none;
}
`;

Expand Down
13 changes: 9 additions & 4 deletions src/components/common/card/projects/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ const ProjectCard: FC<IProjectCardProps> = ({ contents }) => {
const skillSVGList = convertToSkillSVG(contents.skills);

return (
<Link href={`/projects/${contents.id}?purpose=${purposeParam}`}>
<Link
href={`/projects/${contents.id}?purpose=${purposeParam}`}
data-testid="projectCard"
>
<ClassificationTagWrapper>
<ClassificationTag bgColor={siteNameBgColor}>
{contents.siteType}
Expand All @@ -57,12 +60,14 @@ const ProjectCard: FC<IProjectCardProps> = ({ contents }) => {
{skillSVGList.length > 0 &&
skillSVGList
.slice(0, 7)
.map((e, i) => <Image key={i} src={e} alt="skill img" />)}
.map((e, i) => (
<Image key={i} src={e} alt={`${contents.skills[i]}`} />
))}
</SkillTagWrapper>
<InfoWrapper>
<PostsInfoWrapper>
<PostsInfo>댓글 5개</PostsInfo>
<PostsInfo>조회수 55회</PostsInfo>
{/**<PostsInfo>댓글 5개</PostsInfo>*/}
<PostsInfo>조회수 {contents.viewCount}</PostsInfo>
</PostsInfoWrapper>
<UserInfoWrapper>
<Image src={profileImg} alt="user Profile" />
Expand Down
27 changes: 27 additions & 0 deletions src/components/common/loading/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import styled from "@emotion/styled";

const Wrapper = styled.div`
position: relative;
width: 100%;
height: 100%;
`;

const Spinner = styled.div`
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 10rem;
`;

const Loading = () => {
return (
<Wrapper>
<Spinner>Loading...</Spinner>
</Wrapper>
);
};

export default Loading;
8 changes: 4 additions & 4 deletions src/components/home/projects/Hottest.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useComponentMount } from "lib/hooks/useComponentMount";
import useProjectsQuery from "lib/hooks/useProjectsQuery";
import useStudiesQuery from "lib/hooks/useStudiesQuery";
import { useProjectsQuery } from "lib/hooks/useProjectsQuery";
import { useStudiesQuery } from "lib/hooks/useStudiesQuery";
import type { TPostPreview } from "lib/types/post";

import ProjectCarousel from "./Carousel";
Expand All @@ -11,8 +11,8 @@ const HottestProjects = () => {
const [mount] = useComponentMount();
const contents: TPostPreview[] = [];

const { data: hottestProject } = useProjectsQuery(0, 3, "hotCount");
const { data: hottestStudy } = useStudiesQuery(0, 3, "hotCount");
const { data: hottestProject } = useProjectsQuery(0, 3, "hotCount", []);
const { data: hottestStudy } = useStudiesQuery(0, 3, "hotCount", []);

if (hottestProject && hottestStudy) {
contents.push(
Expand Down
8 changes: 4 additions & 4 deletions src/components/home/projects/Latest.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useComponentMount } from "lib/hooks/useComponentMount";
import useProjectsQuery from "lib/hooks/useProjectsQuery";
import useStudiesQuery from "lib/hooks/useStudiesQuery";
import { useProjectsQuery } from "lib/hooks/useProjectsQuery";
import { useStudiesQuery } from "lib/hooks/useStudiesQuery";
import type { TPostPreview } from "lib/types/post";

import ProjectCarousel from "./Carousel";
Expand All @@ -11,8 +11,8 @@ const LatestProjects = () => {
const [mount] = useComponentMount();
const contents: TPostPreview[] = [];

const { data: latestProject } = useProjectsQuery(0, 3, "id");
const { data: latestStudy } = useStudiesQuery(0, 3, "id");
const { data: latestProject } = useProjectsQuery(0, 3, "id", []);
const { data: latestStudy } = useStudiesQuery(0, 3, "id", []);

if (latestProject && latestStudy) {
contents.push(
Expand Down
10 changes: 8 additions & 2 deletions src/components/home/projects/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import ArrowSVG from "components/common/arrow";
import Loading from "components/common/loading";
import { H2, P, Section, ShowMore } from "components/home/index.styles";
import { Suspense } from "react";
import { palette } from "styles/palette";

import HottestProjects from "./Hottest";
Expand All @@ -16,8 +18,12 @@ const Projects = () => {
<ArrowSVG width={35} color={`${palette.fontGray300}`} />
</ShowMore>
</div>
<LatestProjects />
<HottestProjects />
<Suspense fallback={<Loading />}>
<LatestProjects />
</Suspense>
<Suspense fallback={<Loading />}>
<HottestProjects />
</Suspense>
</Section>
);
};
Expand Down
4 changes: 2 additions & 2 deletions src/components/home/projects/utils/pickHottestThree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ export const pickHottestThree = (...dataes: TPostPreview[]) => {
const bHotIdx = b.viewCount + b.scrapCount;

if (aHotIdx > bHotIdx) {
return 1;
} else {
return -1;
} else {
return +1;
}
})
.slice(0, 3);
Expand Down
4 changes: 2 additions & 2 deletions src/components/home/projects/utils/pickLatestThree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ export const pickLatestThree = (...dataes: TPostPreview[]) => {
const bDates = new Date(b.createdTime);

if (aDates > bDates) {
return 1;
} else {
return -1;
} else {
return +1;
}
})
.slice(0, 3);
Expand Down
16 changes: 16 additions & 0 deletions src/components/projects/Loading/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import styled from "@emotion/styled";
import { palette } from "styles/palette";

const EmptyBox = styled.div`
width: 100%;
height: 80vh;
background-color: ${palette.bgSubOrange};
border-radius: 1rem;
opacity: 0.7;
`;

const Loading = () => {
return <EmptyBox />;
};

export default Loading;
Loading

0 comments on commit a17484e

Please sign in to comment.