-
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.
* fix: 로그인 유무에 의한 페이지 리다이렉션 설정 * fix: userContext 분리 provider 컴포넌트 생성, 커스텀훅 구현 * fix: react hook form 타입 지정 * fix: react-hook-form정상적용 * feat: 리액트 쿼리 설치 및 세팅 * refactor: user context 데이터 react-query로 변경 * refactor: 폴더 리스트 페이지 전체 로직 리팩토링 * feat: 폴더 리스트 리액트 쿼리로 변경 * feat: 링크 리스트 리액트 쿼리 적용 * feat: 검색 기능, debounce기능 추가 * refactor: 로그인전 user정보 리퀘스트 방지 * feat: 로그인 페이지 리액트 쿼리 적용 * refactor: 링크 공유 페이지 리팩토링 * feat: 회원가입 페이지 리액트 쿼리 적용 및 react-hook-form 리팩토링 * refactor: 로그인 페이지 버튼 disabled 옵션 추가 및 스타일 변경 * refactor: 로딩 컴포넌트 포탈에서 렌더링, 페이지 최상단에 위치설정 * refactor: 회원가입 버튼 disabled 옵션 추가 및 로그인 로직 수정 * feat: 폴더 추가 리액트 쿼리 적용, 생성시 refetch설정 * feat: 폴더이름 변경 리액트 쿼리 적용 * fix: api주소 변경으로 인한 코드 수정 * fix: 검색기능 수정 * feat: shared페이지 리액트 쿼리 적용 * fix: 카드 케밥 메뉴, 즐겨찾기 아이콘 설정 * feat: 링크 추가 기능 리액트 쿼리 적용 및 사용자 편의성 개선 * refactor: 카드 리스트 렌더링 오류, 디펜던시값 추가 * feat: 링크 삭제 기능 리액트 쿼리 적용 * feat: 링크 삭제 기능 리액트 쿼리 적용 * refactor: api 리스폰스 도착전 버튼 비활성화 설정 * feat: 링크 즐겨찾기 기능 구현 및 옵티미스틱 업데이트 구현 * refactor: 링크 데이터 로직 리팩토링 * refactor: 즐겨찾기 폴더 수정, 삭제 버튼 제거 * fix: 빌드 오류 캐시 데이터 타입 지정 및 공유 페이지 수정 * fix: 모달 외부 클릭, esc클릭시 모달 close, 케밥 close 옵션 수정 * fix: 링크 추가시 인풋 value 초기화 * feat: nextAuth 적용, 미들웨어 적용, 로그인 로직 리액트 쿼리 삭제 * refactor: 로그인 페이지 앱라우터로 리펙토링 * refactor: 회원가입 페이지 앱라우터로 마이그레이션 * refactor: 공유 페이지 앱라우터로 리팩토링 * fix: 폴더 공유 링크 수정 * fix: 링크 경로 수정
- Loading branch information
Showing
68 changed files
with
2,855 additions
and
1,149 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 |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"plugins": ["prettier-plugin-tailwindcss"] | ||
} |
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,5 @@ | ||
@import '../styles/color.css'; | ||
@import '../styles/reset.css'; | ||
@tailwind base; | ||
@tailwind components; | ||
@tailwind utilities; |
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,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 ( | ||
<html lang="ko"> | ||
<body> | ||
<QueryProvider>{children}</QueryProvider> | ||
<Footer /> | ||
</body> | ||
</html> | ||
); | ||
} |
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,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<FormValueType>({ 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 ( | ||
<form | ||
className="flex flex-col justify-start gap-[1rem]" | ||
onSubmit={handleSubmit(formAction)} | ||
> | ||
<div className="gap--[1.2rem] relative flex flex-col items-start"> | ||
<Controller | ||
name="id" | ||
control={control} | ||
rules={{ | ||
required: "이메일을 입력해주세요!", | ||
pattern: { | ||
value: emailPattern, | ||
message: "이메일 형식이 아닙니다!", | ||
}, | ||
}} | ||
render={({ | ||
field: { value, onChange, onBlur }, | ||
fieldState: { error }, | ||
}) => ( | ||
<AuthInput | ||
id="email" | ||
label="이메일" | ||
value={value} | ||
onChange={onChange} | ||
onBlur={onBlur} | ||
type="text" | ||
placeholder="이메일" | ||
size="md" | ||
error={error} | ||
/> | ||
)} | ||
/> | ||
</div> | ||
<div className="gap--[1.2rem] relative flex flex-col items-start"> | ||
<Controller | ||
name="password" | ||
control={control} | ||
rules={{ | ||
required: "비밀번호를 입력해주세요!", | ||
}} | ||
render={({ | ||
field: { value, onChange, onBlur }, | ||
fieldState: { error }, | ||
}) => ( | ||
<AuthInput | ||
id="password" | ||
label="비밀번호" | ||
value={value} | ||
onChange={onChange} | ||
onBlur={onBlur} | ||
type={textHidden ? "password" : "text"} | ||
placeholder="비밀번호" | ||
size="md" | ||
error={error} | ||
/> | ||
)} | ||
/> | ||
<div | ||
className="absolute right-[1.5rem] top-[5.5rem] m-0 cursor-pointer border-none p-0" | ||
onClick={hiddenText} | ||
> | ||
<Image | ||
src={textHidden ? eyeOffIcon : eyeIcon} | ||
width={16} | ||
height={16} | ||
alt="눈 아이콘" | ||
/> | ||
</div> | ||
</div> | ||
<Button size={"lg"} type="submit" buttonActive={!isValid}> | ||
로그인 | ||
</Button> | ||
</form> | ||
); | ||
} |
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,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 ( | ||
<div className="flex h-[100vh] flex-col items-center justify-center bg-[--Background] p-[3.2rem]"> | ||
<div className="flex flex-col content-center items-center gap-[3.2rem]"> | ||
<div className="flex flex-col items-center justify-center gap-[3rem]"> | ||
<div className="flex flex-col justify-center gap-[1.6rem]"> | ||
<Link href="/"> | ||
<Image src={LogoIcon} alt="메인로고" width={210} height={38} /> | ||
</Link> | ||
<div className="flex items-center justify-center gap-[0.8rem]"> | ||
<span className="text-[1.6rem]">회원이 아니신가요?</span> | ||
<Link href="/signup" style={{ textDecoration: "none" }}> | ||
<p className="text-[1.6rem] font-[600] text-[--Primary]"> | ||
회원 가입하기 | ||
</p> | ||
</Link> | ||
</div> | ||
</div> | ||
<LoginForm /> | ||
</div> | ||
<div className="flex w-[40rem] items-center justify-between rounded-[0.8rem] border border-solid border-[--Linkbrary-gray20] bg-[--Linkbrary-gray10] px-[2.4rem] py-[1.2rem]"> | ||
<p className="text-[1.4rem] font-[--Linkbrary-gray100]"> | ||
소셜 로그인 | ||
</p> | ||
<div className="flex items-center justify-normal gap-[1.6rem]"> | ||
<Link | ||
href="https://www.google.com/" | ||
target="_blank" | ||
className="flex h-[4.2rem] w-[4.2rem] items-center justify-center rounded-full bg-[--Section-white]" | ||
> | ||
<Image src={googleIcon} alt="구글아이콘" width={22} height={22} /> | ||
</Link> | ||
<Link | ||
href="https://www.kakaocorp.com/page/" | ||
target="_blank" | ||
className="flex h-[4.2rem] w-[4.2rem] items-center justify-center rounded-full bg-[--Kakao-logo-color]" | ||
> | ||
<Image | ||
src={kakaoIcon} | ||
alt="카카오아이콘" | ||
width={26} | ||
height={24} | ||
/> | ||
</Link> | ||
</div> | ||
</div> | ||
</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,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 ( | ||
<> | ||
<SharedFolderInfo owner={owner.data[0]} folderInfo={folderInfo.data[0]} /> | ||
<div className="mx-auto my-0 flex max-w-[106rem] flex-col items-center justify-center py-[5rem]"> | ||
<SharedFolderContents list={linkList} /> | ||
</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 @@ | ||
import { Links } from "@/hooks/useGetFolder"; | ||
import SharedLinkItem from "./SharedLinkItem"; | ||
|
||
export default function SharedFolderContents({ list }: { list: Links }) { | ||
return ( | ||
<div className="relative mx-auto my-0 grid gap-[2rem] sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3"> | ||
{list.length > 0 ? ( | ||
list.map((item) => <SharedLinkItem item={item} key={item.id} />) | ||
) : ( | ||
<div className="flex h-[50vh] flex-col items-center justify-center py-[8rem]"> | ||
저장된 링크가 없습니다. | ||
</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,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 ( | ||
<div className="flex w-full flex-col items-center justify-center bg-[--Background] pb-[6rem] pt-[2rem]"> | ||
<Image | ||
src={owner?.image_source} | ||
alt="owner 이미지" | ||
width={60} | ||
height={60} | ||
/> | ||
<p className="mt-[1.2rem] h-[2.4rem] text-[1.6rem] font-[400] leading-[2.4rem]"> | ||
{owner?.name} | ||
</p> | ||
<p className="mt-[2rem] h-[5.5rem] text-[4rem] font-[600] leading-normal"> | ||
{folderInfo?.name} | ||
</p> | ||
</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,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 ( | ||
<Link href={url} target="_blank" rel="noreferrer"> | ||
<div className="relative flex w-[34rem] flex-col items-center rounded-[1.5rem] text-[1.6rem] no-underline shadow-[0_5px_25px_0px_rgba(0,0,0,0.3)]"> | ||
<div className="flex h-[23.5rem] w-full flex-col items-center overflow-hidden rounded-[1.5rem_1.5rem_0_0]"> | ||
{image_source ? ( | ||
<div className="relative h-full w-full transition ease-in hover:scale-[170%]"> | ||
<Image | ||
src={image_source} | ||
alt="카드 이미지" | ||
fill | ||
objectFit="cover" | ||
/> | ||
</div> | ||
) : ( | ||
<div> | ||
<Image src={logo} alt="빈 이미지" width={133} height={24} /> | ||
</div> | ||
)} | ||
</div> | ||
<div className="relative flex w-full flex-col gap-[1rem] rounded-b-[1.5rem] bg-[--Section-white] px-[2rem] py-[1.5rem]"> | ||
<p className="text-[1.3rem] text-[--Description]"> | ||
{date.time} {date.result} ago | ||
</p> | ||
<p className="overflow-hidden text-ellipsis whitespace-nowrap text-[1.4rem]"> | ||
{title ? title : description} | ||
</p> | ||
<p className="h-[2.4rem] text-[1.4rem]">{createDate}</p> | ||
</div> | ||
</div> | ||
</Link> | ||
); | ||
} |
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,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 ( | ||
<div> | ||
<div className="sticky top-0 z-10 w-full bg-[--Background] px-[3.2rem] py-[2rem] lg:px-[20rem]"> | ||
<div className="flex w-fit flex-col items-start justify-center"> | ||
<Link href="/folder"> | ||
<Image src={Logo} alt="메인 로고" width={133} height={24} /> | ||
</Link> | ||
</div> | ||
</div> | ||
{children} | ||
</div> | ||
); | ||
} |
Oops, something went wrong.