Skip to content

Commit 33f9ccd

Browse files
authored
Refactor: link페이지 수정
Refactor: link페이지 수정
2 parents 0015b39 + 4fe5a84 commit 33f9ccd

File tree

7 files changed

+97
-61
lines changed

7 files changed

+97
-61
lines changed

components/Link/LinkCard.tsx

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useEffect, useRef, useState } from "react";
1+
import { MouseEvent, useEffect, useRef, useState } from "react";
22
import { useRouter } from "next/router";
33
import { useLinkCardStore } from "@/store/useLinkCardStore";
44
import { ensureAbsoluteUrl } from "@/util/ensureAbsoluteUrl";
@@ -44,7 +44,8 @@ const LinkCard = ({ info }: LinkCardProps) => {
4444
});
4545

4646
// 즐겨찾기 버튼 클릭 시 호출되는 함수
47-
const handleFavoriteToggle = async () => {
47+
const handleFavoriteToggle = async (e: MouseEvent<HTMLDivElement>) => {
48+
e.stopPropagation();
4849
setIsSubscribed((prev) => !prev);
4950
try {
5051
updateFavorite(info.id, !isSubscribed);
@@ -54,7 +55,10 @@ const LinkCard = ({ info }: LinkCardProps) => {
5455
};
5556

5657
// dropdown 버튼
57-
const toggleDropdown = () => setIsDropdownOpen((prev) => !prev);
58+
const toggleDropdown = (e: MouseEvent<HTMLButtonElement>) => {
59+
e.stopPropagation();
60+
setIsDropdownOpen((prev) => !prev);
61+
};
5862

5963
const handleModalOpen = (
6064
type: "EditLink" | "DeleteLinkModal",
@@ -64,6 +68,12 @@ const LinkCard = ({ info }: LinkCardProps) => {
6468
openModal(type, { link, linkId });
6569
};
6670

71+
const handleNavigate = (url: string) => {
72+
if (!isDropdownOpen)
73+
window.location.href =
74+
url.slice(0, 4) === "http" ? url : `https://${url}`;
75+
};
76+
6777
const dropdownItems = [
6878
{
6979
label: "수정하기",
@@ -76,7 +86,10 @@ const LinkCard = ({ info }: LinkCardProps) => {
7686
];
7787

7888
return (
79-
<div className="w-[340px] h-[344px] rounded-[12px] shadow-lg overflow-hidden cursor-pointer hover:scale-105 hover:duration-300">
89+
<div
90+
className="w-[340px] h-[344px] rounded-[12px] shadow-lg overflow-hidden cursor-pointer hover:scale-105 hover:duration-300"
91+
onClick={() => handleNavigate(info.url)}
92+
>
8093
<section className="relative w-full h-[60%]">
8194
<Image
8295
src={ensureAbsoluteUrl(info.imageSource) || `/images/no-content.svg`}
@@ -120,7 +133,10 @@ const LinkCard = ({ info }: LinkCardProps) => {
120133
</div>
121134
)}
122135
</div>
123-
<div className="text-black100 y-[42px] line-clamp-2">
136+
<div
137+
className="text-black100 y-[42px] line-clamp-2"
138+
onClick={() => handleNavigate(info.url)}
139+
>
124140
{info.description || "설명"}
125141
</div>
126142
<div className="text-sm">{formattedDate || "2024.11.06"}</div>

hooks/useFetchLinks.tsx

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,21 @@
1-
import { useState, useEffect } from "react";
1+
import { useEffect } from "react";
2+
import { useRouter } from "next/router";
23
import { proxy } from "@/lib/api/axiosInstanceApi";
34
import { LinkData } from "@/types/linkTypes";
4-
import { ParsedUrlQuery } from "querystring";
55
import useViewport from "./useViewport";
66

77
// 링크 페이지의 query가 바뀌면 그에 맞는 링크들을 보여주는 훅
88
const useFetchLinks = (
9-
setLinkCardList: React.Dispatch<React.SetStateAction<LinkData[]>>,
10-
setTotalCount?: React.Dispatch<React.SetStateAction<number>>,
11-
query?: ParsedUrlQuery,
12-
pathname?: string
9+
setLinkCardList: (list: LinkData[], totalCount: number) => void,
10+
setIsLoading: React.Dispatch<React.SetStateAction<boolean>>
1311
) => {
12+
const router = useRouter();
13+
const { query, pathname } = router;
1414
const { isTablet } = useViewport();
15-
const [loading, setLoading] = useState<boolean>(false); // 로딩 상태 관리
1615

1716
useEffect(() => {
1817
const fetchLinks = async () => {
19-
if (isTablet === undefined) return; // isTablet이 정의되지 않았으면 API 호출을 막음
20-
21-
setLoading(true); // API 호출 시작 시 로딩 상태 true
22-
18+
setIsLoading(true);
2319
// 경로에 따라 API 엔드포인트 분기
2420
let endpoint =
2521
pathname === "/favorite"
@@ -35,16 +31,12 @@ const useFetchLinks = (
3531
search: query?.search,
3632
},
3733
});
38-
setLinkCardList(res.data.list);
39-
{
40-
setTotalCount && setTotalCount(res.data.totalCount);
41-
}
34+
setLinkCardList(res.data.list, res.data.totalCount);
35+
setIsLoading(false);
4236
};
4337

4438
if (query) fetchLinks();
45-
}, [setLinkCardList, query, isTablet]);
46-
47-
return loading; // 로딩 상태 반환
39+
}, [setLinkCardList, setIsLoading, pathname, query, isTablet]);
4840
};
4941

5042
export default useFetchLinks;

hooks/useFolderName.tsx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { getFolder } from "@/lib/api/folder";
2+
import { useEffect, useState } from "react";
3+
4+
const useFolderName = (folderId: string | string[] | undefined) => {
5+
const [folderName, setFolderName] = useState("전체");
6+
7+
useEffect(() => {
8+
if (!folderId) return;
9+
10+
const fetchFolderInfo = async () => {
11+
try {
12+
const res = await getFolder(folderId as string);
13+
setFolderName(res.name);
14+
} catch (error) {
15+
console.error("Failed to fetch folder info:", error);
16+
}
17+
};
18+
fetchFolderInfo();
19+
}, [folderId]);
20+
21+
return [folderName, setFolderName];
22+
};
23+
24+
export default useFolderName;

lib/api/fetchProxy.ts

Lines changed: 0 additions & 10 deletions
This file was deleted.

lib/toastMessage.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const toastMessages = {
3131
sameFolderName: "같은 이름으로는 수정할 수 없습니다",
3232
invalidLink: "잘못된 링크 형식입니다",
3333
invalidLinkCount: "폴더 정보를 받아오는데 실패했습니다",
34+
needLogin: "로그인 후 이용해주세요",
3435
},
3536
};
3637

pages/favorite/index.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1+
import { useState } from "react";
2+
import { useRouter } from "next/router";
13
import { GetServerSideProps, GetServerSidePropsContext } from "next";
4+
import { parse } from "cookie";
25
import axiosInstance from "@/lib/api/axiosInstanceApi";
36
import CardsLayout from "@/components/Layout/CardsLayout";
47
import Container from "@/components/Layout/Container";
58
import LinkCard from "@/components/Link/LinkCard";
69
import Pagination from "@/components/Pagination";
710
import useFetchLinks from "@/hooks/useFetchLinks";
8-
import { useRouter } from "next/router";
9-
import { useState } from "react";
10-
import { parse } from "cookie";
1111
import LoadingSpinner from "@/components/LoadingSpinner";
1212
import EmptyFavoriteList from "@/components/Favorite/EmptyFavoriteList";
1313

@@ -62,9 +62,11 @@ const FavoritePage = ({
6262
const router = useRouter();
6363
const [linkCardList, setLinkCardList] =
6464
useState<FavoriteDataType[]>(favoriteList);
65+
const [isLoading, setIsLoading] = useState(false);
6566
const [totalCount, setTotalCount] = useState(initialTotalCount);
6667

67-
const loading = useFetchLinks(setLinkCardList, setTotalCount, router.query);
68+
useFetchLinks(setLinkCardList, setIsLoading);
69+
//
6870

6971
// 마이링크 페이지로 돌아감
7072
const returnButton = () => {
@@ -86,7 +88,7 @@ const FavoritePage = ({
8688
</div>
8789

8890
{/* 로딩 중일 때 */}
89-
{loading ? (
91+
{isLoading ? (
9092
<div className="text-center">
9193
<LoadingSpinner />
9294
</div>

pages/link/index.tsx

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
import { useState } from "react";
1+
import { useEffect, useState } from "react";
22
import { GetServerSidePropsContext } from "next";
33
import { useRouter } from "next/router";
44
import { parse } from "cookie";
55
import { LinkData } from "@/types/linkTypes";
66
import { FolderData } from "@/types/folderTypes";
77
import { Modal } from "@/components/modal/modalManager/ModalManager";
88
import { SearchInput } from "../../components/Search/SearchInput";
9+
import { useLinkCardStore } from "@/store/useLinkCardStore";
910
import axiosInstance from "@/lib/api/axiosInstanceApi";
1011
import useModalStore from "@/store/useModalStore";
1112
import Pagination from "@/components/Pagination";
@@ -20,6 +21,7 @@ import LinkCard from "@/components/Link/LinkCard";
2021
import RenderEmptyLinkMessage from "@/components/Link/RenderEmptyLinkMessage";
2122
import useFetchLinks from "@/hooks/useFetchLinks";
2223
import useViewport from "@/hooks/useViewport";
24+
import useFolderName from "@/hooks/useFolderName";
2325
import LoadingSpinner from "@/components/LoadingSpinner";
2426

2527
interface LinkPageProps {
@@ -36,6 +38,16 @@ export const getServerSideProps = async (
3638
const cookies = parse(req.headers.cookie || "");
3739
const accessToken = cookies.accessToken;
3840

41+
// accessToken이 없으면 클라이언트에서 실행될 때 /login 페이지로 이동시킴.
42+
if (!accessToken) {
43+
return {
44+
redirect: {
45+
destination: "/login",
46+
permanent: false,
47+
},
48+
};
49+
}
50+
3951
const fetchData = async (endpoint: string) => {
4052
const res = await axiosInstance.get(endpoint, {
4153
headers: {
@@ -68,17 +80,18 @@ const LinkPage = ({
6880
const { search, folder } = router.query;
6981
const { isOpen } = useModalStore();
7082
const { isMobile } = useViewport();
71-
const [linkCardList, setLinkCardList] = useState(initialLinkList);
83+
const { totalCount, linkCardList, setLinkCardList } =
84+
useLinkCardStore.getState();
85+
const [isLoading, setIsLoading] = useState(false);
86+
const [folderName] = useFolderName(folder);
7287
const [folderList, setFolderList] = useState(initialFolderList);
73-
const [totalCount, setTotalCount] = useState(initialTotalCount);
88+
89+
useEffect(() => {
90+
setLinkCardList(initialLinkList, initialTotalCount);
91+
}, [initialLinkList, initialTotalCount, setLinkCardList]);
7492

7593
// 링크페이지의 query가 바뀌면 새로운 리스트로 업데이트 해주는 훅
76-
const loading = useFetchLinks(
77-
setLinkCardList,
78-
setTotalCount,
79-
router.query,
80-
router.pathname
81-
);
94+
useFetchLinks(setLinkCardList, setIsLoading);
8295

8396
return (
8497
<>
@@ -94,29 +107,27 @@ const LinkPage = ({
94107
{!isMobile && <AddFolderButton setFolderList={setFolderList} />}
95108
</div>
96109
<div className="flex justify-between items-center my-[24px]">
97-
<h1 className="text-2xl ">유용한 글</h1>
98110
{folder && (
99-
<FolderActionsMenu
100-
setFolderList={setFolderList}
101-
folderId={folder}
102-
linkCount={totalCount}
103-
/>
111+
<>
112+
<h1 className="text-2xl ">{folderName as string}</h1>
113+
<FolderActionsMenu
114+
setFolderList={setFolderList}
115+
folderId={folder}
116+
linkCount={totalCount as number}
117+
/>
118+
</>
104119
)}
105120
</div>
106-
107-
{/* 로딩 중일 때 */}
108-
{loading ? (
109-
<div className="text-center">
110-
<LoadingSpinner />
111-
</div>
112-
) : linkCardList.length > 0 ? (
121+
{isLoading ? (
122+
<LoadingSpinner /> // 로딩 상태일 때 로딩 스피너 표시
123+
) : linkCardList.length !== 0 ? (
113124
<>
114125
<CardsLayout>
115126
{linkCardList.map((link) => (
116127
<LinkCard key={link.id} info={link} />
117128
))}
118129
</CardsLayout>
119-
<Pagination totalCount={totalCount} />
130+
<Pagination totalCount={totalCount as number} />
120131
</>
121132
) : (
122133
<RenderEmptyLinkMessage />

0 commit comments

Comments
 (0)