diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 000000000..b4bfed357
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,3 @@
+{
+ "plugins": ["prettier-plugin-tailwindcss"]
+}
diff --git a/app/global.css b/app/global.css
new file mode 100644
index 000000000..577f1336d
--- /dev/null
+++ b/app/global.css
@@ -0,0 +1,5 @@
+@import '../styles/color.css';
+@import '../styles/reset.css';
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
diff --git a/app/layout.tsx b/app/layout.tsx
new file mode 100644
index 000000000..aa381e463
--- /dev/null
+++ b/app/layout.tsx
@@ -0,0 +1,18 @@
+import QueryProvider from "@/ui/providers/queryProvider";
+import "./global.css";
+import Footer from "@/components/Footer/Footer";
+
+export default function RootLayout({
+ children,
+}: {
+ children: React.ReactNode;
+}) {
+ return (
+
+
+ {children}
+
+
+
+ );
+}
diff --git a/app/login/_components/loginForm.tsx b/app/login/_components/loginForm.tsx
new file mode 100644
index 000000000..ab90de8c1
--- /dev/null
+++ b/app/login/_components/loginForm.tsx
@@ -0,0 +1,129 @@
+"use client";
+
+import { useState } from "react";
+import { Button } from "@/components/Button/Button";
+import { Controller, useForm } from "react-hook-form";
+import { emailPattern } from "@/util/util";
+import AuthInput from "@/components/Input/AuthInput";
+import { signIn } from "next-auth/react";
+import Image from "next/image";
+import eyeIcon from "@/public/eye-on.svg";
+import eyeOffIcon from "@/public/eye_off.svg";
+import { useRouter } from "next/navigation";
+
+export interface FormValueType {
+ id: string;
+ password: string;
+ confirmPassword?: string;
+}
+
+export default function LoginForm() {
+ const [textHidden, setTextHidden] = useState(true);
+ const {
+ handleSubmit,
+ control,
+ setError,
+ formState: { isValid },
+ } = useForm({ mode: "onChange" });
+ const router = useRouter();
+
+ const formAction = async (data: FormValueType) => {
+ const result = await signIn("credentials", {
+ id: data.id,
+ password: data.password,
+ redirect: false,
+ });
+ if (result?.ok) {
+ router.push("/folder");
+ } else if (result?.error) {
+ setError("id", {
+ type: "manual",
+ message: "아이디를 다시 확인해주세요!",
+ });
+ setError("password", {
+ type: "manual",
+ message: "비밀번호를 다시 확인해주세요!",
+ });
+ }
+ };
+
+ const hiddenText = () => {
+ setTextHidden(!textHidden);
+ };
+
+ return (
+
+ );
+}
diff --git a/app/login/page.tsx b/app/login/page.tsx
new file mode 100644
index 000000000..e731bf1af
--- /dev/null
+++ b/app/login/page.tsx
@@ -0,0 +1,57 @@
+import Image from "next/image";
+import Link from "next/link";
+import LoginForm from "./_components/loginForm";
+import LogoIcon from "@/public/logo.svg";
+import kakaoIcon from "@/public/Kakao.svg";
+import googleIcon from "@/public/googleIcon.png";
+
+export default function Login() {
+ return (
+
+
+
+
+
+
+
+
+
회원이 아니신가요?
+
+
+ 회원 가입하기
+
+
+
+
+
+
+
+
+ 소셜 로그인
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/app/sharedFolder/[[...folderId]]/page.tsx b/app/sharedFolder/[[...folderId]]/page.tsx
new file mode 100644
index 000000000..0784ab8e4
--- /dev/null
+++ b/app/sharedFolder/[[...folderId]]/page.tsx
@@ -0,0 +1,23 @@
+import { getFolderData, getFolderList, getUserData } from "@/service/api";
+import SharedFolderInfo from "../_components/SharedFolderInfo";
+import SharedFolderContents from "../_components/SharedFolderContents";
+
+export default async function SharedFolder({
+ params,
+}: {
+ params: { folderId: string };
+}) {
+ const folderInfo = await getFolderData(params.folderId);
+ const folderLink = await getFolderList(params.folderId);
+ const linkList = folderLink?.data ?? [];
+ const owner = await getUserData(folderInfo?.data[0].user_id);
+
+ return (
+ <>
+
+
+
+
+ >
+ );
+}
diff --git a/app/sharedFolder/_components/SharedFolderContents.tsx b/app/sharedFolder/_components/SharedFolderContents.tsx
new file mode 100644
index 000000000..b5d6ec2da
--- /dev/null
+++ b/app/sharedFolder/_components/SharedFolderContents.tsx
@@ -0,0 +1,16 @@
+import { Links } from "@/hooks/useGetFolder";
+import SharedLinkItem from "./SharedLinkItem";
+
+export default function SharedFolderContents({ list }: { list: Links }) {
+ return (
+
+ {list.length > 0 ? (
+ list.map((item) =>
)
+ ) : (
+
+ 저장된 링크가 없습니다.
+
+ )}
+
+ );
+}
diff --git a/app/sharedFolder/_components/SharedFolderInfo.tsx b/app/sharedFolder/_components/SharedFolderInfo.tsx
new file mode 100644
index 000000000..a9c4f20d3
--- /dev/null
+++ b/app/sharedFolder/_components/SharedFolderInfo.tsx
@@ -0,0 +1,35 @@
+import { User } from "@/contexts/UserContext";
+import Image from "next/image";
+
+interface FolderInfoType {
+ id: number;
+ created_at: Date;
+ favorite: boolean;
+ name: string;
+ user_id: number;
+}
+
+export default function SharedFolderInfo({
+ owner,
+ folderInfo,
+}: {
+ owner: User;
+ folderInfo: FolderInfoType;
+}) {
+ return (
+
+
+
+ {owner?.name}
+
+
+ {folderInfo?.name}
+
+
+ );
+}
diff --git a/app/sharedFolder/_components/SharedLinkItem.tsx b/app/sharedFolder/_components/SharedLinkItem.tsx
new file mode 100644
index 000000000..720d1dc81
--- /dev/null
+++ b/app/sharedFolder/_components/SharedLinkItem.tsx
@@ -0,0 +1,46 @@
+import { changeDate, calculateDate } from "@/util/util";
+import Image from "next/image";
+import Link from "next/link";
+import logo from "@/public/logo.svg";
+import { LinkData } from "@/hooks/useGetFolder";
+
+export default async function SharedLinkItem({ item }: { item: LinkData }) {
+ const { url, description, image_source, title } = item;
+ const nowDate = new Date();
+ const createDate = changeDate(new Date(item.created_at));
+ const date = calculateDate(
+ (Number(nowDate) - Number(new Date(item.created_at))) / 1000,
+ );
+
+ return (
+
+
+
+ {image_source ? (
+
+
+
+ ) : (
+
+
+
+ )}
+
+
+
+ {date.time} {date.result} ago
+
+
+ {title ? title : description}
+
+
{createDate}
+
+
+
+ );
+}
diff --git a/app/sharedFolder/layout.tsx b/app/sharedFolder/layout.tsx
new file mode 100644
index 000000000..9d375057e
--- /dev/null
+++ b/app/sharedFolder/layout.tsx
@@ -0,0 +1,23 @@
+import Image from "next/image";
+import Link from "next/link";
+import React from "react";
+import Logo from "@/public/logo.svg";
+
+export default function SharedFolderLayout({
+ children,
+}: {
+ children: React.ReactNode;
+}) {
+ return (
+
+ );
+}
diff --git a/app/signup/_components/signupForm.tsx b/app/signup/_components/signupForm.tsx
new file mode 100644
index 000000000..3c10b9b2b
--- /dev/null
+++ b/app/signup/_components/signupForm.tsx
@@ -0,0 +1,164 @@
+"use client";
+
+import { FormValueType } from "@/app/login/_components/loginForm";
+import { Button } from "@/components/Button/Button";
+import AuthInput from "@/components/Input/AuthInput";
+import { postCheckEmail, postSignUp } from "@/service/api";
+import { emailPattern } from "@/util/util";
+import { useMutation } from "@tanstack/react-query";
+import { useState } from "react";
+import { Controller, useForm } from "react-hook-form";
+
+export default function SignUpForm() {
+ const {
+ handleSubmit,
+ control,
+ watch,
+ setError,
+ formState: { isValid },
+ } = useForm({
+ mode: "onChange",
+ });
+ const [passwordHidden, setPasswordHidden] = useState(true);
+ const [passwordConfirmHidden, setPasswordConfirmHidden] = useState(true);
+ const [isActive, setIsActive] = useState(false);
+
+ const { mutate: checkEmail } = useMutation({
+ mutationFn: (id: string) => postCheckEmail(id),
+ onMutate: () => setIsActive(true),
+ onError: () => {
+ setIsActive(false);
+ setError("id", { type: "manual", message: "이미 가입된 이메일입니다!" });
+ },
+ });
+
+ const { mutate: signUp, isPending: signUpLoading } = useMutation({
+ mutationFn: (user: { id: string; password: string }) =>
+ postSignUp(user.id, user.password),
+ onSuccess: () => (window.location.href = "/signin"),
+ });
+
+ const formAction = async (data: FormValueType) => {
+ signUp(data);
+ };
+
+ return (
+