-
Notifications
You must be signed in to change notification settings - Fork 44
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #409 from HMRyu/part3-유호민-week13
[유호민] Week13
- Loading branch information
Showing
57 changed files
with
3,136 additions
and
802 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,8 @@ | |
/node_modules | ||
/.pnp | ||
.pnp.js | ||
.yarn/install-state.gz | ||
|
||
|
||
# testing | ||
/coverage | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
export default function AddLinkInput() { | ||
return ( | ||
<div className="relative flex justify-center pt-[60px] pb-[90px] px-[24px] lg:px-[300px] bg-[#F0F6FF]"> | ||
<input | ||
placeholder="링크를 추가해 보세요." | ||
className="w-full px-5 py-4 border border-[#6D6AFE] rounded-md" | ||
/> | ||
<button className="absolute right-[30px] top-[70px] lg:right-[310px] lg:top-[70px] px-4 py-2 w-[100px] bg-gradient-to-r from-[#6D6AFE] to-[#6AE3FE] rounded-md text-[#F5F5F5] text-[14px]"> | ||
추가하기 | ||
</button> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,254 @@ | ||
import useUserFolders from "@/hooks/useUserFolders"; | ||
import { useEffect, useState } from "react"; | ||
import Modal from "./Modal"; | ||
import LinkCardListByFolderId from "./LinkCardListByFolderId"; | ||
import useSWR from "swr"; | ||
import { fetcher } from "@/lib/fetcher"; | ||
import axios from "axios"; | ||
|
||
interface UserData { | ||
id: number; | ||
name: string; | ||
email: string; | ||
profileImageSource: string; | ||
} | ||
|
||
interface Folder { | ||
id: number; | ||
created_at: Date; | ||
name: string; | ||
user_id: number; | ||
favorite?: boolean; | ||
} | ||
|
||
interface Link { | ||
id: string; | ||
created_at: Date; | ||
url: string; | ||
title: string; | ||
description: string; | ||
image_source: string; | ||
} | ||
|
||
export default function FolderMain({ | ||
user, | ||
inputValue, | ||
}: { | ||
user: UserData | null; | ||
inputValue: string; | ||
}) { | ||
if (!user) { | ||
return <div>Loading...</div>; | ||
} | ||
const [title, setTitle] = useState<string>("전체"); | ||
const [clickedButton, setClickedButton] = useState<number | null>(0); | ||
const [modalStates, setModalStates] = useState<{ | ||
addModal: boolean; | ||
shareModal: boolean; | ||
editModal: boolean; | ||
deleteModal: boolean; | ||
addLinkModal: boolean; | ||
deleteLinkModal: boolean; | ||
}>({ | ||
addModal: false, | ||
shareModal: false, | ||
editModal: false, | ||
deleteModal: false, | ||
addLinkModal: false, | ||
deleteLinkModal: false, | ||
}); | ||
const [folderId, setFolderId] = useState<number>(0); | ||
const [filteredLinks, setFilteredLinks] = useState<Link[]>([]); | ||
const [originalLinks, setOriginalLinks] = useState<Link[]>([]); | ||
|
||
const { data: folders } = useUserFolders(user.id); | ||
const { data: links } = useSWR( | ||
() => | ||
folderId === 0 | ||
? `https://bootcamp-api.codeit.kr/api/users/${user.id}/links` | ||
: `https://bootcamp-api.codeit.kr/api/users/${user.id}/links?folderId=${folderId}`, | ||
fetcher | ||
); | ||
|
||
const openModal = (modal: keyof typeof modalStates) => { | ||
setModalStates({ ...modalStates, [modal]: true }); | ||
}; | ||
|
||
const closeModal = (modal: keyof typeof modalStates) => { | ||
setModalStates({ ...modalStates, [modal]: false }); | ||
}; | ||
|
||
const handleButtonClick = (folderId: number) => { | ||
setClickedButton(folderId); | ||
const clickedFolder = folders.data.find( | ||
(folder: Folder) => folder.id === folderId | ||
); | ||
if (clickedFolder) { | ||
setFolderId(clickedFolder.id); | ||
setTitle(clickedFolder.name); | ||
} | ||
}; | ||
|
||
const handleAllButtonClick = () => { | ||
setClickedButton(0); | ||
setFolderId(0); | ||
setTitle("전체"); | ||
}; | ||
|
||
const getInputValue = async () => { | ||
const response = await axios.post("/api/input", { inputValue }); | ||
|
||
return response.data; | ||
}; | ||
|
||
const handleFilter = async () => { | ||
if (links) { | ||
const i = await getInputValue(); | ||
const nextLinks = links.data.filter( | ||
(link: any) => | ||
(link.url && link.url.includes(i)) || | ||
(link.title && link.title.includes(i)) || | ||
(link.description && link.description.includes(i)) | ||
); | ||
|
||
setFilteredLinks(nextLinks); | ||
} | ||
}; | ||
|
||
useEffect(() => { | ||
handleFilter(); | ||
}, [inputValue]); | ||
|
||
return ( | ||
<> | ||
<div className="flex items-center justify-between mt-[40px] px-[32px] xl:px-[200px]"> | ||
<div> | ||
<button | ||
className={`px-3 py-2 mr-2 border rounded-md ${ | ||
clickedButton === 0 | ||
? "bg-blue-500 text-white" | ||
: "border-[#6D6AFE] text-black" | ||
}`} | ||
onClick={handleAllButtonClick} | ||
> | ||
전체 | ||
</button> | ||
{folders && | ||
folders.data.map((folder: Folder) => { | ||
return ( | ||
<button | ||
key={folder.id} | ||
className={`px-3 py-2 mr-2 border rounded-md ${ | ||
folder.id === clickedButton | ||
? "bg-blue-500 text-white" | ||
: "border-[#6D6AFE] text-black" | ||
}`} | ||
onClick={() => { | ||
handleButtonClick(folder.id); | ||
}} | ||
> | ||
{folder.name} | ||
</button> | ||
); | ||
})} | ||
</div> | ||
<div | ||
className="text-[#6D6AFE] cursor-pointer" | ||
onClick={() => openModal("addModal")} | ||
> | ||
폴더 추가 + | ||
</div> | ||
<Modal | ||
isOpen={modalStates.addModal} | ||
onClose={() => closeModal("addModal")} | ||
title="폴더 추가" | ||
> | ||
<input | ||
placeholder="내용 입력" | ||
className="px-4 py-5 rounded-md border border-[#6d6afe] bg-[#fff] w-full" | ||
/> | ||
<button className="flex m-auto justify-center w-full px-5 py-4 mt-4 rounded-md text-[#f5f5f5] text-[16px] bg-gradient-to-r from-[#6D6AFE] to-[#6AE3FE]"> | ||
추가하기 | ||
</button> | ||
</Modal> | ||
</div> | ||
<div className="flex items-center justify-between mt-[40px] px-[32px] xl:px-[200px]"> | ||
<div className="text-[30px] font-bold">{title}</div> | ||
<div className="flex space-x-2"> | ||
{title !== "전체" ? ( | ||
<> | ||
<img | ||
src="/images/share.svg" | ||
alt="share" | ||
className="cursor-pointer" | ||
onClick={() => openModal("shareModal")} | ||
/> | ||
<Modal | ||
isOpen={modalStates.shareModal} | ||
onClose={() => closeModal("shareModal")} | ||
title="폴더 공유" | ||
> | ||
<div className="flex justify-center gap-x-5"> | ||
<img | ||
src="/images/kakao.svg" | ||
alt="kakao" | ||
className="bg-[#FEE500] p-4 rounded-full" | ||
/> | ||
<img | ||
src="/images/facebook.svg" | ||
alt="facebook" | ||
className="text-white bg-[#1877F2] p-4 rounded-full" | ||
/> | ||
<img src="/images/link.svg" alt="link" className="p-4" /> | ||
</div> | ||
</Modal> | ||
<img | ||
src="/images/pen.svg" | ||
alt="pen" | ||
className="cursor-pointer" | ||
onClick={() => openModal("editModal")} | ||
/> | ||
<Modal | ||
isOpen={modalStates.editModal} | ||
onClose={() => closeModal("editModal")} | ||
title="폴더 이름 변경" | ||
> | ||
<input | ||
placeholder="내용 입력" | ||
className="px-4 py-5 rounded-md border border-[#6d6afe] bg-[#fff] w-full" | ||
/> | ||
<button className="flex m-auto justify-center w-full px-5 py-4 mt-4 rounded-md text-[#f5f5f5] text-[16px] bg-gradient-to-r from-[#6D6AFE] to-[#6AE3FE]"> | ||
변경하기 | ||
</button> | ||
</Modal> | ||
<img | ||
src="/images/delete.svg" | ||
alt="delete" | ||
className="cursor-pointer" | ||
onClick={() => openModal("deleteModal")} | ||
/> | ||
<Modal | ||
isOpen={modalStates.deleteModal} | ||
onClose={() => closeModal("deleteModal")} | ||
title="폴더 삭제" | ||
> | ||
<button className="flex m-auto justify-center w-full px-5 py-4 mt-4 rounded-md text-[#f5f5f5] text-[16px] bg-[#FF5B56]"> | ||
삭제하기 | ||
</button> | ||
</Modal> | ||
</> | ||
) : null} | ||
</div> | ||
</div> | ||
<LinkCardListByFolderId | ||
links={links?.data} | ||
filteredLinks={filteredLinks} | ||
inputValue={inputValue} | ||
modalStates={modalStates} | ||
setModalStates={setModalStates} | ||
openModal={openModal} | ||
closeModal={closeModal} | ||
/> | ||
</> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
export default function Footer() { | ||
return ( | ||
<div className="flex justify-between items-center mt-[120px] px-[32px] xl:px-[100px] pt-8 pb-[64px] bg-black"> | ||
<div className="text-[#676767]">©codeit - 2023</div> | ||
<div className="flex gap-5"> | ||
<div className="text-[#CFCFCF]">Privacy Policy</div> | ||
<div className="text-[#CFCFCF]">FAQ</div> | ||
</div> | ||
<div className="flex gap-2"> | ||
<img src="/images/facebook.svg" alt="facebook" /> | ||
<img src="/images/twitter.svg" alt="twitter" /> | ||
<img src="/images/youtube.svg" alt="youtube" /> | ||
<img src="/images/instagram.svg" alt="instagram" /> | ||
</div> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
export default function Hero() { | ||
return ( | ||
<div className="flex flex-col justify-center items-center px-[32px] xl:px-[360px] py-[70px] bg-[#F0F6FF]"> | ||
<div className="text-center text-[64px] font-bold"> | ||
<p> | ||
세상의 모든 정보를 <br /> | ||
쉽게 저장하고 관리해 보세요 | ||
</p> | ||
</div> | ||
<button className="my-10 px-5 py-4 w-[350px] bg-gradient-to-r from-[#6D6AFE] to-[#6AE3FE] rounded-md text-[18px] text-white"> | ||
링크 추가하기 | ||
</button> | ||
<img src="/images/hero.png" alt="hero" /> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
export default function LandingDescription() { | ||
return ( | ||
<div className="px-[32px]"> | ||
<div className="flex justify-center items-center mt-[120px]"> | ||
<div> | ||
<div className="text-4xl font-bold"> | ||
원하는 링크를 <br /> | ||
저장하세요. | ||
</div> | ||
<p className="text-sm text-[#6B6B6B] mr-[150px] "> | ||
나중에 읽고 싶은 글, 다시 보고 싶은 영상, <br /> | ||
사고 싶은 옷, 기억하고 싶은 모든 것을 <br />한 공간에 저장하세요. | ||
</p> | ||
</div> | ||
<img src="/images/dog.png" alt="dog" className="w-[400px] h-[300px]" /> | ||
</div> | ||
<div className="flex justify-center items-center mt-[120px]"> | ||
<img | ||
src="/images/edit-folder.png" | ||
alt="edit-folder" | ||
className="w-[400px] h-[300px] mr-[150px]" | ||
/> | ||
<div className="pl-[50px]"> | ||
<div className="text-4xl font-bold"> | ||
링크를 폴더로 <br /> | ||
관리하세요. | ||
</div> | ||
<p className="text-sm text-[#6B6B6B]"> | ||
나만의 폴더를 무제한으로 만들고 <br /> | ||
다양하게 활용할 수 있습니다. | ||
</p> | ||
</div> | ||
</div> | ||
<div className="flex justify-center items-center mt-[120px]"> | ||
<div> | ||
<div className="text-4xl font-bold"> | ||
저장한 링크를 <br /> | ||
공유해 보세요. | ||
</div> | ||
<p className="text-sm text-[#6B6B6B] mr-[150px]"> | ||
여러 링크를 폴더에 담고 공유할 수 있습니다. <br /> | ||
가족, 친구, 동료들에게 쉽고 빠르게 링크를 <br /> | ||
공유해 보세요. | ||
</p> | ||
</div> | ||
<img | ||
src="/images/share-folder.png" | ||
alt="share-folder" | ||
className="w-[400px] h-[300px]" | ||
/> | ||
</div> | ||
<div className="flex justify-center items-center mt-[120px]"> | ||
<img | ||
src="/images/search-folder.png" | ||
alt="search-folder" | ||
className="w-[400px] h-[300px] mr-[150px]" | ||
/> | ||
<div> | ||
<div className="text-4xl font-bold"> | ||
저장한 링크를 <br /> | ||
검색해 보세요. | ||
</div> | ||
<p className="text-sm text-[#6B6B6B]"> | ||
중요한 정보들을 검색으로 쉽게 찾아보세요. | ||
</p> | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
} |
Oops, something went wrong.