From 964d67d01681e856489c1a404249489c7102026c Mon Sep 17 00:00:00 2001 From: Haneul-Kim <4188989@naver.com> Date: Fri, 8 Dec 2023 19:13:17 +0900 Subject: [PATCH 1/7] =?UTF-8?q?Refactor=20(FolderSelect,=20CardList)=20:?= =?UTF-8?q?=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/Footer/Footer.tsx | 3 +- components/Header/Header.tsx | 15 +-- components/Header/HeaderInput.tsx | 8 +- components/Header/index/HomeHeader.tsx | 4 +- components/Main/Card/CardList.tsx | 92 ------------- components/Main/CardList/Card.styled.tsx | 41 ++++++ components/Main/CardList/Card.tsx | 29 ++++ .../{Card => CardList}/CardList.styled.tsx | 41 +----- components/Main/CardList/CardList.tsx | 29 ++++ components/Main/CardList/CardList.type.ts | 17 +++ .../Main/{Card => CardList}/Kebab.styled.tsx | 0 components/Main/{Card => CardList}/Kebab.tsx | 2 +- .../Main/{Card => CardList}/TimeFlow.tsx | 0 .../FolderCatergory/FolderSelect.styled.tsx | 127 ------------------ .../Main/FolderCatergory/FolderSelect.tsx | 115 ---------------- .../FolderSelect/FolderAddFloat.styled.tsx | 30 +++++ .../Main/FolderSelect/FolderAddFloat.tsx | 12 ++ .../FolderSelect/FolderController.styled.tsx | 30 +++++ .../Main/FolderSelect/FolderController.tsx | 26 ++++ .../Main/FolderSelect/FolderSelect.styled.tsx | 25 ++++ components/Main/FolderSelect/FolderSelect.tsx | 26 ++++ .../Main/FolderSelect/FolderSelect.type.ts | 21 +++ .../Main/FolderSelect/FolderTabs.styled.tsx | 48 +++++++ components/Main/FolderSelect/FolderTabs.tsx | 45 +++++++ .../SearchBar.styled.tsx | 0 .../SearchBar.tsx | 8 +- components/Main/LinkSection.tsx | 6 +- components/Main/index/Section.tsx | 1 + components/Nav/Avatar/Avatar.tsx | 2 +- components/Nav/Avatar/Profile.tsx | 3 +- components/Nav/Navigation.tsx | 18 ++- pages/shared.tsx | 4 +- tsconfig.json | 2 +- utils/validate.ts | 8 +- 34 files changed, 420 insertions(+), 418 deletions(-) delete mode 100644 components/Main/Card/CardList.tsx create mode 100644 components/Main/CardList/Card.styled.tsx create mode 100644 components/Main/CardList/Card.tsx rename components/Main/{Card => CardList}/CardList.styled.tsx (57%) create mode 100644 components/Main/CardList/CardList.tsx create mode 100644 components/Main/CardList/CardList.type.ts rename components/Main/{Card => CardList}/Kebab.styled.tsx (100%) rename components/Main/{Card => CardList}/Kebab.tsx (94%) rename components/Main/{Card => CardList}/TimeFlow.tsx (100%) delete mode 100644 components/Main/FolderCatergory/FolderSelect.styled.tsx delete mode 100644 components/Main/FolderCatergory/FolderSelect.tsx create mode 100644 components/Main/FolderSelect/FolderAddFloat.styled.tsx create mode 100644 components/Main/FolderSelect/FolderAddFloat.tsx create mode 100644 components/Main/FolderSelect/FolderController.styled.tsx create mode 100644 components/Main/FolderSelect/FolderController.tsx create mode 100644 components/Main/FolderSelect/FolderSelect.styled.tsx create mode 100644 components/Main/FolderSelect/FolderSelect.tsx create mode 100644 components/Main/FolderSelect/FolderSelect.type.ts create mode 100644 components/Main/FolderSelect/FolderTabs.styled.tsx create mode 100644 components/Main/FolderSelect/FolderTabs.tsx rename components/Main/{FolderCatergory => FolderSelect}/SearchBar.styled.tsx (100%) rename components/Main/{FolderCatergory => FolderSelect}/SearchBar.tsx (80%) diff --git a/components/Footer/Footer.tsx b/components/Footer/Footer.tsx index cea387838..a6abc54a2 100644 --- a/components/Footer/Footer.tsx +++ b/components/Footer/Footer.tsx @@ -2,9 +2,10 @@ import { Container, Copy, Info, Sns } from "@/components/Footer/Footer.styled"; import { Dom } from "@/hooks/useObserver"; import Image from "next/image"; import Link from "next/link"; +import { MutableRefObject } from "react"; interface Props { - dom?: React.MutableRefObject; + dom?: MutableRefObject; } export default function Footer({ dom }: Props) { diff --git a/components/Header/Header.tsx b/components/Header/Header.tsx index d1aeb346e..1c780d7ae 100644 --- a/components/Header/Header.tsx +++ b/components/Header/Header.tsx @@ -5,19 +5,16 @@ import { URLS } from "@/utils/getData.type"; export default function Header() { const folderName = useData(URLS.SHARED_FOLDERNAME); + if (!folderName) { + return null; + } return ( - {folderName ? ( - <> - - {folderName.owner.name} - {folderName.folderName} - - ) : ( -

폴더 정보를 읽어오는 데 실패했습니다.

- )} + + {folderName.owner.name} + {folderName.folderName}
); diff --git a/components/Header/HeaderInput.tsx b/components/Header/HeaderInput.tsx index c685dd4e5..14554ea93 100644 --- a/components/Header/HeaderInput.tsx +++ b/components/Header/HeaderInput.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { ChangeEvent, FormEvent, MutableRefObject, useState } from "react"; import { Float, Form, Input, InputButton, InputImg, InputWrapper } from "@/components/Header/HeaderInput.styled"; import useData from "@/hooks/useData"; import useModal from "@/hooks/useModal"; @@ -7,7 +7,7 @@ import { URLS } from "@/utils/getData.type"; interface Props { id: number; - dom: React.MutableRefObject; + dom: MutableRefObject; } export default function HeaderSearch({ id, dom }: Props) { @@ -15,14 +15,14 @@ export default function HeaderSearch({ id, dom }: Props) { const { modal, dispatch } = useModal(); const [value, setValue] = useState(""); - const handleModal = (e: React.FormEvent) => { + const handleModal = (e: FormEvent) => { e.preventDefault(); if (folder?.path === URLS.FOLDER_CATEGORY) { dispatch({ title: value, type: "추가하기", data: folder.data }); } }; - const handleChange = (e: React.ChangeEvent) => { + const handleChange = (e: ChangeEvent) => { if (e.target === dom.current.headerInput) { const input = dom.current.headerInput as HTMLInputElement; setValue(input.value); diff --git a/components/Header/index/HomeHeader.tsx b/components/Header/index/HomeHeader.tsx index 550420f15..3305d9f33 100644 --- a/components/Header/index/HomeHeader.tsx +++ b/components/Header/index/HomeHeader.tsx @@ -1,10 +1,8 @@ import { CutLine, StyledHeader, StyledImage, Title, WrapperLink } from "@/components/Header/index/HomeHeader.styled"; import Link from "next/link"; -import { useEffect } from "react"; - -let locate = "/folder"; export default function HomeHeader() { + let locate = "/folder"; const accessToken = typeof window !== "undefined" ? sessionStorage.getItem("accessToken") : null; if (accessToken) { locate = `/folder?a=${accessToken}`; diff --git a/components/Main/Card/CardList.tsx b/components/Main/Card/CardList.tsx deleted file mode 100644 index cbd55ddec..000000000 --- a/components/Main/Card/CardList.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import useData from "@/hooks/useData"; -import { filterFolder, formatDate } from "@/utils/filterAndData"; -import starImg from "@/public/star.svg"; -import TimeFlow from "@/components/Main/Card/TimeFlow"; -import Kebab from "@/components/Main/Card/Kebab"; -import { FolderData, LinkData, SampleLink, URLS } from "@/utils/getData.type"; -import { - ButtonStar, - CardImg, - CardLink, - CardText, - ContainerCardList, - EmptyBox, - H3, - WrapperCardImg, - WrapperTime, -} from "@/components/Main/Card/CardList.styled"; -import { useRouter } from "next/router"; -import Image from "next/image"; - -interface PcardList { - id?: number; - path: URLS.SHARED_FOLDER | URLS.FOLDER_LINKS; -} - -let prev: string | null; - -export default function CardList({ id, path }: PcardList) { - const cardData = useData(path, id); - const folderData = useData(URLS.FOLDER_CATEGORY, id); - - const router = useRouter(); - const searchKeyword = router.query["q"] as string; - const folderId = router.query["folderId"] as string; - const links = filterFolder(cardData, searchKeyword, folderId); - - return links?.length ? ( - - - - ) : ( - 저장된 링크가 없습니다. - ); -} - -interface PcardSet { - folder?: FolderData[]; - links: (SampleLink | LinkData)[]; -} - -function CardSet({ folder, links }: PcardSet) { - return links.map((link) => { - return ( - - - - ); - }); -} - -interface Pcard { - folder?: FolderData[]; - url: string; - imageSource?: string; - image_source?: string; - title: string; - description: string; - createdAt?: string; - created_at?: string; -} - -function Card({ folder, url, imageSource, image_source, title, description, createdAt, created_at }: Pcard) { - return ( - <> - - - - - - - {folder && } - -

{title?.length > 40 ? title.slice(0, 40) + "..." : title}

-

{description?.length > 50 ? description.slice(0, 50) + "..." : description}

-

{formatDate(createdAt ?? (created_at as string))}

-
- - 즐겨찾기에 추가하기 - - - ); -} diff --git a/components/Main/CardList/Card.styled.tsx b/components/Main/CardList/Card.styled.tsx new file mode 100644 index 000000000..153a7d097 --- /dev/null +++ b/components/Main/CardList/Card.styled.tsx @@ -0,0 +1,41 @@ +import styled from "styled-components"; + +export const WrapperCardImg = styled.div` + height: 20.5rem; + margin: 0 auto; + overflow: hidden; + border-top-right-radius: 1.5rem; + border-top-left-radius: 1.5rem; +`; + +export const CardImg = styled.img` + width: 34rem; + height: 100%; + border-radius: 1.5rem 1.5rem 0 0; + object-fit: cover; +`; + +export const CardText = styled.div` + display: flex; + flex-direction: column; + height: 13.5rem; + padding: 1.5rem 2rem; + gap: 1rem; +`; + +export const WrapperTime = styled.div` + display: flex; + justify-content: space-between; + font-size: 1.2rem; + color: var(--Gray5); +`; + +export const H3 = styled.h3` + font-size: 1.4rem; +`; + +export const ButtonStar = styled.button` + position: absolute; + top: 1.5rem; + right: 1.5rem; +`; diff --git a/components/Main/CardList/Card.tsx b/components/Main/CardList/Card.tsx new file mode 100644 index 000000000..5b4054de9 --- /dev/null +++ b/components/Main/CardList/Card.tsx @@ -0,0 +1,29 @@ +import { ButtonStar, CardImg, CardText, H3, WrapperCardImg, WrapperTime } from "@/components/Main/CardList/Card.styled"; +import { CardProps } from "@/components/Main/CardList/CardList.type"; +import Kebab from "@/components/Main/CardList/Kebab"; +import TimeFlow from "@/components/Main/CardList/TimeFlow"; +import { formatDate } from "@/utils/filterAndData"; +import Image from "next/image"; +import starImg from "@/public/star.svg"; + +export default function Card({ folder, url, imageSource, image_source, title, description, createdAt, created_at }: CardProps) { + return ( + <> + + + + + + + {folder && } + +

{title?.length > 40 ? title.slice(0, 40) + "..." : title}

+

{description?.length > 50 ? description.slice(0, 50) + "..." : description}

+

{formatDate(createdAt ?? (created_at as string))}

+
+ + 즐겨찾기에 추가하기 + + + ); +} diff --git a/components/Main/Card/CardList.styled.tsx b/components/Main/CardList/CardList.styled.tsx similarity index 57% rename from components/Main/Card/CardList.styled.tsx rename to components/Main/CardList/CardList.styled.tsx index fd90c810c..911e5cc43 100644 --- a/components/Main/Card/CardList.styled.tsx +++ b/components/Main/CardList/CardList.styled.tsx @@ -1,3 +1,4 @@ +import { CardImg } from "@/components/Main/CardList/Card.styled"; import styled from "styled-components"; export const Absolute = styled.div` @@ -23,29 +24,6 @@ export const ContainerCardList = styled.div` } `; -export const WrapperCardImg = styled.div` - height: 20.5rem; - margin: 0 auto; - overflow: hidden; - border-top-right-radius: 1.5rem; - border-top-left-radius: 1.5rem; -`; - -export const CardImg = styled.img` - width: 34rem; - height: 100%; - border-radius: 1.5rem 1.5rem 0 0; - object-fit: cover; -`; - -export const CardText = styled.div` - display: flex; - flex-direction: column; - height: 13.5rem; - padding: 1.5rem 2rem; - gap: 1rem; -`; - export const CardLink = styled.a` position: relative; display: flex; @@ -62,23 +40,6 @@ export const CardLink = styled.a` } `; -export const WrapperTime = styled.div` - display: flex; - justify-content: space-between; - font-size: 1.2rem; - color: var(--Gray5); -`; - -export const H3 = styled.h3` - font-size: 1.4rem; -`; - -export const ButtonStar = styled.button` - position: absolute; - top: 1.5rem; - right: 1.5rem; -`; - export const EmptyBox = styled.div` display: flex; justify-content: center; diff --git a/components/Main/CardList/CardList.tsx b/components/Main/CardList/CardList.tsx new file mode 100644 index 000000000..8e68bafcf --- /dev/null +++ b/components/Main/CardList/CardList.tsx @@ -0,0 +1,29 @@ +import Card from "@/components/Main/CardList/Card"; +import { CardLink, ContainerCardList, EmptyBox } from "@/components/Main/CardList/CardList.styled"; +import { CardListProps } from "@/components/Main/CardList/CardList.type"; +import useData from "@/hooks/useData"; +import { filterFolder } from "@/utils/filterAndData"; +import { URLS } from "@/utils/getData.type"; +import { useRouter } from "next/router"; + +export default function CardList({ id, path }: CardListProps) { + const cardData = useData(path, id); + const folderData = useData(URLS.FOLDER_CATEGORY, id); + + const router = useRouter(); + const searchKeyword = router.query["q"] as string; + const folderId = router.query["folderId"] as string; + const links = filterFolder(cardData, searchKeyword, folderId); + + return links?.length ? ( + + {links.map((link) => ( + + + + ))} + + ) : ( + 저장된 링크가 없습니다. + ); +} diff --git a/components/Main/CardList/CardList.type.ts b/components/Main/CardList/CardList.type.ts new file mode 100644 index 000000000..2156202bb --- /dev/null +++ b/components/Main/CardList/CardList.type.ts @@ -0,0 +1,17 @@ +import { FolderData, URLS } from "@/utils/getData.type"; + +export interface CardListProps { + id?: number; + path: URLS.SHARED_FOLDER | URLS.FOLDER_LINKS; +} + +export interface CardProps { + folder?: FolderData[]; + url: string; + imageSource?: string; + image_source?: string; + title: string; + description: string; + createdAt?: string; + created_at?: string; +} diff --git a/components/Main/Card/Kebab.styled.tsx b/components/Main/CardList/Kebab.styled.tsx similarity index 100% rename from components/Main/Card/Kebab.styled.tsx rename to components/Main/CardList/Kebab.styled.tsx diff --git a/components/Main/Card/Kebab.tsx b/components/Main/CardList/Kebab.tsx similarity index 94% rename from components/Main/Card/Kebab.tsx rename to components/Main/CardList/Kebab.tsx index 921d9caf8..386e61f3b 100644 --- a/components/Main/Card/Kebab.tsx +++ b/components/Main/CardList/Kebab.tsx @@ -1,6 +1,6 @@ import { useRef } from "react"; import kebabImg from "@/public/kebab.svg"; -import { Container, PopOver } from "@/components/Main/Card/Kebab.styled"; +import { Container, PopOver } from "@/components/Main/CardList/Kebab.styled"; import useModal from "@/hooks/useModal"; import { FolderData } from "@/utils/getData.type"; import Image from "next/image"; diff --git a/components/Main/Card/TimeFlow.tsx b/components/Main/CardList/TimeFlow.tsx similarity index 100% rename from components/Main/Card/TimeFlow.tsx rename to components/Main/CardList/TimeFlow.tsx diff --git a/components/Main/FolderCatergory/FolderSelect.styled.tsx b/components/Main/FolderCatergory/FolderSelect.styled.tsx deleted file mode 100644 index 05afeeee4..000000000 --- a/components/Main/FolderCatergory/FolderSelect.styled.tsx +++ /dev/null @@ -1,127 +0,0 @@ -import styled, { keyframes } from "styled-components"; - -export const Ul = styled.ul` - display: flex; - flex-wrap: wrap; - gap: 0.8rem; - width: 34rem; - padding-left: 0; - - @media screen and (min-width: 768px) { - width: 68rem; - } - - @media screen and (min-width: 1200px) { - width: 106rem; - } -`; - -export const Li = styled.li` - height: 3.2rem; - - display: flex; - align-items: center; - padding: 0.4rem 1rem; - background-color: var(--White); - color: var(--Black); - border: 0.1px solid var(--Primary); - border-radius: 0.5rem; - font-size: 1.4rem; - - &:hover, - &.active { - background-color: var(--Primary); - color: var(--White); - } -`; - -export const BaseButton = styled.button` - display: flex; - align-items: center; - background-color: var(--White); - white-space: nowrap; - border: none; -`; - -export const ButtonAdd = styled(BaseButton)` - display: none; - - @media screen and (min-width: 768px) { - display: flex; - gap: 0.2rem; - height: 3rem; - color: var(--Primary); - } -`; - -export const ButtonControl = styled(BaseButton)` - gap: 0.5rem; - color: var(--Gray4); - font-size: 1.4rem; - font-weight: 600; -`; - -export const scrollDown = keyframes` - 50% { - bottom: 11rem; - } -`; - -export const ButtonFloat = styled(BaseButton)` - animation: ${scrollDown} 1.3s ease-in-out infinite; - position: fixed; - z-index: 2; - bottom: 10.1rem; - padding: 1.2rem 2.4rem; - border-radius: 2rem; - gap: 0.3rem; - background-color: var(--Primary); - color: var(--White); - font-size: 1.6rem; - font-weight: 500; - - &:hover { - background-color: var(--Red); - } - - @media screen and (min-width: 768px) { - display: none; - } -`; - -export const Container = styled.div` - display: flex; - flex-wrap: wrap; - row-gap: 1rem; - width: 34rem; - - @media screen and (min-width: 768px) { - width: 68rem; - flex-wrap: nowrap; - } - - @media screen and (min-width: 1200px) { - width: 106rem; - } -`; - -export const Wrapper = styled.div` - display: flex; - ${({ title }) => title === "전체" && `display: none;`} - gap: 1.2rem; -`; - -export const H1 = styled.h1` - font-size: 2.4rem; - font-weight: 600; - width: 34rem; - padding-left: 0; - - @media screen and (min-width: 768px) { - width: 68rem; - } - - @media screen and (min-width: 1200px) { - width: 106rem; - } -`; diff --git a/components/Main/FolderCatergory/FolderSelect.tsx b/components/Main/FolderCatergory/FolderSelect.tsx deleted file mode 100644 index 473939930..000000000 --- a/components/Main/FolderCatergory/FolderSelect.tsx +++ /dev/null @@ -1,115 +0,0 @@ -import { useState } from "react"; -import useModal from "@/hooks/useModal"; -import useData from "@/hooks/useData"; -import { ButtonAdd, ButtonControl, ButtonFloat, Container, H1, Li, Ul, Wrapper } from "@/components/Main/FolderCatergory/FolderSelect.styled"; -import { URLS } from "@/utils/getData.type"; -import Link from "next/link"; -import Image from "next/image"; - -interface Props { - id: number; -} - -interface IhandleModal { - (e: React.MouseEvent): void; -} - -export default function FolderSelect({ id }: Props) { - const [title, setTitle] = useState("전체"); - const { modal, dispatch } = useModal(); - - const handleModal: IhandleModal = (e) => { - const title = e.currentTarget.parentElement?.title ?? ""; - const type = e.currentTarget.textContent ?? ""; - dispatch({ title, type }); - }; - - return ( - <> - - - - {modal} - - ); -} - -interface Pcategories { - id: number; - setTitle: React.Dispatch>; - handleModal: IhandleModal; -} - -function FolderCategories({ id, setTitle, handleModal }: Pcategories) { - const categories = useData(URLS.FOLDER_CATEGORY, id); - const [prevSelect, setPrevSelect] = useState(); - - const handleClick = (e: React.MouseEvent) => { - prevSelect?.classList.remove("active"); - - const target = e.target as HTMLLIElement; - - setPrevSelect(target); - - target.classList.add("active"); - - if (!target.textContent) return; - setTitle(target.textContent); - }; - - return ( - -
    - -
  • 전체
  • - - {categories?.data?.map((category) => ( - -
  • {category.name}
  • - - ))} -
- - 폴더 추가 - 폴더에 추가하기 - -
- ); -} - -interface Pcontroller extends Pick { - title: string; -} - -function FolderController({ title, handleModal }: Pcontroller) { - return ( - -

{title}

- - - 폴더 공유하기 - 공유 - - - 폴더 이름 바꾸기 - 이름 변경 - - - 폴더 삭제하기 - 삭제 - - -
- ); -} - -interface PaddFloat extends Pick {} - -function FolderAddFloat({ handleModal }: PaddFloat) { - return ( - - 폴더 추가 - 폴더에 추가하기 - - ); -} diff --git a/components/Main/FolderSelect/FolderAddFloat.styled.tsx b/components/Main/FolderSelect/FolderAddFloat.styled.tsx new file mode 100644 index 000000000..c7d33db96 --- /dev/null +++ b/components/Main/FolderSelect/FolderAddFloat.styled.tsx @@ -0,0 +1,30 @@ +import { BaseButton } from "@/components/Main/FolderSelect/FolderSelect.styled"; +import styled, { keyframes } from "styled-components"; + +export const scrollDown = keyframes` + 50% { + bottom: 11rem; + } +`; + +export const ButtonFloat = styled(BaseButton)` + animation: ${scrollDown} 1.3s ease-in-out infinite; + position: fixed; + z-index: 2; + bottom: 10.1rem; + padding: 1.2rem 2.4rem; + border-radius: 2rem; + gap: 0.3rem; + background-color: var(--Primary); + color: var(--White); + font-size: 1.6rem; + font-weight: 500; + + &:hover { + background-color: var(--Red); + } + + @media screen and (min-width: 768px) { + display: none; + } +`; diff --git a/components/Main/FolderSelect/FolderAddFloat.tsx b/components/Main/FolderSelect/FolderAddFloat.tsx new file mode 100644 index 000000000..b2b4a83e2 --- /dev/null +++ b/components/Main/FolderSelect/FolderAddFloat.tsx @@ -0,0 +1,12 @@ +import { ButtonFloat } from "@/components/Main/FolderSelect/FolderAddFloat.styled"; +import { AddFloatProps } from "@/components/Main/FolderSelect/FolderSelect.type"; +import Image from "next/image"; + +export default function FolderAddFloat({ handleModal }: AddFloatProps) { + return ( + + 폴더 추가 + 폴더에 추가하기 + + ); +} diff --git a/components/Main/FolderSelect/FolderController.styled.tsx b/components/Main/FolderSelect/FolderController.styled.tsx new file mode 100644 index 000000000..76679504d --- /dev/null +++ b/components/Main/FolderSelect/FolderController.styled.tsx @@ -0,0 +1,30 @@ +import { BaseButton } from "@/components/Main/FolderSelect/FolderSelect.styled"; +import styled from "styled-components"; + +export const Wrapper = styled.div` + display: flex; + ${({ title }) => title === "전체" && `display: none;`} + gap: 1.2rem; +`; + +export const H1 = styled.h1` + font-size: 2.4rem; + font-weight: 600; + width: 34rem; + padding-left: 0; + + @media screen and (min-width: 768px) { + width: 68rem; + } + + @media screen and (min-width: 1200px) { + width: 106rem; + } +`; + +export const ButtonControl = styled(BaseButton)` + gap: 0.5rem; + color: var(--Gray4); + font-size: 1.4rem; + font-weight: 600; +`; diff --git a/components/Main/FolderSelect/FolderController.tsx b/components/Main/FolderSelect/FolderController.tsx new file mode 100644 index 000000000..fe451462e --- /dev/null +++ b/components/Main/FolderSelect/FolderController.tsx @@ -0,0 +1,26 @@ +import { ButtonControl, H1, Wrapper } from "@/components/Main/FolderSelect/FolderController.styled"; +import { Container } from "@/components/Main/FolderSelect/FolderSelect.styled"; +import { ControllerProps } from "@/components/Main/FolderSelect/FolderSelect.type"; +import Image from "next/image"; + +export default function FolderController({ title, handleModal }: ControllerProps) { + return ( + +

{title}

+ + + 폴더 공유하기 + 공유 + + + 폴더 이름 바꾸기 + 이름 변경 + + + 폴더 삭제하기 + 삭제 + + +
+ ); +} diff --git a/components/Main/FolderSelect/FolderSelect.styled.tsx b/components/Main/FolderSelect/FolderSelect.styled.tsx new file mode 100644 index 000000000..b9c493274 --- /dev/null +++ b/components/Main/FolderSelect/FolderSelect.styled.tsx @@ -0,0 +1,25 @@ +import styled from "styled-components"; + +export const Container = styled.div` + display: flex; + flex-wrap: wrap; + row-gap: 1rem; + width: 34rem; + + @media screen and (min-width: 768px) { + width: 68rem; + flex-wrap: nowrap; + } + + @media screen and (min-width: 1200px) { + width: 106rem; + } +`; + +export const BaseButton = styled.button` + display: flex; + align-items: center; + background-color: var(--White); + white-space: nowrap; + border: none; +`; diff --git a/components/Main/FolderSelect/FolderSelect.tsx b/components/Main/FolderSelect/FolderSelect.tsx new file mode 100644 index 000000000..6e02a1ea8 --- /dev/null +++ b/components/Main/FolderSelect/FolderSelect.tsx @@ -0,0 +1,26 @@ +import FolderAddFloat from "@/components/Main/FolderSelect/FolderAddFloat"; +import FolderController from "@/components/Main/FolderSelect/FolderController"; +import { IhandleModal, Props } from "@/components/Main/FolderSelect/FolderSelect.type"; +import FolderTabs from "@/components/Main/FolderSelect/FolderTabs"; +import useModal from "@/hooks/useModal"; +import { useState } from "react"; + +export default function FolderSelect({ id }: Props) { + const [title, setTitle] = useState("전체"); + const { modal, dispatch } = useModal(); + + const handleModal: IhandleModal = (e) => { + const title = e.currentTarget.parentElement?.title ?? ""; + const type = e.currentTarget.textContent ?? ""; + dispatch({ title, type }); + }; + + return ( + <> + + + + {modal} + + ); +} diff --git a/components/Main/FolderSelect/FolderSelect.type.ts b/components/Main/FolderSelect/FolderSelect.type.ts new file mode 100644 index 000000000..8c6ed6fe0 --- /dev/null +++ b/components/Main/FolderSelect/FolderSelect.type.ts @@ -0,0 +1,21 @@ +import { Dispatch, MouseEvent, SetStateAction } from "react"; + +export interface Props { + id: number; +} + +export interface IhandleModal { + (e: MouseEvent): void; +} + +export interface TabsProps { + id: number; + setTitle: Dispatch>; + handleModal: IhandleModal; +} + +export interface ControllerProps extends Pick { + title: string; +} + +export interface AddFloatProps extends Pick {} diff --git a/components/Main/FolderSelect/FolderTabs.styled.tsx b/components/Main/FolderSelect/FolderTabs.styled.tsx new file mode 100644 index 000000000..348fb04bf --- /dev/null +++ b/components/Main/FolderSelect/FolderTabs.styled.tsx @@ -0,0 +1,48 @@ +import { BaseButton } from "@/components/Main/FolderSelect/FolderSelect.styled"; +import styled from "styled-components"; + +export const Ul = styled.ul` + display: flex; + flex-wrap: wrap; + gap: 0.8rem; + width: 34rem; + padding-left: 0; + + @media screen and (min-width: 768px) { + width: 68rem; + } + + @media screen and (min-width: 1200px) { + width: 106rem; + } +`; + +export const Li = styled.li` + height: 3.2rem; + + display: flex; + align-items: center; + padding: 0.4rem 1rem; + background-color: var(--White); + color: var(--Black); + border: 0.1px solid var(--Primary); + border-radius: 0.5rem; + font-size: 1.4rem; + + &:hover, + &.active { + background-color: var(--Primary); + color: var(--White); + } +`; + +export const ButtonAdd = styled(BaseButton)` + display: none; + + @media screen and (min-width: 768px) { + display: flex; + gap: 0.2rem; + height: 3rem; + color: var(--Primary); + } +`; diff --git a/components/Main/FolderSelect/FolderTabs.tsx b/components/Main/FolderSelect/FolderTabs.tsx new file mode 100644 index 000000000..65d3a4d2b --- /dev/null +++ b/components/Main/FolderSelect/FolderTabs.tsx @@ -0,0 +1,45 @@ +import { ButtonAdd, Li, Ul } from "@/components/Main/FolderSelect/FolderTabs.styled"; +import { Container } from "@/components/Main/FolderSelect/FolderSelect.styled"; +import useData from "@/hooks/useData"; +import { URLS } from "@/utils/getData.type"; +import Image from "next/image"; +import Link from "next/link"; +import { useState } from "react"; +import { TabsProps } from "@/components/Main/FolderSelect/FolderSelect.type"; + +export default function FolderTabs({ id, setTitle, handleModal }: TabsProps) { + const tabs = useData(URLS.FOLDER_CATEGORY, id); + const [prevSelect, setPrevSelect] = useState(); + + const handleClick = (e: React.MouseEvent) => { + prevSelect?.classList.remove("active"); + + const target = e.target as HTMLLIElement; + + setPrevSelect(target); + + target.classList.add("active"); + + if (!target.textContent) return; + setTitle(target.textContent); + }; + + return ( + +
    + +
  • 전체
  • + + {tabs?.data?.map((tab) => ( + +
  • {tab.name}
  • + + ))} +
+ + 폴더 추가 + 폴더에 추가하기 + +
+ ); +} diff --git a/components/Main/FolderCatergory/SearchBar.styled.tsx b/components/Main/FolderSelect/SearchBar.styled.tsx similarity index 100% rename from components/Main/FolderCatergory/SearchBar.styled.tsx rename to components/Main/FolderSelect/SearchBar.styled.tsx diff --git a/components/Main/FolderCatergory/SearchBar.tsx b/components/Main/FolderSelect/SearchBar.tsx similarity index 80% rename from components/Main/FolderCatergory/SearchBar.tsx rename to components/Main/FolderSelect/SearchBar.tsx index feda958d4..483e191bb 100644 --- a/components/Main/FolderCatergory/SearchBar.tsx +++ b/components/Main/FolderSelect/SearchBar.tsx @@ -1,17 +1,17 @@ import { useRouter } from "next/router"; -import { useRef, useState } from "react"; -import { CloseImg, ContainerSearch, SearchImg, SerachInput } from "@/components/Main/FolderCatergory/SearchBar.styled"; +import { ChangeEvent, FormEvent, useRef, useState } from "react"; +import { CloseImg, ContainerSearch, SearchImg, SerachInput } from "@/components/Main/FolderSelect/SearchBar.styled"; export default function SearchBar() { const [value, setValue] = useState(""); const input = useRef(null); const router = useRouter(); - const handleChange = (e: React.ChangeEvent) => { + const handleChange = (e: ChangeEvent) => { setValue(e.target.value); }; - const handleSubmit = (e: React.FormEvent) => { + const handleSubmit = (e: FormEvent) => { e.preventDefault(); const query = router.query; router.push({ diff --git a/components/Main/LinkSection.tsx b/components/Main/LinkSection.tsx index 2545d723d..df81152fa 100644 --- a/components/Main/LinkSection.tsx +++ b/components/Main/LinkSection.tsx @@ -1,6 +1,6 @@ -import CardList from "@/components/Main/Card/CardList"; -import FolderSelect from "@/components/Main/FolderCatergory/FolderSelect"; -import SearchBar from "@/components/Main/FolderCatergory/SearchBar"; +import CardList from "@/components/Main/CardList/CardList"; +import FolderSelect from "@/components/Main/FolderSelect/FolderSelect"; +import SearchBar from "@/components/Main/FolderSelect/SearchBar"; import { URLS } from "@/utils/getData.type"; interface Props { diff --git a/components/Main/index/Section.tsx b/components/Main/index/Section.tsx index 328ae6da0..cf24b1d64 100644 --- a/components/Main/index/Section.tsx +++ b/components/Main/index/Section.tsx @@ -1,4 +1,5 @@ import { StyledImage, StyledSection, Text, Title } from "@/components/Main/index/Section.styled"; +import Image from "next/image"; const TEXT = { link: ["", "원하는 링크", "를 저장하세요", "나중에 읽고 싶은 글, 다시 보고 싶은 영상, 사고 싶은 옷, 기억하고 싶은 모든 것을 한 공간에 저장하세요."], diff --git a/components/Nav/Avatar/Avatar.tsx b/components/Nav/Avatar/Avatar.tsx index bf78ca6c9..ea80376dc 100644 --- a/components/Nav/Avatar/Avatar.tsx +++ b/components/Nav/Avatar/Avatar.tsx @@ -9,7 +9,7 @@ interface AvatarProps { export default function Avatar({ id }: AvatarProps) { const router = useRouter(); - const pathname = router.asPath; + const pathname = router.pathname; const type = pathname === "/shared" ? URLS.SHARED_USER : URLS.FOLDER_USER; const userData = useData(type, id); diff --git a/components/Nav/Avatar/Profile.tsx b/components/Nav/Avatar/Profile.tsx index e9c478c76..0462572f4 100644 --- a/components/Nav/Avatar/Profile.tsx +++ b/components/Nav/Avatar/Profile.tsx @@ -1,4 +1,5 @@ import { Container, ProfileImg, ProfileText } from "@/components/Nav/Avatar/Profile.styled"; +import defaultProfileImg from "@/public/Avatar.png"; interface Props { profileImg: string; @@ -8,7 +9,7 @@ interface Props { export default function Profile({ profileImg, email }: Props) { return ( - + {email} ); diff --git a/components/Nav/Navigation.tsx b/components/Nav/Navigation.tsx index da8696b91..f0a44a9e8 100644 --- a/components/Nav/Navigation.tsx +++ b/components/Nav/Navigation.tsx @@ -18,18 +18,22 @@ export default function Navigation({ id, $page = "" }: Props) { if (accessToken) { locate = `/folder?a=${accessToken}`; } + + const Login = () => + $page === "/" ? ( + + 로그인 + + ) : ( + + ); + return ( <> ); diff --git a/pages/shared.tsx b/pages/shared.tsx index f15cb0383..8f7f46f6a 100644 --- a/pages/shared.tsx +++ b/pages/shared.tsx @@ -1,8 +1,8 @@ import Footer from "@/components/Footer/Footer"; import Header from "@/components/Header/Header"; import Main from "@/components/Main/Main"; -import CardList from "@/components/Main/Card/CardList"; -import SearchBar from "@/components/Main/FolderCatergory/SearchBar"; +import CardList from "@/components/Main/CardList/CardList"; +import SearchBar from "@/components/Main/FolderSelect/SearchBar"; import { URLS } from "@/utils/getData.type"; import Navigation from "@/components/Nav/Navigation"; diff --git a/tsconfig.json b/tsconfig.json index 1ddf0b124..63ceccb60 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -17,6 +17,6 @@ "@/*": ["./*"] } }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "next.config.js"], "exclude": ["node_modules"] } diff --git a/utils/validate.ts b/utils/validate.ts index aad5f3449..9398a2d82 100644 --- a/utils/validate.ts +++ b/utils/validate.ts @@ -67,18 +67,12 @@ const pipe = for (const f of iter) { const res = f(acc); if (typeof res === "string") return res; - if (res instanceof Promise) return res.then(recursive); + if (res instanceof Promise) return res.then(recursive).catch((e) => Promise.reject(e)); } return ""; })(init); }; -// funcs.reduce((acc, func, i, arr) => { -// const res = func(acc); -// if (typeof res === "string") return arr.splice(1), res as unknown as Obj; -// return res; -// }, init); - export const validate_signin = pipe(isValue, isReg); export const validate_signup = pipe(isValue, isReg, isSameEmail, isSamePassword); From 0cdc1be8e483928eb97b6f4030fd142c9d4799c4 Mon Sep 17 00:00:00 2001 From: Haneul-Kim <4188989@naver.com> Date: Sat, 9 Dec 2023 09:03:10 +0900 Subject: [PATCH 2/7] =?UTF-8?q?Refactor=20(constant/path.ts)=20:=20enum=20?= =?UTF-8?q?URLS=20=EC=82=AD=EC=A0=9C,=20js=EA=B0=9D=EC=B2=B4=EB=A1=9C=20?= =?UTF-8?q?=EB=B0=94=EA=BF=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/Footer/Footer.tsx | 4 +- components/Header/Header.tsx | 4 +- components/Header/HeaderInput.tsx | 6 +-- components/Main/CardList/CardList.tsx | 4 +- components/Main/CardList/CardList.type.ts | 5 ++- components/Main/FolderSelect/FolderTabs.tsx | 2 +- components/Main/LinkSection.tsx | 2 +- components/Nav/Avatar/Avatar.tsx | 4 +- components/Nav/Navigation.tsx | 5 +-- constants/path.ts | 9 +++++ hooks/useData.ts | 15 +++---- pages/shared.tsx | 4 +- utils/filterAndData.ts | 7 ++-- utils/getData.ts | 17 ++++---- utils/getData.type.ts | 44 +++++++++------------ 15 files changed, 68 insertions(+), 64 deletions(-) create mode 100644 constants/path.ts diff --git a/components/Footer/Footer.tsx b/components/Footer/Footer.tsx index a6abc54a2..cafd1cbfe 100644 --- a/components/Footer/Footer.tsx +++ b/components/Footer/Footer.tsx @@ -12,7 +12,9 @@ export default function Footer({ dom }: Props) { return ( { - dom && (dom.current.footer = el); + if (dom) { + dom.current.footer = el; + } }} > ©codeit - 2023 diff --git a/components/Header/Header.tsx b/components/Header/Header.tsx index 1c780d7ae..a56c349ac 100644 --- a/components/Header/Header.tsx +++ b/components/Header/Header.tsx @@ -1,10 +1,10 @@ import defaultAvatar from "@/public/Avatar.png"; import useData from "@/hooks/useData"; import { Container, User, UserImg, UserText, UserTitle } from "@/components/Header/Header.styled"; -import { URLS } from "@/utils/getData.type"; +import { PATHS } from "@/constants/path"; export default function Header() { - const folderName = useData(URLS.SHARED_FOLDERNAME); + const folderName = useData(PATHS.SHARED_FOLDERNAME); if (!folderName) { return null; } diff --git a/components/Header/HeaderInput.tsx b/components/Header/HeaderInput.tsx index 14554ea93..18fb1f4fb 100644 --- a/components/Header/HeaderInput.tsx +++ b/components/Header/HeaderInput.tsx @@ -3,7 +3,7 @@ import { Float, Form, Input, InputButton, InputImg, InputWrapper } from "@/compo import useData from "@/hooks/useData"; import useModal from "@/hooks/useModal"; import { Dom } from "@/hooks/useObserver"; -import { URLS } from "@/utils/getData.type"; +import { PATHS } from "@/constants/path"; interface Props { id: number; @@ -11,13 +11,13 @@ interface Props { } export default function HeaderSearch({ id, dom }: Props) { - const folder = useData(URLS.FOLDER_CATEGORY, id); + const folder = useData(PATHS.FOLDER_CATEGORY, id); const { modal, dispatch } = useModal(); const [value, setValue] = useState(""); const handleModal = (e: FormEvent) => { e.preventDefault(); - if (folder?.path === URLS.FOLDER_CATEGORY) { + if (folder.path === PATHS.FOLDER_CATEGORY) { dispatch({ title: value, type: "추가하기", data: folder.data }); } }; diff --git a/components/Main/CardList/CardList.tsx b/components/Main/CardList/CardList.tsx index 8e68bafcf..05f4b06d7 100644 --- a/components/Main/CardList/CardList.tsx +++ b/components/Main/CardList/CardList.tsx @@ -1,14 +1,14 @@ import Card from "@/components/Main/CardList/Card"; import { CardLink, ContainerCardList, EmptyBox } from "@/components/Main/CardList/CardList.styled"; import { CardListProps } from "@/components/Main/CardList/CardList.type"; +import { PATHS } from "@/constants/path"; import useData from "@/hooks/useData"; import { filterFolder } from "@/utils/filterAndData"; -import { URLS } from "@/utils/getData.type"; import { useRouter } from "next/router"; export default function CardList({ id, path }: CardListProps) { const cardData = useData(path, id); - const folderData = useData(URLS.FOLDER_CATEGORY, id); + const folderData = useData(PATHS.FOLDER_CATEGORY, id); const router = useRouter(); const searchKeyword = router.query["q"] as string; diff --git a/components/Main/CardList/CardList.type.ts b/components/Main/CardList/CardList.type.ts index 2156202bb..731c2a3df 100644 --- a/components/Main/CardList/CardList.type.ts +++ b/components/Main/CardList/CardList.type.ts @@ -1,8 +1,9 @@ -import { FolderData, URLS } from "@/utils/getData.type"; +import { FolderData } from "@/utils/getData.type"; +import { PATHS } from "@/constants/path"; export interface CardListProps { id?: number; - path: URLS.SHARED_FOLDER | URLS.FOLDER_LINKS; + path: typeof PATHS.SHARED_FOLDER | typeof PATHS.FOLDER_LINKS; } export interface CardProps { diff --git a/components/Main/FolderSelect/FolderTabs.tsx b/components/Main/FolderSelect/FolderTabs.tsx index 65d3a4d2b..ff06583b3 100644 --- a/components/Main/FolderSelect/FolderTabs.tsx +++ b/components/Main/FolderSelect/FolderTabs.tsx @@ -1,11 +1,11 @@ import { ButtonAdd, Li, Ul } from "@/components/Main/FolderSelect/FolderTabs.styled"; import { Container } from "@/components/Main/FolderSelect/FolderSelect.styled"; import useData from "@/hooks/useData"; -import { URLS } from "@/utils/getData.type"; import Image from "next/image"; import Link from "next/link"; import { useState } from "react"; import { TabsProps } from "@/components/Main/FolderSelect/FolderSelect.type"; +import { URLS } from "@/constants/path"; export default function FolderTabs({ id, setTitle, handleModal }: TabsProps) { const tabs = useData(URLS.FOLDER_CATEGORY, id); diff --git a/components/Main/LinkSection.tsx b/components/Main/LinkSection.tsx index df81152fa..920b83d7b 100644 --- a/components/Main/LinkSection.tsx +++ b/components/Main/LinkSection.tsx @@ -1,7 +1,7 @@ import CardList from "@/components/Main/CardList/CardList"; import FolderSelect from "@/components/Main/FolderSelect/FolderSelect"; import SearchBar from "@/components/Main/FolderSelect/SearchBar"; -import { URLS } from "@/utils/getData.type"; +import { URLS } from "@/constants/path"; interface Props { id: number; diff --git a/components/Nav/Avatar/Avatar.tsx b/components/Nav/Avatar/Avatar.tsx index ea80376dc..f640d31a6 100644 --- a/components/Nav/Avatar/Avatar.tsx +++ b/components/Nav/Avatar/Avatar.tsx @@ -1,6 +1,6 @@ import Profile from "@/components/Nav/Avatar/Profile"; +import { PATHS } from "@/constants/path"; import useData from "@/hooks/useData"; -import { URLS } from "@/utils/getData.type"; import { useRouter } from "next/router"; interface AvatarProps { @@ -10,7 +10,7 @@ interface AvatarProps { export default function Avatar({ id }: AvatarProps) { const router = useRouter(); const pathname = router.pathname; - const type = pathname === "/shared" ? URLS.SHARED_USER : URLS.FOLDER_USER; + const type = pathname === "/shared" ? PATHS.SHARED_USER : PATHS.FOLDER_USER; const userData = useData(type, id); return ; diff --git a/components/Nav/Navigation.tsx b/components/Nav/Navigation.tsx index f0a44a9e8..c3e06c214 100644 --- a/components/Nav/Navigation.tsx +++ b/components/Nav/Navigation.tsx @@ -1,10 +1,7 @@ import Avatar from "@/components/Nav/Avatar/Avatar"; import Logo from "@/components/Nav/Avatar/Logo"; -import { Background, Nav, StyledLink } from "@/components/Nav/Navigation.styled"; -import { Url } from "next/dist/shared/lib/router/router"; +import { Background, Nav } from "@/components/Nav/Navigation.styled"; import Link from "next/link"; -import { useRouter } from "next/router"; -import { useEffect, useRef } from "react"; interface Props { id?: number; diff --git a/constants/path.ts b/constants/path.ts new file mode 100644 index 000000000..8010d96e8 --- /dev/null +++ b/constants/path.ts @@ -0,0 +1,9 @@ +export const PATHS = { + SHARED_USER: "SHARED_USER", + SHARED_FOLDER: "SHARED_FOLDER", + SHARED_FOLDERNAME: "SHARED_FOLDERNAME", + FOLDER_USER: "FOLDER_USER", + FOLDER_CATEGORY: "FOLDER_CATEGORY", + FOLDER_LINKS: "FOLDER_LINKS", + DEFAULT: "DEFAULT", +} as const; diff --git a/hooks/useData.ts b/hooks/useData.ts index ba1ca1bdf..eb15eeff3 100644 --- a/hooks/useData.ts +++ b/hooks/useData.ts @@ -1,31 +1,32 @@ import { useCallback, useEffect, useState } from "react"; import { getData } from "@/utils/getData"; -import { Action, Rgeneric, URLS, UrlType } from "@/utils/getData.type"; +import { Action, Rgeneric, UrlType } from "@/utils/getData.type"; +import { PATHS } from "@/constants/path"; export const reduceData = (action: Action) => { switch (action.path) { - case URLS.SHARED_USER: + case PATHS.SHARED_USER: const { id, name, email, profileImageSource: profileImg } = action; return { path: action.path, id, name, email, profileImg } as Rgeneric; - case URLS.SHARED_FOLDER: + case PATHS.SHARED_FOLDER: const { folder: { links }, } = action; return { path: action.path, links } as Rgeneric; - case URLS.SHARED_FOLDERNAME: + case PATHS.SHARED_FOLDERNAME: const { folder: { name: folderName, owner }, } = action; return { path: action.path, folderName, owner } as Rgeneric; - case URLS.FOLDER_USER: { + case PATHS.FOLDER_USER: { const { data: [{ id, name, email, image_source: profileImg }], } = action; return { path: action.path, id, name, email, profileImg } as Rgeneric; } - case URLS.FOLDER_CATEGORY: + case PATHS.FOLDER_CATEGORY: return action as Rgeneric; - case URLS.FOLDER_LINKS: { + case PATHS.FOLDER_LINKS: { const { data: links } = action; return { path: action.path, links } as Rgeneric; } diff --git a/pages/shared.tsx b/pages/shared.tsx index 8f7f46f6a..31f00d0df 100644 --- a/pages/shared.tsx +++ b/pages/shared.tsx @@ -3,8 +3,8 @@ import Header from "@/components/Header/Header"; import Main from "@/components/Main/Main"; import CardList from "@/components/Main/CardList/CardList"; import SearchBar from "@/components/Main/FolderSelect/SearchBar"; -import { URLS } from "@/utils/getData.type"; import Navigation from "@/components/Nav/Navigation"; +import { PATHS } from "@/constants/path"; export default function SharedPage() { return ( @@ -13,7 +13,7 @@ export default function SharedPage() {
- +