Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion components/Link/LinkCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useEffect, useState } from "react";
import { useRouter } from "next/router";
import { putLinkFavorite } from "@/lib/api/link";
import { useLinkCardStore } from "@/store/useLinkCardStore";
import { ensureAbsoluteUrl } from "@/lib/utils";
import timeAgo from "@/util/timAgo";
import Image from "next/image";
import Dropdown from "../Dropdown";
Expand Down Expand Up @@ -73,7 +74,7 @@ const LinkCard = ({ info }: LinkCardProps) => {
<div className="w-[340px] h-[344px] rounded-[12px] shadow-lg overflow-hidden cursor-pointer hover:scale-105 hover:duration-300">
<section className="relative w-full h-[60%]">
<Image
src={info.imageSource || `/images/no-content.svg`}
src={ensureAbsoluteUrl(info.imageSource) || `/images/no-content.svg`}
className="object-cover"
alt="링크 미리보기"
fill
Expand Down
71 changes: 42 additions & 29 deletions components/Pagination.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import useViewport from "@/hooks/useViewport";
import Image from "next/image";
import Link from "next/link";
import { useRouter } from "next/router";
import { useEffect, useState } from "react";

Expand All @@ -8,31 +8,42 @@ interface PaginationProps {
}

const Pagination: React.FC<PaginationProps> = ({ totalCount }) => {
const router = useRouter();
const LiStyle = "relative w-12 h-12 rounded-lg bg-gray900";
const buttonStyle = "flex justify-center items-center h-full text-black400";
const { page, pageSize } = router.query;
const buttonStyle =
"flex justify-center items-center w-full h-full text-black400";

const router = useRouter();

const currentPage = Number(page);
const currentPageSize = Number(pageSize);
const { page, pageSize } = router.query;
const currentPage = Number(page) || 1;
const currentPageSize = Number(pageSize) || 6;
const totalPages = Math.ceil(totalCount / currentPageSize);
const [maxPagesToShow, setMaxPagesToShow] = useState(2);

// 화면 크기 변화에 따라 pageSize와 maxPagesToShow를 설정
useEffect(() => {
const handleResize = () => {
const width = window.innerWidth;
setMaxPagesToShow(width > 1024 ? 5 : 3);
};
const [maxPagesToShow, setMaxPagesToShow] = useState(2);
const { isPC } = useViewport();

// 초기 설정 및 리사이즈 이벤트 리스너 추가
handleResize();
window.addEventListener("resize", handleResize);
const handlePageChange = (newPage: number) => {
if (newPage !== currentPage) {
const path = router.pathname;
router.push(
{
pathname: path,
query: { page: newPage, pageSize: currentPageSize },
},
undefined,
{ shallow: true }
);
}
};

return () => {
window.removeEventListener("resize", handleResize);
};
}, []);
// 화면 크기 변화에 따라 maxPagesToShow를 설정
useEffect(() => {
if (isPC) {
setMaxPagesToShow(5);
} else {
setMaxPagesToShow(3);
}
}, [isPC]);

// 페이지 리스트 생성 함수
const getPageNumbers = () => {
Expand All @@ -59,9 +70,10 @@ const Pagination: React.FC<PaginationProps> = ({ totalCount }) => {
return (
<ul className="flex justify-center gap-[10px] my-10">
<li className={LiStyle}>
<Link
href={`/link?page=${currentPage - 1}&pageSize=${currentPageSize}`}
<button
onClick={() => handlePageChange(currentPage - 1)}
className={`${buttonStyle} ${currentPage > 1 ? "text-black500" : "pointer-events-none"}`}
disabled={currentPage <= 1}
>
<Image
src={
Expand All @@ -73,19 +85,19 @@ const Pagination: React.FC<PaginationProps> = ({ totalCount }) => {
width={24}
alt="prev"
/>
</Link>
</button>
</li>

{/* 페이지 번호와 생략 표시 */}
{getPageNumbers().map((pageNum, index) =>
typeof pageNum === "number" ? (
<li key={index} className={LiStyle}>
<Link
href={`/link?page=${pageNum}&pageSize=${pageSize}`}
<button
onClick={() => handlePageChange(pageNum)}
className={`${buttonStyle} ${pageNum === currentPage ? "text-black500" : "text-black400"}`}
>
{pageNum}
</Link>
</button>
</li>
) : (
<li
Expand All @@ -98,9 +110,10 @@ const Pagination: React.FC<PaginationProps> = ({ totalCount }) => {
)}

<li className={LiStyle}>
<Link
href={`/link?page=${currentPage + 1}&pageSize=${pageSize}`}
<button
onClick={() => handlePageChange(currentPage + 1)}
className={`${buttonStyle} ${currentPage < totalPages ? "text-black500" : "pointer-events-none"}`}
disabled={currentPage >= totalPages}
>
<Image
src={
Expand All @@ -112,7 +125,7 @@ const Pagination: React.FC<PaginationProps> = ({ totalCount }) => {
height={24}
alt="next"
/>
</Link>
</button>
</li>
</ul>
);
Expand Down
34 changes: 22 additions & 12 deletions hooks/useFetchLinks.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useEffect } from "react";
import { useEffect, useState } from "react";
import { proxy } from "@/lib/api/axiosInstanceApi";
import { LinkData } from "@/types/linkTypes";
import useViewport from "./useViewport";
import { useRouter } from "next/router";

// 링크페이지의 query가 바뀌면 새로운 리스트로 업데이트 해주는 훅
const useFetchLinks = (
Expand All @@ -11,22 +11,32 @@ const useFetchLinks = (
},
setLinkCardList: (list: LinkData[]) => void
) => {
const { isTablet } = useViewport();
const router = useRouter();

useEffect(() => {
const fetchLinks = async () => {
const res = await proxy.get("/api/links", {
params: {
page: query.page,
pageSize: isTablet ? 6 : 10,
search: query.search,
},
});
setLinkCardList(res.data.list);
// 경로에 따라 API 엔드포인트 분기
let endpoint = "/api/links";
const params: any = {
page: query.page,
pageSize: 6,
search: query.search,
};

if (router.pathname === "/favorite") {
endpoint = "/api/favorites";
}

try {
const res = await proxy.get(endpoint, { params });
setLinkCardList(res.data.list);
} catch (error) {
console.error("Error fetching links:", error);
}
};

if (query) fetchLinks();
}, [query, setLinkCardList, isTablet]);
}, [query, setLinkCardList, router.pathname]);
};

export default useFetchLinks;
5 changes: 5 additions & 0 deletions lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,8 @@
export const bindCls = (...cls: string[]) => {
return cls.join(" ");
};

// 데이터나 API에서 이미지 URL이 //로 오는 경우 자동으로 프로토콜 추가
export const ensureAbsoluteUrl = (url: string) => {
return url.startsWith("//") ? `https:${url}` : url;
};
11 changes: 5 additions & 6 deletions pages/api/favorites/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import axiosInstance from "@/lib/api/axiosInstanceApi";
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const cookies = parse(req.headers.cookie || "");
const accessToken = cookies.accessToken;
const { page, pageSize = 6 } = req.query;

if (!accessToken) {
return res.status(401).json({ message: "인증 오류: 토큰이 없습니다." });
Expand All @@ -14,12 +15,10 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
case "GET":
// 즐겨찾기 목록 조회
try {
const response = await axiosInstance.get(
"/favorites?page=1&pageSize=10",
{
headers: { Authorization: `Bearer ${accessToken}` },
}
);
const response = await axiosInstance.get(`/favorites`, {
params: { page, pageSize },
headers: { Authorization: `Bearer ${accessToken}` },
});
return res.status(200).json(response.data);
} catch (err: any) {
// 즐겨찾기 폴더가 없는 경우 (404 처리)
Expand Down
2 changes: 1 addition & 1 deletion pages/api/links/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import axiosInstance from "@/lib/api/axiosInstanceApi";
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const cookies = parse(req.headers.cookie || "");
const accessToken = cookies.accessToken;
const { page, pageSize, search } = req.query;
const { page, pageSize = 6, search } = req.query;

switch (req.method) {
case "GET":
Expand Down
28 changes: 19 additions & 9 deletions pages/favorite/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import { GetServerSideProps, GetServerSidePropsContext } from "next";
import { proxy } from "@/lib/api/axiosInstanceApi";
import axiosInstance from "@/lib/api/axiosInstanceApi";
import CardsLayout from "@/components/Layout/CardsLayout";
import Container from "@/components/Layout/Container";
import LinkCard from "@/components/Link/LinkCard";
import Pagination from "@/components/Pagination";
import useFetchLinks from "@/hooks/useFetchLinks";
import { useRouter } from "next/router";
import { useState } from "react";
import { parse } from "cookie";

interface FavoriteDataType {
id: number;
Expand All @@ -24,13 +29,11 @@ export const getServerSideProps: GetServerSideProps = async (
) => {
// 클라이언트의 쿠키 가져오기
const { req } = context;
const cookies = req.headers.cookie || "";

const cookies = parse(req.headers.cookie || "");
const accessToken = cookies.accessToken;
try {
const res = await proxy.get("/api/favorites", {
headers: {
Cookie: cookies,
},
const res = await axiosInstance.get("/favorites?page=1&pageSize=10", {
headers: { Authorization: `Bearer ${accessToken}` },
});

const { list, totalCount } = res.data || { list: [], totalCount: 0 };
Expand All @@ -42,6 +45,12 @@ export const getServerSideProps: GetServerSideProps = async (
};

const FavoritePage = ({ favoriteList, totalCount }: FavoriteProps) => {
const router = useRouter();

const [linkCardList, setLinkCardList] =
useState<FavoriteDataType[]>(favoriteList);

useFetchLinks(router.query, setLinkCardList);
return (
<>
<div className="page-title pt-[10px] md:pt-5 pb-10 md:pb-[60px] bg-gray100 text-center">
Expand All @@ -51,8 +60,8 @@ const FavoritePage = ({ favoriteList, totalCount }: FavoriteProps) => {
</div>
<Container>
<CardsLayout>
{favoriteList.length > 0
? favoriteList.map((favorite) => (
{linkCardList.length > 0
? linkCardList.map((favorite) => (
<LinkCard key={favorite.id} info={favorite} />
))
: null}
Expand All @@ -70,6 +79,7 @@ const FavoritePage = ({ favoriteList, totalCount }: FavoriteProps) => {
</div>
</div>
)}
<Pagination totalCount={totalCount} />
</Container>
</>
);
Expand Down
Loading