Skip to content

Commit

Permalink
Merge pull request #409 from HMRyu/part3-유호민-week13
Browse files Browse the repository at this point in the history
[유호민] Week13
  • Loading branch information
o-seung-yeon authored May 15, 2024
2 parents 0c228dc + 6a6a663 commit 7e58fa2
Show file tree
Hide file tree
Showing 57 changed files with 3,136 additions and 802 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
/node_modules
/.pnp
.pnp.js
.yarn/install-state.gz


# testing
/coverage
Expand Down
13 changes: 13 additions & 0 deletions component/AddLinkInput.tsx
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>
);
}
254 changes: 254 additions & 0 deletions component/FolderMain.tsx
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}
/>
</>
);
}
17 changes: 17 additions & 0 deletions component/Footer.tsx
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>
);
}
16 changes: 16 additions & 0 deletions component/Hero.tsx
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>
);
}
70 changes: 70 additions & 0 deletions component/LandingDescription.tsx
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>
);
}
Loading

0 comments on commit 7e58fa2

Please sign in to comment.