Skip to content

Commit 3ce0daa

Browse files
committed
Merge branch 'develop' of https://github.com/codeit9-temporary/linkbrary into feature/simple-login-kakao
2 parents ba21810 + caab5db commit 3ce0daa

File tree

20 files changed

+312
-39
lines changed

20 files changed

+312
-39
lines changed

components/HeaderMenu.tsx

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,29 @@ import Link from "next/link";
55
import SubmitButton from "./SubMitButton";
66
import { useRouter } from "next/router";
77
import useAuthStore from "@/store/useAuthStore";
8-
import { useEffect } from "react";
8+
import { useEffect, useState } from "react";
9+
import Dropdown from "./Dropdown";
910

1011
const HeaderMenu = () => {
11-
const { user, isLoggedIn, checkLogin } = useAuthStore();
12+
const { user, checkLogin, isLoggedIn, logout } = useAuthStore();
13+
const [isOpen, setIsOpen] = useState(false);
1214
const router = useRouter();
1315

1416
useEffect(() => {
1517
checkLogin();
1618
}, [checkLogin]);
1719

20+
const dropdownItems = [
21+
{
22+
label: "마이링크",
23+
href: "/link",
24+
},
25+
{
26+
label: "로그아웃",
27+
onClick: logout,
28+
},
29+
];
30+
1831
return (
1932
<>
2033
{!isLoggedIn ? (
@@ -30,7 +43,7 @@ const HeaderMenu = () => {
3043
로그인
3144
</SubmitButton>
3245
) : (
33-
<div className="flex items-center gap-[24px]">
46+
<div className="relative flex items-center gap-[24px]">
3447
<Link
3548
href={"/favorite"}
3649
className="flex items-center gap-[6px] bg-gray200 border border-purple100 rounded-[4px] py-[10px] px-[12px] text-[12px] leading-[14.32px] md:text-[14px] md:leading-[16.71px] lg:text-[14px] lg:leading-[16.71px] font-normal"
@@ -44,10 +57,16 @@ const HeaderMenu = () => {
4457
/>
4558
즐겨찾기
4659
</Link>
47-
<div className="flex items-center gap-[6px] text-[14px] leading-[16.71px] font-normal">
60+
<div
61+
className="flex items-center gap-[6px] text-[14px] leading-[16.71px] font-normal"
62+
onClick={() => setIsOpen(!isOpen)}
63+
>
4864
<Image src={Profile} width={28} height={28} alt="프로필" />
4965
<span className="hidden md:block lg:block">{user?.name}</span>
5066
</div>
67+
<div className="absolute top-8 right-0">
68+
{isOpen && <Dropdown items={dropdownItems} />}
69+
</div>
5170
</div>
5271
)}
5372
</>

components/LinkCard.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ interface LinkCardProps {
2222
const LinkCard = ({ openEdit, openDelete, info }: LinkCardProps) => {
2323
const [isSubscribed, setIsSubscribed] = useState(false);
2424
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
25-
const { isOpen: isModalOpen } = useModalStore(); // 모달 열림 상태 구독
25+
const { isOpen: isModalOpen } = useModalStore();
2626

2727
const formattedDate = info.createdAt?.slice(0, 10).replace(/-/g, ".");
2828
const createdTime = timeAgo(info.createdAt);

components/Pagination.tsx

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
import Image from "next/image";
2+
import Link from "next/link";
3+
import { useEffect, useState } from "react";
4+
5+
interface PaginationProps {
6+
page: number;
7+
pageSize: number;
8+
totalCount: number;
9+
}
10+
11+
const Pagination: React.FC<PaginationProps> = ({
12+
page,
13+
pageSize,
14+
totalCount,
15+
}) => {
16+
const LiStyle = "relative w-12 h-12 rounded-lg bg-gray900";
17+
const buttonStyle = "flex justify-center items-center h-full text-black400";
18+
19+
const totalPages = Math.ceil(totalCount / pageSize);
20+
const [maxPagesToShow, setMaxPagesToShow] = useState(2);
21+
22+
// 화면 크기 변화에 따라 pageSize와 maxPagesToShow를 설정
23+
useEffect(() => {
24+
const handleResize = () => {
25+
const width = window.innerWidth;
26+
setMaxPagesToShow(width > 1024 ? 5 : 3);
27+
};
28+
29+
// 초기 설정 및 리사이즈 이벤트 리스너 추가
30+
handleResize();
31+
window.addEventListener("resize", handleResize);
32+
33+
return () => {
34+
window.removeEventListener("resize", handleResize);
35+
};
36+
}, []);
37+
38+
// 페이지 리스트 생성 함수
39+
const getPageNumbers = () => {
40+
const pages = [];
41+
42+
if (totalPages <= maxPagesToShow) {
43+
// 전체 페이지 수가 표시 가능한 페이지 수 이하인 경우 모든 페이지 표시
44+
for (let i = 1; i <= totalPages; i++) pages.push(i);
45+
} else {
46+
// 첫 페이지와 마지막 페이지는 항상 표시
47+
pages.push(1);
48+
let start = Math.max(2, page - 1);
49+
let end = Math.min(totalPages - 1, page + 1);
50+
51+
if (page > 3) pages.push("...");
52+
for (let i = start; i <= end; i++) pages.push(i);
53+
if (page < totalPages - 2) pages.push("...");
54+
pages.push(totalPages);
55+
}
56+
57+
return pages;
58+
};
59+
60+
return (
61+
<ul className="flex justify-center gap-[10px] my-10">
62+
<li className={LiStyle}>
63+
<Link
64+
href={`/link?page=${page - 1}&pageSize=${pageSize}`}
65+
className={`${buttonStyle} ${page > 1 ? "text-black500" : "pointer-events-none"}`}
66+
>
67+
<Image
68+
src={
69+
page > 1
70+
? "/icons/pagination-left-active.png"
71+
: "/icons/pagination-left.png"
72+
}
73+
height={24}
74+
width={24}
75+
alt="prev"
76+
/>
77+
</Link>
78+
</li>
79+
80+
{/* 페이지 번호와 생략 표시 */}
81+
{getPageNumbers().map((pageNum, index) =>
82+
typeof pageNum === "number" ? (
83+
<li key={index} className={LiStyle}>
84+
<Link
85+
href={`/link?page=${pageNum}&pageSize=${pageSize}`}
86+
className={`${buttonStyle} ${pageNum === page ? "text-black500" : "text-black400"}`}
87+
>
88+
{pageNum}
89+
</Link>
90+
</li>
91+
) : (
92+
<li
93+
key={index}
94+
className={`${LiStyle} flex items-center justify-center text-black400`}
95+
>
96+
...
97+
</li>
98+
)
99+
)}
100+
101+
<li className={LiStyle}>
102+
<Link
103+
href={`/link?page=${page + 1}&pageSize=${pageSize}`}
104+
className={`${buttonStyle} ${page < totalPages ? "text-black500" : "pointer-events-none"}`}
105+
>
106+
<Image
107+
src={
108+
page < totalPages
109+
? "/icons/pagination-right-active.png"
110+
: "/icons/pagination-right.png"
111+
}
112+
width={24}
113+
height={24}
114+
alt="next"
115+
/>
116+
</Link>
117+
</li>
118+
</ul>
119+
);
120+
};
121+
122+
export default Pagination;

components/modal/AddModal.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ const AddModal = ({ list, link }: { list: FolderItemType[]; link: string }) => {
4343
type="button"
4444
onClick={handleSubmit}
4545
width="w-full"
46-
height="h-[51px] "
46+
height="h-[51px]"
4747
color="positive"
4848
>
4949
추가하기

components/modal/DeleteFolderModal.tsx

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,33 @@
1+
import useModalStore from "@/store/useModalStore";
12
import SubmitButton from "../SubMitButton";
23
import ModalContainer from "./modalComponents/ModalContainer";
4+
import { deleteFolder } from "@/lib/api/folder";
5+
6+
const DeleteFolderModal = ({
7+
folderName,
8+
folderId,
9+
}: {
10+
folderName: string;
11+
folderId: number;
12+
}) => {
13+
const { closeModal } = useModalStore();
14+
const handleSubmit = async () => {
15+
try {
16+
await deleteFolder(folderId);
17+
} catch (error) {
18+
console.log(error, "폴더 삭제 에러");
19+
} finally {
20+
closeModal();
21+
}
22+
};
323

4-
const DeleteFolderModal = ({ folderName }: { folderName: string }) => {
5-
console.log("folderName", folderName);
624
return (
725
<ModalContainer title="폴더 삭제" subtitle={folderName}>
826
<SubmitButton
927
type="button"
10-
// onClick={handleSubmit}
28+
onClick={handleSubmit}
1129
width="w-full"
12-
height="h-[51px] "
30+
height="h-[51px]"
1331
color="negative"
1432
>
1533
삭제하기

components/modal/EditLink.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ const EditLink = ({
2121
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
2222
setValue(e.target.value);
2323
};
24-
2524
const handleSubmit = async () => {
2625
const body = {
2726
url: value,

components/modal/EditModal.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ const EditModal = ({ folderName }: { folderName: string }) => {
4141
type="button"
4242
// onClick={handleSubmit}
4343
width="w-full"
44-
height="h-[51px] "
44+
height="h-[51px]"
4545
color="positive"
4646
>
4747
변경하기

components/modal/modalComponents/ModalContainer.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,24 @@
11
import { IoIosClose } from "react-icons/io";
2-
import SubmitButton from "../../SubMitButton";
32
import { ModalPropType } from "@/types/modalTypes";
43
import useModalStore from "@/store/useModalStore";
54
import { MouseEvent, useRef } from "react";
65

76
const ModalContainer = ({ title, subtitle, children }: ModalPropType) => {
8-
const { closeModal } = useModalStore();
7+
const { isOpen, closeModal } = useModalStore();
98
const modalRef = useRef<HTMLDivElement | null>(null);
109
const onClickBackDrop = (e: MouseEvent<HTMLDivElement>) => {
1110
if (modalRef.current && !modalRef.current.contains(e.target as Node))
1211
closeModal();
1312
};
14-
13+
if (isOpen) {
14+
document.body.style.overflow = "hidden";
15+
} else {
16+
document.body.style.overflow = "auto";
17+
}
1518
return (
1619
<div
1720
onClick={onClickBackDrop}
18-
className="z-30 absolute top-0 left-0 flex justify-center items-center bg-black/40 h-screen w-screen"
21+
className=" z-30 fixed top-0 left-0 flex justify-center items-center bg-black/40 h-screen w-screen"
1922
>
2023
<div
2124
ref={modalRef}

components/modal/modalManager/ModalManager.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,12 @@ export const Modal = () => {
4242
/>
4343
);
4444
case "DeleteFolderModal":
45-
return <DeleteFolderModal folderName={props.folderName || "폴더이름"} />;
45+
return (
46+
<DeleteFolderModal
47+
folderName={props.folderName || "폴더이름"}
48+
folderId={props.folderId || 1}
49+
/>
50+
);
4651
case "DeleteLinkModal":
4752
return (
4853
<DeleteLinkModal

lib/api/folder.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,29 +25,29 @@ export const postFolders = async (body: folderApiProps) => {
2525
};
2626

2727
// 폴더 조회
28-
export const getFolder = async (forderId: number) => {
28+
export const getFolder = async (folderId: number) => {
2929
try {
30-
const res = await axiosInstance.get(`/folders/${forderId}`);
30+
const res = await axiosInstance.get(`/folders/${folderId}`);
3131
if (res.status >= 200 && res.status < 300) return res.data;
3232
} catch (err) {
3333
console.error("에러 메시지: ", err instanceof Error ? err.message : err);
3434
}
3535
};
3636

3737
// 폴더 삭제(auth)
38-
export const deleteFolder = async (forderId: number) => {
38+
export const deleteFolder = async (folderId: number) => {
3939
try {
40-
const res = await proxy.delete(`/api/folders/${forderId}`);
40+
const res = await proxy.delete(`/api/folders/${folderId}`);
4141
if (res.status >= 200 && res.status < 300) return res.data;
4242
} catch (err) {
4343
console.error("에러 메시지: ", err instanceof Error ? err.message : err);
4444
}
4545
};
4646

4747
// 폴더 이름 수정(auth)
48-
export const putFolder = async (forderId: number, body: folderApiProps) => {
48+
export const putFolder = async (folderId: number, body: folderApiProps) => {
4949
try {
50-
const res = await proxy.put(`/api/folders/${forderId}`, body);
50+
const res = await proxy.put(`/api/folders/${folderId}`, body);
5151
if (res.status >= 200 && res.status < 300) return res.data;
5252
} catch (err) {
5353
console.error("에러 메시지: ", err instanceof Error ? err.message : err);

0 commit comments

Comments
 (0)