From 65df8aa18d9df4c6c53ec7ff30c06006a763865b Mon Sep 17 00:00:00 2001 From: SeungRyeolBaek Date: Sat, 29 Jun 2024 13:30:01 +0900 Subject: [PATCH 1/6] =?UTF-8?q?feat:=2015=EC=A3=BC=EC=B0=A8=20=EC=9C=84?= =?UTF-8?q?=ED=81=B4=EB=A6=AC=20=EB=AF=B8=EC=85=98=20=EC=9A=94=EA=B5=AC?= =?UTF-8?q?=EC=82=AC=ED=95=AD=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/folder/[[...folderId]]/index.tsx | 51 ++++++++++++++++++ pages/folder/index.tsx | 42 --------------- pages/shared/{ => [folderId]}/index.tsx | 17 +++--- src/data-access/index.js | 3 +- src/data-access/useGetFolder.ts | 25 ++++++--- src/data-access/useGetSharedLinks.ts | 27 ++++++++++ src/data-access/useGetUser.ts | 24 ++++++--- src/type/link.ts | 18 +++++++ src/ui/layout/parts/footer/Footer.tsx | 71 +++++++++++++++---------- src/ui/layout/parts/nav/Nav.tsx | 6 +-- src/util/constant.js | 15 +++++- src/util/custom-hook/useAsync.ts | 23 +++++--- 12 files changed, 218 insertions(+), 104 deletions(-) create mode 100644 pages/folder/[[...folderId]]/index.tsx delete mode 100644 pages/folder/index.tsx rename pages/shared/{ => [folderId]}/index.tsx (62%) create mode 100644 src/data-access/useGetSharedLinks.ts diff --git a/pages/folder/[[...folderId]]/index.tsx b/pages/folder/[[...folderId]]/index.tsx new file mode 100644 index 000000000..7910a4ae9 --- /dev/null +++ b/pages/folder/[[...folderId]]/index.tsx @@ -0,0 +1,51 @@ +import { useState } from "react"; +import { CardList, FolderToolBar, LinkForm } from "@/src/feature"; +import { Layout, SearchBar } from "@/src/ui"; +import { FolderLayout } from "@/src/page-layout/FolderLayout"; +import { + useIntersectionObserver, + useSearchLink, + ALL_LINKS_ID, +} from "@/src/util"; +import { useGetLinks, useGetFolders } from "@/src/data-access"; +import { ROUTE } from "@/src/util"; +import { useRouter } from "next/router"; +import { useEffect, useMemo } from "react"; + +const FolderPage = () => { + const router = useRouter(); + const { folderId } = router.query; + const currentFolderId = useMemo(() => { + if (router.isReady) { + return folderId?.[0] ? parseInt(folderId?.[0]) : ALL_LINKS_ID; + } + return undefined; + }, [router.isReady, folderId]); + const { data: folders } = useGetFolders(); + const { data: links, loading } = useGetLinks(currentFolderId); + const { searchValue, handleChange, handleCloseClick, result } = useSearchLink(links); + const { ref, isIntersecting } = useIntersectionObserver(); + + useEffect(() => { + const accessToken = localStorage.getItem("accessToken"); + if (!accessToken) { + router.replace(ROUTE.로그인); + } + }, [router]); + + return ( + + } + searchBar={ + + } + folderToolBar={} + cardList={loading ? null : } + /> + + ); + }; + + export default FolderPage; + \ No newline at end of file diff --git a/pages/folder/index.tsx b/pages/folder/index.tsx deleted file mode 100644 index 3f7959bd5..000000000 --- a/pages/folder/index.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { useState } from "react"; -import { CardList, FolderToolBar, LinkForm } from "@/src/feature"; -import { Layout, SearchBar } from "@/src/ui"; -import { FolderLayout } from "@/src/page-layout/FolderLayout"; -import { useIntersectionObserver, useSearchLink, ALL_LINKS_ID } from "@/src/util"; -import { SelectedFolderId } from "@/src/type"; -import { useGetLinks, useGetFolders } from "@/src/data-access"; - -const FolderPage = () => { - const { data: folders } = useGetFolders(); - const [selectedFolderId, setSelectedFolderId] = - useState(ALL_LINKS_ID); - const { data: links, loading } = useGetLinks(selectedFolderId); - const { searchValue, handleChange, handleCloseClick, result } = - useSearchLink(links); - const { ref, isIntersecting } = useIntersectionObserver(); - - return ( - - } - searchBar={ - - } - folderToolBar={ - - } - cardList={loading ? null : } - /> - - ); -}; - -export default FolderPage; diff --git a/pages/shared/index.tsx b/pages/shared/[folderId]/index.tsx similarity index 62% rename from pages/shared/index.tsx rename to pages/shared/[folderId]/index.tsx index 657fd3225..efe436c8a 100644 --- a/pages/shared/index.tsx +++ b/pages/shared/[folderId]/index.tsx @@ -1,4 +1,4 @@ -import { useGetFolder } from "@/src/data-access"; +import { useGetFolder, useGetUser, useGetSharedLinks } from "@/src/data-access"; import { CardList, Layout, @@ -8,10 +8,15 @@ import { } from "@/src/ui"; import { SharedLayout } from "@/src/page-layout/SharedLayout"; import { useSearchLink } from "@/src/util"; +import { useRouter } from "next/router"; const SharedPage = () => { - const { data } = useGetFolder(); - const { profileImage, ownerName, folderName, links } = data || {}; + const router = useRouter(); + const { folderId } = router.query; + const { data: folder } = useGetFolder(folderId as string); + const { data: owner } = useGetUser(folder.userId); + const { data: links } = useGetSharedLinks(folder.userId, folderId as string); + const { searchValue, handleChange, handleCloseClick, result } = useSearchLink(links); @@ -20,9 +25,9 @@ const SharedPage = () => { } searchBar={ diff --git a/src/data-access/index.js b/src/data-access/index.js index b33be5952..b60dbda65 100644 --- a/src/data-access/index.js +++ b/src/data-access/index.js @@ -4,4 +4,5 @@ export * from "./useGetFolders"; export * from "./useGetLinks" export * from "./useSignIn"; export * from "./useSignUp"; -export * from "./useCheckEmailDuplicate"; \ No newline at end of file +export * from "./useCheckEmailDuplicate"; +export * from "./useGetSharedLinks" \ No newline at end of file diff --git a/src/data-access/useGetFolder.ts b/src/data-access/useGetFolder.ts index 30090c465..e7a800792 100644 --- a/src/data-access/useGetFolder.ts +++ b/src/data-access/useGetFolder.ts @@ -1,5 +1,5 @@ -import { useAsync, instance, mapFolderData } from "@/src/util"; -import { SampleFolderRawData } from "@/src/type"; +import { FolderRawData } from "../type"; +import { DEFAULT_FOLDER, instance, useAsync } from "../util"; /** * useGetFolder 훅은 샘플 폴더 데이터를 가져와서 매핑된 폴더 데이터를 반환합니다. @@ -37,14 +37,23 @@ import { SampleFolderRawData } from "@/src/type"; * * ); */ -export const useGetFolder = () => { +export const useGetFolder = (folderId: string) => { const getFolder = () => - instance.get<{ folder: SampleFolderRawData }>("sample/folder"); - const { loading, error, data } = useAsync(getFolder); + instance.get<{ data: FolderRawData[] }>(`folders/${folderId}`); + const { loading, error, data } = useAsync({ + asyncFunction: getFolder, + enabled: !!folderId, + }); + const folderDataResponse = data?.data?.[0]; - const folderData = mapFolderData(data?.folder); + const folderData = folderDataResponse + ? { + id: folderDataResponse.id, + name: folderDataResponse.name, + userId: folderDataResponse.user_id, + createdAt: folderDataResponse.created_at, + } + : DEFAULT_FOLDER; return { loading, error, data: folderData }; }; - - diff --git a/src/data-access/useGetSharedLinks.ts b/src/data-access/useGetSharedLinks.ts new file mode 100644 index 000000000..1860818b3 --- /dev/null +++ b/src/data-access/useGetSharedLinks.ts @@ -0,0 +1,27 @@ +import { useCallback, useEffect } from "react"; +import { formatLinkRawData, LinkRawData } from "../type"; +import { useAsync, mapLinksData } from "../util"; +import { instance } from "../util"; + +export const useGetSharedLinks = (userId: number, folderId?: string) => { + const getLinks = useCallback( + () => + instance.get<{ data: LinkRawData[] }>( + `users/${userId}/links?folderId=${folderId}` + ), + [userId, folderId] + ); + const { execute, loading, error, data } = useAsync({ + asyncFunction: getLinks, + enabled: !!userId && !!folderId, + }); + + useEffect(() => { + execute(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [userId, folderId]); + + const linksData = data?.data?.map(formatLinkRawData).map(mapLinksData) ?? []; + + return { execute, loading, error, data: linksData }; +}; diff --git a/src/data-access/useGetUser.ts b/src/data-access/useGetUser.ts index c083ac5f9..64982cf5f 100644 --- a/src/data-access/useGetUser.ts +++ b/src/data-access/useGetUser.ts @@ -1,6 +1,6 @@ import { useAsync, instance } from "@/src/util"; import { UserRawData } from "@/src/type"; - +import { DEFAULT_USER } from "@/src/util"; /** * useGetUser 훅은 사용자 데이터를 가져와 반환합니다. @@ -28,8 +28,20 @@ import { UserRawData } from "@/src/type"; * * ); */ -export const useGetUser = () => { - const getUser = () => instance.get<{ data: UserRawData }>("sample/user"); - const { loading, error, data } = useAsync(getUser); - return { loading, error, data: data?.data ?? null }; -}; +export const useGetUser = (userId?: number) => { + const getUser = () => + instance.get<{ data: UserRawData[] }>(`users${userId ? `/${userId}` : ""}`); + const { loading, error, data } = useAsync({ asyncFunction: getUser, enabled: !!userId }); + + const userDataResponse = data?.data?.[0]; + const userData = userDataResponse + ? { + id: userDataResponse.id, + name: userDataResponse.name, + email: userDataResponse.email, + imageSource: userDataResponse.image_source, + } + : DEFAULT_USER; + + return { loading, error, data: userData }; + }; diff --git a/src/type/link.ts b/src/type/link.ts index 63a578e82..0c6051775 100644 --- a/src/type/link.ts +++ b/src/type/link.ts @@ -28,3 +28,21 @@ export type Link = { elapsedTime: string; createdAt: string; }; + +export const formatLinkRawData = ({ + id, + created_at, + updated_at, + url, + image_source, + title, + description, +}: LinkRawData) => ({ + id, + createdAt: created_at, + updatedAt: updated_at, + imageSource: image_source, + url, + title, + description, +}); diff --git a/src/ui/layout/parts/footer/Footer.tsx b/src/ui/layout/parts/footer/Footer.tsx index e5bee3fb4..b67b7b902 100644 --- a/src/ui/layout/parts/footer/Footer.tsx +++ b/src/ui/layout/parts/footer/Footer.tsx @@ -6,29 +6,6 @@ import { forwardRef } from "react"; const cx = classNames.bind(styles); -const snsLinks = [ - { - href: "https://www.facebook.com/", - src: "images/facebook.svg", - alt: "facebook 홈페이지로 연결된 facebook 로고", - }, - { - href: "https://twitter.com/", - src: "images/twitter.svg", - alt: "twitter 홈페이지로 연결된 twitter 로고", - }, - { - href: "https://www.youtube.com/", - src: "images/youtube.svg", - alt: "youtube 홈페이지로 연결된 youtube 로고", - }, - { - href: "https://www.instagram.com/", - src: "images/instagram.svg", - alt: "instagram 홈페이지로 연결된 instagram 로고", - }, -]; - /** * Footer 컴포넌트는 애플리케이션의 하단에 표시되는 footer를 렌더링합니다. * @@ -39,9 +16,10 @@ const snsLinks = [ * ); * * @param {React.Ref} ref - 푸터 요소에 전달할 ref입니다. - * + * * @returns {JSX.Element} 애플리케이션 하단에 표시되는 푸터 컴포넌트입니다. */ + export const Footer = forwardRef((_, ref) => { return (
@@ -56,11 +34,46 @@ export const Footer = forwardRef((_, ref) => {
- {snsLinks.map(({ href, src, alt }) => ( - - {alt} - - ))} + + facebook 홈페이지로 연결된 facebook 로고 + + + twitter 홈페이지로 연결된 twitter 로고 + + + youtube 홈페이지로 연결된 youtube 로고 + + + instagram 홈페이지로 연결된 instagram 로고 +
diff --git a/src/ui/layout/parts/nav/Nav.tsx b/src/ui/layout/parts/nav/Nav.tsx index 628d06b75..1ad8d5a9a 100644 --- a/src/ui/layout/parts/nav/Nav.tsx +++ b/src/ui/layout/parts/nav/Nav.tsx @@ -13,7 +13,7 @@ type NavigationBarProps = { imageSource: string; email: string; } | null; - isSticky: boolean; + isSticky: boolean; }; /** @@ -27,8 +27,8 @@ type NavigationBarProps = { *