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
12 changes: 10 additions & 2 deletions components/Folder/AddFolderButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,24 @@ import useRerenderFolderList from "@/hooks/useRerenderFolderList";

interface AddFolderButtonProps {
setFolderList: React.Dispatch<React.SetStateAction<FolderData[]>>;
isModal?: boolean;
}

export const AddFolderButton = ({ setFolderList }: AddFolderButtonProps) => {
export const AddFolderButton = ({
setFolderList,
isModal = false,
}: AddFolderButtonProps) => {
const { isOpen, openModal } = useModalStore();

useRerenderFolderList(isOpen, setFolderList);

return (
<button
className="w-[79px] h-[19px] text-purple100"
className={
!isModal
? "w-[100px] mt-auto text-purple100"
: "fixed-bottom w-[120px] h-[35px] rounded-[20px] bg-purple100 text-white hover:bg-purple50"
}
onClick={() => openModal("AddFolderModal")}
>
폴더 추가 +
Expand Down
17 changes: 14 additions & 3 deletions components/Folder/FolderActionsMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,15 @@ import useRerenderFolderList from "../../hooks/useRerenderFolderList";

interface FolderActionsMenuProps {
setFolderList: React.Dispatch<React.SetStateAction<FolderData[]>>;
folderId: string | string[] | undefined;
linkCount: number;
}

const FolderActionsMenu = ({ setFolderList }: FolderActionsMenuProps) => {
const FolderActionsMenu = ({
setFolderList,
folderId,
linkCount,
}: FolderActionsMenuProps) => {
const { isOpen, openModal } = useModalStore();

const handleModalOpen = (text: string) => {
Expand All @@ -16,10 +22,15 @@ const FolderActionsMenu = ({ setFolderList }: FolderActionsMenuProps) => {
openModal("SNSModal");
break;
case "이름 변경":
openModal("EditModal");
openModal("EditModal", {
folderId: Number(folderId),
});
break;
case "삭제":
openModal("DeleteFolderModal");
openModal("DeleteFolderModal", {
folderId: Number(folderId),
linkCount: linkCount,
});
break;
default:
break;
Expand Down
10 changes: 5 additions & 5 deletions components/Folder/FolderTag.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,23 @@ const FolderTag = ({ folderList }: FolderListData) => {
const { folder: currentFolderId } = router.query;

const folderStyle =
"py-[8px] px-[12px] border border-purple100 rounded-md hover:bg-purple100 hover:text-white";
"w-[100px] h-[35px] px-[15px] text-sm whitespace-nowrap truncate border border-purple100 rounded-md hover:bg-purple100 hover:text-white";

const handleSubmit = (id: number | string) => {
const handleSubmit = (selectedFolderId: number | string) => {
router.push({
pathname: router.pathname,
query: id ? { folder: id } : {},
query: selectedFolderId ? { folder: selectedFolderId } : {},
});
};

return (
<ul className="flex flex-wrap gap-[8px]">
<ul className="flex flex-wrap gap-[8px] lg:w-[80%] md:w-[80%]">
<li>
<button className={folderStyle} onClick={() => handleSubmit("")}>
전체
</button>
</li>
{folderList.map((folder) => (
{folderList.slice(0, 8).map((folder) => (
<li key={folder.id}>
<button
className={`${folderStyle} ${folder.id === Number(currentFolderId) && "bg-purple100 text-white"}`}
Expand Down
2 changes: 1 addition & 1 deletion components/Link/LinkCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ 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 timeAgo from "@/util/timeAgo";
import Image from "next/image";
import Dropdown from "../Dropdown";
import useModalStore from "@/store/useModalStore";
Expand Down
9 changes: 9 additions & 0 deletions components/Link/RenderEmptyLinkMessage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const RenderEmptyLinkMessage = () => {
return (
<span className="w-full h-[200px] flex justify-center items-center">
저장된 링크가 없습니다.
</span>
);
};

export default RenderEmptyLinkMessage;
2 changes: 1 addition & 1 deletion components/Search/SearchInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const SearchInput = () => {
return (
<form
onSubmit={handleSubmit}
className="flex gap-[8px] w-[1024px] h-[54px] items-center px-[16px] py-[15px] bg-gray-100 rounded-[10px] md:w-[704px] md:h-[54px] sm:w-[325px] sm:h-[43px] transition-all"
className="flex gap-[8px] w-full h-[54px] items-center px-[16px] py-[15px] bg-gray-100 rounded-[10px] md:h-[54px] sm:h-[43px] transition-all"
>
<Image
src="/icons/search.svg"
Expand Down
2 changes: 1 addition & 1 deletion components/modal/DeleteFolderModal.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { deleteFolder } from "@/lib/api/folder";
import useModalStore from "@/store/useModalStore";
import SubmitButton from "../SubMitButton";
import ModalContainer from "./modalComponents/ModalContainer";
import { deleteFolder } from "@/lib/api/folder";
import toast from "react-hot-toast";
import toastMessages from "@/lib/toastMessage";

Expand Down
1 change: 0 additions & 1 deletion components/modal/modalManager/ModalManager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ export type ModalKeysType = keyof typeof ModalType;

export const Modal = () => {
const { modalType, isOpen, props } = useModalStore();

if (!modalType || !isOpen) return null;

switch (modalType) {
Expand Down
51 changes: 28 additions & 23 deletions hooks/useFetchLinks.tsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,43 @@
import { useEffect, useState } from "react";
import { useEffect } from "react";
import { proxy } from "@/lib/api/axiosInstanceApi";
import { LinkData } from "@/types/linkTypes";
import { useRouter } from "next/router";
import { ParsedUrlQuery } from "querystring";
import useViewport from "./useViewport";

// 링크페이지의 query가 바뀌면 새로운 리스트로 업데이트 해주는
// 링크페이지의 query가 바뀌면 그에 맞는 링크들을 보여주는
const useFetchLinks = (
setLinkCardList: (list: LinkData[], totalCount: number) => void
setLinkCardList: React.Dispatch<React.SetStateAction<LinkData[]>>,
setTotalCount?: React.Dispatch<React.SetStateAction<number>>,
query?: ParsedUrlQuery,
pathname?: string
) => {
const router = useRouter();
const { isTablet } = useViewport();

useEffect(() => {
const fetchLinks = async () => {
// 경로에 따라 API 엔드포인트 분기
let endpoint = "/api/links";
const params: any = {
page: router.query.page,
pageSize: 6,
search: router.query.search,
};
let endpoint =
pathname === "/favorite"
? "/api/favorites"
: query?.folder
? `/api/folders/${query.folder}/links`
: "/api/links";

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

try {
const res = await proxy.get(endpoint, { params });
setLinkCardList(res.data.list, res.data.totalCount);
} catch (error) {
console.error("Error fetching links:", error);
const res = await proxy.get(endpoint, {
params: {
page: query?.page,
pageSize: isTablet ? 6 : 10,
search: query?.search,
},
});
console.log("query가 바뀌었을 때 다시 받아온 리스트:", res.data.list);
setLinkCardList(res.data.list);
{
setTotalCount && setTotalCount(res.data.totalCount);
}
};

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

export default useFetchLinks;
22 changes: 22 additions & 0 deletions hooks/useGetFolderInfo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { useEffect, useState } from "react";
import { useRouter } from "next/router";
import { getFolder } from "@/lib/api/folder";

const useGetFolderInfo = () => {
const router = useRouter();
const folderId = router.query.folder;
const [folderName, setFolderName] = useState("폴더이름");

useEffect(() => {
if (!folderId) return;

const fetchFolderData = async () => {
const res = await getFolder(folderId);
if (res) setFolderName(res.data?.name);
};
fetchFolderData();
}, [folderId]);

return { folderName, folderId };
};
export default useGetFolderInfo;
2 changes: 1 addition & 1 deletion lib/api/axiosInstanceApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const axiosInstance = axios.create({
});

export const proxy = axios.create({
// 배포 이후에는 배포된 URL로 변경해야 함.
// 배포 이후에는 배포된 URL로 변경해야 함.gi
baseURL: "http://localhost:3000",
});

Expand Down
2 changes: 1 addition & 1 deletion lib/api/folder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const postFolders = async (body: folderApiProps) => {
};

// 폴더 조회
export const getFolder = async (folderId: number) => {
export const getFolder = async (folderId: string | string[] | undefined) => {
try {
const res = await axiosInstance.get(`/folders/${folderId}`);
if (res.status >= 200 && res.status < 300) return res.data;
Expand Down
2 changes: 1 addition & 1 deletion next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { NextConfig } from "next";

const nextConfig: NextConfig = {
/* config options here */
reactStrictMode: true,
reactStrictMode: false,
// 외부 이미지 도메인 추가
images: {
remotePatterns: [
Expand Down
57 changes: 37 additions & 20 deletions pages/api/folders/[folderId]/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,44 +5,37 @@ import { NextApiRequest, NextApiResponse } from "next";
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const token = req.cookies.accessToken;
const { folderId } = req.query;
const id = Number(folderId);

if (!token) {
return res.status(401).json({ error: "사용자 정보를 찾을 수 없습니다." });
}

if (isNaN(id)) {
if (!folderId) {
return res.status(400).json({ error: "유효하지 않은 폴더 ID 입니다" });
}

switch (req.method) {
case "DELETE":
case "GET":
try {
await axiosInstance.delete(`/folders/${id}`, {
const response = await axiosInstance.get(`/folders/${folderId}`, {
headers: {
Authorization: `Bearer ${token}`,
},
});
return res.status(204).json({ message: "폴더 삭제 성공" });
return res
.status(200)
.json({ message: "데이터 조회 성공", data: response.data });
} catch (error) {
if (axios.isAxiosError(error)) {
console.error("Axios Error:", error); // 여기서 error 객체 전체를 확인
if (error.response) {
const status = error.response.status;
const message =
error.response.data?.message || "알 수 없는 오류 발생";
console.error("Error Response Data:", error.response.data);
return res.status(status).json({ message: message });
}
console.error("Unknown Error:", error); // Axios 오류가 아닌 경우
throw error;
if (axios.isAxiosError(error) && error.response) {
const status = error.response.status;
const message =
error.response.data?.message || "알 수 없는 오류 발생";
return res.status(status).json({ message });
}
return res.status(500).json({ message: "서버 오류 발생" });
}

case "PUT":
try {
await axiosInstance.put(`/folders/${id}`, req.body, {
await axiosInstance.put(`/folders/${folderId}`, req.body, {
headers: {
Authorization: `Bearer ${token}`,
},
Expand All @@ -53,10 +46,34 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const status = error.response.status;
const message =
error.response.data?.message || "알 수 없는 오류 발생";
throw error;
return res.status(status).json({ message });
}
}

case "DELETE":
console.log("너 왔니?");
try {
await axiosInstance.delete(`/folders/${folderId}`, {
headers: {
Authorization: `Bearer ${token}`,
},
});
return res.status(204).json({ message: "폴더 삭제 성공" });
} catch (error) {
if (axios.isAxiosError(error)) {
console.error("Axios Error:", error); // 여기서 error 객체 전체를 확인
if (error.response) {
const status = error.response.status;
const message =
error.response.data?.message || "알 수 없는 오류 발생";
console.error("Error Response Data:", error.response.data);
return res.status(status).json({ message: message });
}
console.error("Unknown Error:", error); // Axios 오류가 아닌 경우
throw error;
}
return res.status(500).json({ message: "서버 오류 발생" });
}
}
};
export default handler;
40 changes: 40 additions & 0 deletions pages/api/folders/[folderId]/links.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import axiosInstance from "@/lib/api/axiosInstanceApi";
import axios from "axios";
import { NextApiRequest, NextApiResponse } from "next";

const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const token = req.cookies.accessToken;
const { page, pageSize, folderId } = req.query;

if (!token) {
return res.status(401).json({ error: "사용자 정보를 찾을 수 없습니다." });
}

if (!folderId) {
return res.status(400).json({ error: "유효하지 않은 폴더 ID 입니다" });
}

switch (req.method) {
case "GET":
try {
const response = await axiosInstance.get(`/folders/${folderId}/links`, {
headers: {
Authorization: `Bearer ${token}`,
},
params: {
page: page,
pageSize: pageSize,
},
});
return res.status(200).json(response.data);
} catch (error) {
if (axios.isAxiosError(error) && error.response) {
const status = error.response.status;
const message =
error.response.data?.message || "알 수 없는 오류 발생";
return res.status(status).json({ message });
}
}
}
};
export default handler;
Loading
Loading