From 3853580562f0f2d1cd7bc0522ae4468df773c3fb Mon Sep 17 00:00:00 2001 From: MELATONIN99 Date: Mon, 19 Aug 2024 21:32:16 +0900 Subject: [PATCH 1/3] =?UTF-8?q?refactor.=20=EC=BD=94=EB=93=9C=EB=A6=AC?= =?UTF-8?q?=EB=B7=B0=20=EB=B0=98=EC=98=81=ED=95=9C=20=EC=88=98=EC=A0=80?= =?UTF-8?q?=EC=82=AC=ED=95=AD=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- next.config.js | 1 + src/components/DetailBoard.tsx | 4 +-- src/components/DetailBoardComments.tsx | 34 +++++++++++--------------- src/components/ProductComments.tsx | 3 +-- src/pages/addboard.tsx | 3 +-- src/pages/additem.tsx | 5 ++-- 6 files changed, 21 insertions(+), 29 deletions(-) diff --git a/next.config.js b/next.config.js index 549bdfeb9..d40888e07 100644 --- a/next.config.js +++ b/next.config.js @@ -6,6 +6,7 @@ const nextConfig = { "sprint-fe-project.s3.ap-northeast-2.amazonaws.com", "images.samsung.com", "example.com", + "flexible.img.hani.co.kr", ], }, }; diff --git a/src/components/DetailBoard.tsx b/src/components/DetailBoard.tsx index 2648cc7d4..2b9588fd9 100644 --- a/src/components/DetailBoard.tsx +++ b/src/components/DetailBoard.tsx @@ -44,15 +44,15 @@ function Product() { const res = await axios.get(`/articles/${id}`); const nextProduct = res.data; setProduct(nextProduct); + setLoading(false); } catch (error) { - console.error(`유효하지 않은 주소입니다.`); + alert(`유효하지 않은 주소입니다.`); router.replace(`/board`); } } useEffect(() => { getProduct(id); - setLoading(false); }, [id]); if (loading) { diff --git a/src/components/DetailBoardComments.tsx b/src/components/DetailBoardComments.tsx index f7877ad9a..9514ae213 100644 --- a/src/components/DetailBoardComments.tsx +++ b/src/components/DetailBoardComments.tsx @@ -23,21 +23,24 @@ interface ItemsListType { function DetailBoardComments() { const [comments, setComments] = useState([]); const [loading, setLoading] = useState(true); - const [values, setValues] = useState(""); + const [commentsValues, setCommentsValues] = useState(""); const [pass, setPass] = useState(false); const router = useRouter(); const id = Number(router.query["id"]); // 게시판 댓글 데이터 가져오기 async function getProduct(id: number) { - const res = await axios.get(`/articles/${id}/comments?limit=50`); - const nextComments = res.data.list; - console.log(nextComments); - setComments(nextComments); + try { + const res = await axios.get(`/articles/${id}/comments?limit=50`); + const nextComments = res.data.list; + setComments(nextComments); + setLoading(false); + } catch (error) { + alert("댓글 데이터 불러오기 실패"); + } } useEffect(() => { getProduct(id); - setLoading(false); }, [id]); const onClickReturn = () => { @@ -47,13 +50,14 @@ function DetailBoardComments() { // 댓글 인풋의 입력값 파악 const handleInputChange = (e: ChangeEvent) => { const { value } = e.target; - setValues(value); + setCommentsValues(value); }; - // 테스트를 위해 추가한 동작 + // TODO: 스프린트 미션에 API POST 관련 기능 요구 시 추가 예정, 현재는 테스트를 위한 코드 const handleSubmit = (e: FormEvent) => { + if (commentsValues.length <= 0) return; e.preventDefault(); - console.log(values); + console.log(commentsValues); }; // 댓글 작성한 시간 변환 함수 @@ -78,16 +82,6 @@ function DetailBoardComments() { } }; - // 입력값 감지 후 조건 충족 시 등록 버튼 활성화 - useEffect(() => { - function validation() { - const valueCheck = values.length > 0; - return valueCheck; - } - const isValid = validation(); - setPass(isValid); - }, [values]); - if (loading) { return
Loading...
; } @@ -104,7 +98,7 @@ function DetailBoardComments() { />
- - 로그인 - + {isLoggedIn ? ( +
+ 유저 프로필 아이콘 + {isOpen ? ( +
+ 로그아웃 +
+ ) : ( + <> + )} +
+ ) : ( + + 로그인 + + )} ); diff --git a/src/components/ProductComments.tsx b/src/components/ProductComments.tsx index e52721466..66fd4f7e1 100644 --- a/src/components/ProductComments.tsx +++ b/src/components/ProductComments.tsx @@ -7,10 +7,6 @@ import S from "@/components/ProductComments.module.css"; const PLACEHOLDERTEXT = "개인정보를 공유 및 요청하거나, 명예 훼손, 무단 광고, 불법 정보 유포시 모니터링 후 삭제될 수 있으며, 이에 대한 민형사상 책임은 게시자에게 있습니다."; -interface ButtonProps { - $pass?: boolean; -} - interface ItemsListType { list: T[]; } diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 347cf9c0a..a735b10c8 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -1,11 +1,14 @@ import NavBar from "@/components/NavBar"; import "@/styles/globals.css"; import type { AppProps } from "next/app"; +import { useRouter } from "next/router"; export default function App({ Component, pageProps }: AppProps) { + const router = useRouter(); + const noNavBarPages = ["/login", "/register"]; return ( <> - + {!noNavBarPages.includes(router.pathname) && } ); diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 806abbd14..1866a61c3 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -10,7 +10,6 @@ export default function Home() {
- {/* */}
diff --git a/src/pages/login.tsx b/src/pages/login.tsx index 2a91731fb..f176fd745 100644 --- a/src/pages/login.tsx +++ b/src/pages/login.tsx @@ -1,111 +1,89 @@ -import Link from "next/link"; +import { useForm } from "react-hook-form"; +import { useRouter } from "next/router"; import Image from "next/image"; +import S from "@/styles/login.module.css"; +import axios from "@/pages/api/axios"; +import { useEffect } from "react"; + +interface FormData { + email: string; + password: string; +} function Login() { + const { + register, + handleSubmit, + formState: { isSubmitting, isSubmitted, errors }, + } = useForm(); + const router = useRouter(); + + async function getAccessToken(data: FormData) { + try { + const res = await axios.post("/auth/signIn", data); + const token = res.data.accessToken; + localStorage.setItem("accessToken", token); + router.replace("/"); + } catch (error) { + alert("토큰 가져오기 실패"); + router.replace("/login"); + } + } + useEffect(() => { + const token = localStorage.getItem("accessToken"); + if (token) router.replace("/"); + }, [router]); + return ( - <> -
-
- - 판다마켓 로고 - -
-
-
-
-
-
- - -
이메일을 입력해주세요
-
잘못된 이메일 형식입니다.
-
-
- - -
닉네임을 입력해주세요
-
-
- - -
비밀번호를 입력해주세요
-
비밀번호를 8자 이상 입력해주세요.
- visibilty-on-off-icon -
-
- - -
비밀번호가 일치하지 않습니다.
- visibilty-on-off-icon -
-
- -
-
- 간편 로그인하기 -
- - google-icon - - - kakao-icon - -
-
-
-
-
-
-
- 이미 회원이신가요? 로그인 -
-
- +
+
+ 판다마켓 로고 +
+
+ + + {errors.email && ( + + {String(errors.email.message)} + + )} + + + {errors.password && ( + + {String(errors.password.message)} + + )} + +
+
); } diff --git a/src/pages/signup.tsx b/src/pages/signup.tsx new file mode 100644 index 000000000..72162e6c5 --- /dev/null +++ b/src/pages/signup.tsx @@ -0,0 +1,145 @@ +import { useForm } from "react-hook-form"; +import { useRouter } from "next/router"; +import Image from "next/image"; +import S from "@/styles/login.module.css"; +import axios from "@/pages/api/axios"; +import { useEffect } from "react"; + +interface FormData { + email: string; + nickname: string; + password: string; + passwordConfirmation: string; +} +function SignUp() { + const { + register, + handleSubmit, + formState: { isSubmitting, isSubmitted, errors }, + getValues, + } = useForm(); + const router = useRouter(); + + async function postSignUp(data: FormData) { + try { + await axios.post("/auth/signUp", data); + router.replace("/login"); + } catch (error: any) { + let errorMessage = "회원가입 실패"; // 기본 메시지 + + // 서버에서 반환된 메시지를 확인 + if (error.response) { + if (error.response.data.message) { + errorMessage = error.response.data.message; // "이미 사용중인 이메일입니다." + } + if (error.response.data.details && error.response.data.details.email) { + errorMessage = error.response.data.details.email.message; // 구체적인 이메일 오류 메시지 + } + } + + alert(errorMessage); // 사용자에게 에러 메시지 표시 + router.replace("/signup"); + } + } + useEffect(() => { + const token = localStorage.getItem("accessToken"); + if (token) router.replace("/"); + }, [router]); + return ( +
+
+ 판다마켓 로고 +
+
+ + + {errors.email && ( + + {String(errors.email.message)} + + )} + + + {errors.nickname && ( + + {String(errors.nickname.message)} + + )} + + + {errors.password && ( + + {String(errors.password.message)} + + )} + + { + if (getValues("password") !== val) { + return "비밀번호가 일치하지 않습니다."; + } + }, + }, + })} + aria-invalid={isSubmitted ? (errors.passwordConfirmation ? "true" : "false") : undefined} + /> + {errors.passwordConfirmation && ( + + {String(errors.passwordConfirmation.message)} + + )} + +
+
+ ); +} + +export default SignUp; diff --git a/src/styles/globals.css b/src/styles/globals.css index bc7d07a4a..a30ac78fc 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -7,6 +7,7 @@ --gray600: #4b5563; --gray500: #6b7280; --gray400: #9ca3af; + --gray300: #d1d5db; --gray200: #e5e7eb; --gray100: #f3f4f6; --gray50: #f9fafb; @@ -68,3 +69,14 @@ table { a { text-decoration: none; } +input, +input:focus, +textarea, +textarea:focus { + outline: none; + box-shadow: none; +} +input[aria-invalid="true"] { + border: 2px solid red; + border-color: red; +} diff --git a/src/styles/login.module.css b/src/styles/login.module.css new file mode 100644 index 000000000..dd4dde982 --- /dev/null +++ b/src/styles/login.module.css @@ -0,0 +1,43 @@ +.container { + width: 100%; + margin: 70px auto 0px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} + +.LogoImageWrapper { + position: relative; + width: 198px; + height: 66px; +} + +.formContainer { + display: flex; + flex-direction: column; +} +.inputBox { + outline: none; +} +.inputBox :focus { + outline: 2px solid var(--blue) !important; +} +.errorMessage { + font-size: 14px; + font-weight: 600; + color: var(--red); +} +@media screen and (max-width: 1199px) and (min-width: 768px) { +} + +@media screen and (min-width: 1200px) { + .container { + max-width: 1200px; + margin: 70px auto 0px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + } +} From 927c409ed93d9ebd7dfb6184eeb100b2adf03cf2 Mon Sep 17 00:00:00 2001 From: MELATONIN99 Date: Fri, 23 Aug 2024 22:22:13 +0900 Subject: [PATCH 3/3] =?UTF-8?q?chore.=20=EB=B6=88=ED=95=84=EC=9A=94=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/login.tsx | 1 + src/pages/signup.tsx | 17 +++-------------- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/src/pages/login.tsx b/src/pages/login.tsx index f176fd745..bd10e6ae6 100644 --- a/src/pages/login.tsx +++ b/src/pages/login.tsx @@ -25,6 +25,7 @@ function Login() { router.replace("/"); } catch (error) { alert("토큰 가져오기 실패"); + console.error(error); router.replace("/login"); } } diff --git a/src/pages/signup.tsx b/src/pages/signup.tsx index 72162e6c5..13f9805d1 100644 --- a/src/pages/signup.tsx +++ b/src/pages/signup.tsx @@ -24,20 +24,9 @@ function SignUp() { try { await axios.post("/auth/signUp", data); router.replace("/login"); - } catch (error: any) { - let errorMessage = "회원가입 실패"; // 기본 메시지 - - // 서버에서 반환된 메시지를 확인 - if (error.response) { - if (error.response.data.message) { - errorMessage = error.response.data.message; // "이미 사용중인 이메일입니다." - } - if (error.response.data.details && error.response.data.details.email) { - errorMessage = error.response.data.details.email.message; // 구체적인 이메일 오류 메시지 - } - } - - alert(errorMessage); // 사용자에게 에러 메시지 표시 + } catch (error) { + alert("회원가입 실패"); + console.error(error); router.replace("/signup"); } }