From 829755e7d34904c0949f7afad74046fd0b9a4d17 Mon Sep 17 00:00:00 2001
From: whai2
Date: Tue, 9 Apr 2024 16:37:03 +0900
Subject: [PATCH 1/7] =?UTF-8?q?docs:=2015,=2016=EC=A3=BC=EC=B0=A8=20?=
=?UTF-8?q?=EA=B5=AC=ED=98=84=20=EC=82=AC=ED=95=AD=20=EC=A0=95=EB=A6=AC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 63 +++++++++++++++++++++++++-------------------------
docs/README.md | 38 ++++++++++++++++++++++++++++++
2 files changed, 70 insertions(+), 31 deletions(-)
create mode 100644 docs/README.md
diff --git a/README.md b/README.md
index 39a34a4535..35e6961a6b 100644
--- a/README.md
+++ b/README.md
@@ -1,38 +1,39 @@
-# 13주차
+# 15 주차
## 기본 구현 사항
-- [x] TypeScript를 활용해 프로젝트의 필요한 곳에 타입을 명시해 주세요.
-- [x] 검색어를 입력하면 현재 폴더에 있는 링크들 중 “url”, “title”, “description”에 검색어가 포함된 링크들만 필터해서 보이게 해주세요.
-- [x] x 버튼을 클릭하면 입력값이 없던 ui 상태로 돌아갑니다.
+- [ ] 로그인/회원가입시 성공 응답으로 받은 accessToken을 로컬 스토리지에 저장합니다.
+- [ ] 로그인/회원가입 페이지에 접근시 로컬 스토리지에 accessToken이 있는 경우 “/folder” 페이지로 이동합니다.
+- [ ] “회원 가입하기”를 클릭하면 ‘/signup’ 페이지로 이동합니다.
+- [ ] 이메일 input에 placeholder는 “이메일을 입력해 주세요.”비밀번호 input에 placeholder는 “비밀번호를 입력해 주세요.”로 설정해 주세요.
+- [ ] 이메일 input에서 focus out 할 때, 값이 없을 경우 아래에 “이메일을 입력해 주세요.” 에러 메세지를 보입니다.
+- [ ] 이메일 input에서 focus out 할 때, 이메일 형식에 맞지 않는 값이 있는 경우 아래에 “올바른 이메일 주소가 아닙니다.” 에러 메세지를 보입니다.
+- [ ] 비밀번호 input에서 focus out 할 때, 값이 없을 경우 아래에 “비밀번호를 입력해 주세요.” 에러 메세지를 보입니다.
+- [ ] 로그인 실패하는 경우, 이메일 input 아래에 “이메일을 확인해 주세요.”, 비밀번호 input 아래에 “비밀번호를 확인해 주세요.” 에러 메세지를 보입니다.
+- [ ] 로그인 버튼 클릭 또는 Enter키 입력으로 로그인 실행돼야 합니다.
+- [ ] https://bootcamp-api.codeit.kr/docs 에 명세된 “/api/sign-in”으로 { “email”: “test@codeit.com”, “password”: “sprint101” } POST 요청해서 성공 응답을 받으면 “/folder”로 이동합니다.
+- [ ] 소셜 로그인에 구글 아이콘 클릭시 ‘https://www.google.com’카카오 아이콘 클릭시 ‘https://www.kakaocorp.com/page’로 이동하게 해주세요.
+- [ ] 눈 모양 아이콘 클릭시 비밀번호의 문자열이 보이기도 하고, 가려지기도 합니다.
+- [ ] 비밀번호의 문자열이 가려질 때는 눈 모양 아이콘에는 사선이 그어져있고, 비밀번호의 문자열이 보일 때는 사선이 없는 눈 모양 아이콘이 보이도록 합니다.
## 심화 구현 사항
-- [ ] 상단에 있던 링크 추가하기 영역이 가려져 보이지 않을 때 최하단에 링크 추가하기 영역을 고정하도록 만들어 주세요.
-- [ ] 푸터가 시작되는 지점에서는 최하단에 고정된 링크 추가하기 영역이 보이지 않게 해주세요.(IntersectionObserver를 활용해 보세요.)
+- [ ] 로그인, 회원가입 기능에 react-hook-form을 활용해 주세요.
-# 14주차
+# 16 주차
## 기본 구현 사항
-- [x] 기존 React 프로젝트에서 진행했던 작업물을 Next.js 프로젝트에 맞게 변경 및 이전해 주세요.
-- [x] next/link의 Link를 활용해 Linkbrary 아이콘을 클릭하면 ‘/’ 페이지로 이동하게 해주세요.
+- [ ] 링크 공유 페이지의 url path를 ‘/shared’에서 ‘/shared/{folderId}’로 변경해 주세요.
+- [ ] 폴더의 정보는 ‘/api/folders/{folderId}’, 폴더 소유자의 정보는 ‘/api/users/{userId}’를 활용해 주세요.
+- [ ] 링크 공유 페이지에서 폴더의 링크 데이터는 ‘/api/users/{userId}/links?folderId={folderId}’를 사용해 주세요.
+- [ ] 폴더 페이지에서 유저가 access token이 없는 경우 ‘/signin’페이지로 이동하게 해주세요.
+- [ ] 테스트 유저는 id: “codeit@codeit.com”, pw: “sprint101” 를 활용해 보세요.
+- [ ] 폴더 페이지의 url path가 ‘/folder’일 경우 폴더 목록에서 “전체” 가 선택되어 있고, ‘/folder/{folderId}’일 경우 폴더 목록에서 {folderId} 에 해당하는 폴더가 선택되어 있고 폴더에 있는 링크들을 볼 수 있게 해주세요.
+- [ ] 폴더 페이지에서 현재 유저의 폴더 목록 데이터를 받아올 때 ‘/api/folders’를 활용해 주세요.
+- [ ] 폴더 페이지에서 전체 링크 데이터를 받아올 때 ‘/api/links’, 특정 폴더의 링크를 받아올 때 ‘/api/links?folderId={folderId}’를 활용해 주세요.
+- [ ] 유효한 access token이 있는 경우 ‘/api/users’로 현재 로그인한 유저 정보를 받아 상단 네비게이션 유저 프로필을 보이게 해주세요.
-# css 적용
-- [x] css 적용 방식을 선택한다. (css in js vs tailwind)
- -[x] 테일윈드의 경우, 컴포넌트 단위부터 조금씩 바꾼다.
-- [x] css in js를 사용한 경우, 그 이유를 분명히 한다.
-- next는 css in js를 선호하지 않는다. 이를 고찰한다.
-
-# app Router 적용
-- [x] 앱 라우터를 적용한다.
- - [x] pages를 제거한다.
- - [x] pages의 _app.tsx, _documents.tsx 내용은 app/layout.tsx로 이전한다.
- - [x] pages의 index.tsx는 app/page.tsx에 이전한다.
- - [x] styles를 제거한다.
-- [x] 만약, pr 머지 충돌이 일어날 경우, 원격 저장소의 내용을 위와 같은 절차로 제거한다.
-
-# 서버 컴포넌트 사용
-- [x] 데이터를 호출해야 하는 경우, 서버 컴포넌트로 분류한다.
- - [x] 서버 컴포넌트는 클라이언트 컴포넌트에서 호출(import)이 불가능하다. -> {children}으로 호출한다. 이는, 비동기 렌더링을 적용하기 위함이다.
- - [x] useState, useEffect와 같은 생명 주기, 상태를 가질 수 없다. 즉, 1번 렌더링 된다.
-- [x] 클라이언트 컴포넌트와 서버 컴포넌트를 엄격히 분리한다.
+## 심화 구현 사항
+- [ ] 리퀘스트 헤더에 인증 토큰을 첨부할 때 axios interceptors 또는 이와 유사한 기능을 활용해 주세요.
-# 클라이언트 컴포넌트 사용
-- [x] 클라이언트 컴포넌트 내부에서는 데이터를 호출하지 않는다.
-- [x] 컴포넌트 포함 관계를 통해, 서버에서 렌더링이 되고 있는지, 브라우저에서 렌더링이 되고 있는지를 분명히 구별한다. 이를 통해, 웹 사이트를 최적화한다.
\ No newline at end of file
+## 추가 구현 사항
+- [ ] swr 혹은 react-Query를 이용하기.
+- [ ] server actions을 통해, 서버에서 실행하는 로직 분리하기.
+- [ ] 유효성 검사, 중복 검사의 경우, swr 혹은 react-Query의 뮤테이션을 이용하기.
+- [ ] search 부드럽게 적용하기. (spa로 이용)
\ No newline at end of file
diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 0000000000..39a34a4535
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,38 @@
+# 13주차
+## 기본 구현 사항
+- [x] TypeScript를 활용해 프로젝트의 필요한 곳에 타입을 명시해 주세요.
+- [x] 검색어를 입력하면 현재 폴더에 있는 링크들 중 “url”, “title”, “description”에 검색어가 포함된 링크들만 필터해서 보이게 해주세요.
+- [x] x 버튼을 클릭하면 입력값이 없던 ui 상태로 돌아갑니다.
+
+## 심화 구현 사항
+- [ ] 상단에 있던 링크 추가하기 영역이 가려져 보이지 않을 때 최하단에 링크 추가하기 영역을 고정하도록 만들어 주세요.
+- [ ] 푸터가 시작되는 지점에서는 최하단에 고정된 링크 추가하기 영역이 보이지 않게 해주세요.(IntersectionObserver를 활용해 보세요.)
+
+# 14주차
+## 기본 구현 사항
+- [x] 기존 React 프로젝트에서 진행했던 작업물을 Next.js 프로젝트에 맞게 변경 및 이전해 주세요.
+- [x] next/link의 Link를 활용해 Linkbrary 아이콘을 클릭하면 ‘/’ 페이지로 이동하게 해주세요.
+
+# css 적용
+- [x] css 적용 방식을 선택한다. (css in js vs tailwind)
+ -[x] 테일윈드의 경우, 컴포넌트 단위부터 조금씩 바꾼다.
+- [x] css in js를 사용한 경우, 그 이유를 분명히 한다.
+- next는 css in js를 선호하지 않는다. 이를 고찰한다.
+
+# app Router 적용
+- [x] 앱 라우터를 적용한다.
+ - [x] pages를 제거한다.
+ - [x] pages의 _app.tsx, _documents.tsx 내용은 app/layout.tsx로 이전한다.
+ - [x] pages의 index.tsx는 app/page.tsx에 이전한다.
+ - [x] styles를 제거한다.
+- [x] 만약, pr 머지 충돌이 일어날 경우, 원격 저장소의 내용을 위와 같은 절차로 제거한다.
+
+# 서버 컴포넌트 사용
+- [x] 데이터를 호출해야 하는 경우, 서버 컴포넌트로 분류한다.
+ - [x] 서버 컴포넌트는 클라이언트 컴포넌트에서 호출(import)이 불가능하다. -> {children}으로 호출한다. 이는, 비동기 렌더링을 적용하기 위함이다.
+ - [x] useState, useEffect와 같은 생명 주기, 상태를 가질 수 없다. 즉, 1번 렌더링 된다.
+- [x] 클라이언트 컴포넌트와 서버 컴포넌트를 엄격히 분리한다.
+
+# 클라이언트 컴포넌트 사용
+- [x] 클라이언트 컴포넌트 내부에서는 데이터를 호출하지 않는다.
+- [x] 컴포넌트 포함 관계를 통해, 서버에서 렌더링이 되고 있는지, 브라우저에서 렌더링이 되고 있는지를 분명히 구별한다. 이를 통해, 웹 사이트를 최적화한다.
\ No newline at end of file
From 24ce21af3e31e60d47c4a844a978665d80f77a1d Mon Sep 17 00:00:00 2001
From: whai2
Date: Tue, 9 Apr 2024 22:28:20 +0900
Subject: [PATCH 2/7] =?UTF-8?q?feat:=20signin=20=EA=B5=AC=ED=98=84,=20reac?=
=?UTF-8?q?t-hook-form=EC=9D=84=20=EC=9D=B4=EC=9A=A9=ED=95=B4,=20=EC=97=90?=
=?UTF-8?q?=EB=9F=AC=20=EB=AC=B8=EA=B5=AC=20=EC=B2=98=EB=A6=AC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
README.md | 10 +--
app/(sign)/layout.module.scss | 26 ++++++++
app/(sign)/layout.tsx | 16 +++++
app/(sign)/signin/page.tsx | 18 +++++
app/(sign)/signup/page.tsx | 14 ++++
app/shared/page.tsx | 9 +++
components/sign/SignHeader.module.scss | 30 +++++++++
components/sign/SignHeader.tsx | 39 +++++++++++
components/sign/SignInForm.module.scss | 23 +++++++
components/sign/SignInForm.tsx | 66 +++++++++++++++++++
components/sign/SignUpForm.tsx | 0
components/sign/form/Input.module.scss | 38 +++++++++++
components/sign/form/Input.tsx | 39 +++++++++++
.../sign/form/PasswordInput.module.scss | 11 ++++
components/sign/form/PasswordInput.tsx | 61 +++++++++++++++++
lib/constant.ts | 21 ++++++
lib/searchData.ts | 2 +-
package-lock.json | 64 ++++++++++++++++++
package.json | 4 ++
public/eye-off.svg | 4 ++
public/eye-on.svg | 4 ++
styles/colors.scss | 16 +++++
styles/global.scss | 3 +
styles/mixin.scss | 24 +++++++
styles/variables.scss | 4 ++
25 files changed, 540 insertions(+), 6 deletions(-)
create mode 100644 app/(sign)/layout.module.scss
create mode 100644 app/(sign)/layout.tsx
create mode 100644 app/(sign)/signin/page.tsx
create mode 100644 app/(sign)/signup/page.tsx
create mode 100644 components/sign/SignHeader.module.scss
create mode 100644 components/sign/SignHeader.tsx
create mode 100644 components/sign/SignInForm.module.scss
create mode 100644 components/sign/SignInForm.tsx
create mode 100644 components/sign/SignUpForm.tsx
create mode 100644 components/sign/form/Input.module.scss
create mode 100644 components/sign/form/Input.tsx
create mode 100644 components/sign/form/PasswordInput.module.scss
create mode 100644 components/sign/form/PasswordInput.tsx
create mode 100644 lib/constant.ts
create mode 100644 public/eye-off.svg
create mode 100644 public/eye-on.svg
create mode 100644 styles/colors.scss
create mode 100644 styles/global.scss
create mode 100644 styles/mixin.scss
create mode 100644 styles/variables.scss
diff --git a/README.md b/README.md
index 35e6961a6b..341cd22f12 100644
--- a/README.md
+++ b/README.md
@@ -3,10 +3,10 @@
- [ ] 로그인/회원가입시 성공 응답으로 받은 accessToken을 로컬 스토리지에 저장합니다.
- [ ] 로그인/회원가입 페이지에 접근시 로컬 스토리지에 accessToken이 있는 경우 “/folder” 페이지로 이동합니다.
- [ ] “회원 가입하기”를 클릭하면 ‘/signup’ 페이지로 이동합니다.
-- [ ] 이메일 input에 placeholder는 “이메일을 입력해 주세요.”비밀번호 input에 placeholder는 “비밀번호를 입력해 주세요.”로 설정해 주세요.
-- [ ] 이메일 input에서 focus out 할 때, 값이 없을 경우 아래에 “이메일을 입력해 주세요.” 에러 메세지를 보입니다.
-- [ ] 이메일 input에서 focus out 할 때, 이메일 형식에 맞지 않는 값이 있는 경우 아래에 “올바른 이메일 주소가 아닙니다.” 에러 메세지를 보입니다.
-- [ ] 비밀번호 input에서 focus out 할 때, 값이 없을 경우 아래에 “비밀번호를 입력해 주세요.” 에러 메세지를 보입니다.
+- [x] 이메일 input에 placeholder는 “이메일을 입력해 주세요.”비밀번호 input에 placeholder는 “비밀번호를 입력해 주세요.”로 설정해 주세요.
+- [x] 이메일 input에서 focus out 할 때, 값이 없을 경우 아래에 “이메일을 입력해 주세요.” 에러 메세지를 보입니다.
+- [x] 이메일 input에서 focus out 할 때, 이메일 형식에 맞지 않는 값이 있는 경우 아래에 “올바른 이메일 주소가 아닙니다.” 에러 메세지를 보입니다.
+- [x] 비밀번호 input에서 focus out 할 때, 값이 없을 경우 아래에 “비밀번호를 입력해 주세요.” 에러 메세지를 보입니다.
- [ ] 로그인 실패하는 경우, 이메일 input 아래에 “이메일을 확인해 주세요.”, 비밀번호 input 아래에 “비밀번호를 확인해 주세요.” 에러 메세지를 보입니다.
- [ ] 로그인 버튼 클릭 또는 Enter키 입력으로 로그인 실행돼야 합니다.
- [ ] https://bootcamp-api.codeit.kr/docs 에 명세된 “/api/sign-in”으로 { “email”: “test@codeit.com”, “password”: “sprint101” } POST 요청해서 성공 응답을 받으면 “/folder”로 이동합니다.
@@ -15,7 +15,7 @@
- [ ] 비밀번호의 문자열이 가려질 때는 눈 모양 아이콘에는 사선이 그어져있고, 비밀번호의 문자열이 보일 때는 사선이 없는 눈 모양 아이콘이 보이도록 합니다.
## 심화 구현 사항
-- [ ] 로그인, 회원가입 기능에 react-hook-form을 활용해 주세요.
+- [x] 로그인, 회원가입 기능에 react-hook-form을 활용해 주세요.
# 16 주차
## 기본 구현 사항
diff --git a/app/(sign)/layout.module.scss b/app/(sign)/layout.module.scss
new file mode 100644
index 0000000000..babd61725a
--- /dev/null
+++ b/app/(sign)/layout.module.scss
@@ -0,0 +1,26 @@
+@import "@/styles/global.scss";
+
+.container {
+ display: flex;
+ justify-content: center;
+ min-height: 100vh;
+ padding: calc(120 / 844 * 100vh) 3.2rem 5rem;
+ background-color: $color-light-blue;
+
+ @include tablet {
+ padding-top: calc(200 / 982 * 100vh);
+ }
+
+ @include desktop {
+ padding-top: calc(238 / 982 * 100vh);
+ }
+}
+
+.items {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ row-gap: 3rem;
+ width: 100%;
+ max-width: 40rem;
+}
diff --git a/app/(sign)/layout.tsx b/app/(sign)/layout.tsx
new file mode 100644
index 0000000000..f5ab7015de
--- /dev/null
+++ b/app/(sign)/layout.tsx
@@ -0,0 +1,16 @@
+import classNames from "classnames/bind";
+import styles from "./layout.module.scss";
+
+const cx = classNames.bind(styles);
+
+const signLayout = ({ children }: { children: React.ReactNode }) => {
+ return (
+
+
+ {children}
+
+
+ );
+};
+
+export default signLayout;
diff --git a/app/(sign)/signin/page.tsx b/app/(sign)/signin/page.tsx
new file mode 100644
index 0000000000..c91a027572
--- /dev/null
+++ b/app/(sign)/signin/page.tsx
@@ -0,0 +1,18 @@
+import { ROUTE } from "@/lib/constant"
+
+import SignHeader from '@/components/sign/SignHeader'
+import SignInForm from "@/components/sign/SignInForm"
+
+const page = () => {
+ return (
+ <>
+
+
+ >
+ )
+}
+
+export default page
\ No newline at end of file
diff --git a/app/(sign)/signup/page.tsx b/app/(sign)/signup/page.tsx
new file mode 100644
index 0000000000..646ebfad0d
--- /dev/null
+++ b/app/(sign)/signup/page.tsx
@@ -0,0 +1,14 @@
+import { ROUTE } from "@/lib/constant"
+
+import SignHeader from '@/components/sign/SignHeader'
+
+const page = () => {
+ return (
+
+ )
+}
+
+export default page
\ No newline at end of file
diff --git a/app/shared/page.tsx b/app/shared/page.tsx
index e69de29bb2..983ebb85bc 100644
--- a/app/shared/page.tsx
+++ b/app/shared/page.tsx
@@ -0,0 +1,9 @@
+import React from 'react'
+
+const page = () => {
+ return (
+