Skip to content

Commit

Permalink
Merge pull request #996 from gibeom0218/part3-박기범-week15
Browse files Browse the repository at this point in the history
[박기범] week15
  • Loading branch information
devym-37 authored Apr 7, 2024
2 parents c6d40ba + 74d6fb2 commit ce0afc9
Show file tree
Hide file tree
Showing 10 changed files with 648 additions and 16 deletions.
66 changes: 56 additions & 10 deletions components/Input.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,66 @@
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
import Image from "next/image";
import { postCheckEmail } from "@/pages/api/api";
import styles from "@/styles/Input.module.css";
import eyeOff from "@/public/images/eye-off.svg";
import eyeOn from "@/public/images/eye-on.svg";

interface InputProp {
page?: string;
passwordValue?: string;
inputType: string;
onChange: (value: string) => void;
onSetErrMsg: (value: string) => void;
isError: string;
}

export default function Input({ inputType }: InputProp) {
export default function Input({
page,
passwordValue,
inputType,
onChange,
onSetErrMsg,
isError,
}: InputProp) {
const [isFocused, setIsFocused] = useState(false);
const [isShowPassword, setIsShowPassword] = useState(false);
const [type, setType] = useState(inputType);
const [type, setType] = useState(
inputType === "passwordChk" ? "password" : inputType
);
const [errorMsg, setErrorMsg] = useState("");

const emailChk = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
const passwordChk = /^(?=.*\d)(?=.*[a-z])[A-Za-z\d@$!%*?&]{8,}$/;

const handleError = (e: React.FocusEvent<HTMLInputElement>) => {
//에러메시지가 바뀔때마다 에러메시지 초기화
useEffect(() => {
onSetErrMsg(errorMsg);
}, [errorMsg]);

const handleError = async (e: React.FocusEvent<HTMLInputElement>) => {
const value = e.target.value;
setIsFocused(false);
if (!value) {
setErrorMsg("값을 입력해주세요");

if (!value && inputType === "id") {
setErrorMsg("이메일을 입력해 주세요.");
} else if (!value && inputType === "password") {
setErrorMsg("비밀번호를 입력해 주세요.");
} else if (!value && inputType === "passwordChk") {
setErrorMsg("비밀번호를 다시 한번 입력해 주세요.");
} else if (inputType === "id" && !emailChk.test(value)) {
setErrorMsg("올바른 이메일 주소를 입력해주세요.");
} else if (inputType === "password" && !passwordChk.test(value)) {
setErrorMsg("올바른 비밀번호를 입력해주세요.");
} else if (inputType === "passwordChk" && passwordValue !== value) {
setErrorMsg("비밀번호가 일치하지 않아요.");
} else if (page === "signUp" && inputType === "id" && value) {
//회원가입 페이지에서의 이메일 input태그이고 값이 있는경우
const response = await postCheckEmail(value);
if (response.status !== 200) {
setErrorMsg("이미 사용 중인 이메일입니다.");
} else {
setErrorMsg("");
}
} else {
setErrorMsg("");
}
Expand All @@ -40,28 +75,39 @@ export default function Input({ inputType }: InputProp) {
}
};

const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const newValue = e.target.value;
onChange(newValue); // 부모 컴포넌트로 값을 전달
};

return (
<>
<div
className={`${styles.inputContainer} ${
isFocused ? styles.focused : ""
} ${errorMsg ? styles.err : ""}`}
} ${isError ? styles.err : ""}`}
>
<input
type={type}
placeholder={type === "id" ? "아이디 입력" : "비밀번호 입력"}
placeholder={
inputType === "id"
? "이메일을 입력해 주세요."
: inputType === "password"
? "비밀번호를 입력해 주세요."
: "비밀번호와 일치하는 값을 입력해 주세요."
}
onFocus={() => setIsFocused(true)}
onBlur={handleError}
onChange={handleChange}
/>
{inputType === "password" && (
{(inputType === "password" || inputType === "passwordChk") && (
<Image
src={isShowPassword ? eyeOn : eyeOff}
alt={isShowPassword ? "숨김" : "표시"}
onClick={handleIcon}
/>
)}
</div>
{errorMsg && <p className={styles.errMsg}>{errorMsg}</p>}
</>
);
}
26 changes: 26 additions & 0 deletions components/SignLogoFrame.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import Image from "next/image";
import styles from "@/styles/SignLogoFrame.module.css";
import logo from "@/public/images/logo.svg";

interface SignLogoProp {
type: string;
}

export default function SignLogoFrame({ type }: SignLogoProp) {
return (
<div className={styles.logoFrame}>
<Image id={styles.logoImg} src={logo} alt="로고이미지" />
<div className={styles.commentFrame}>
<span id={styles.comment}>
{type === "signIn" ? "회원이 아니신가요?" : "이미 회원이신가요?"}
</span>
<a
id={styles.linkComment}
href={type === "signIn" ? "/signup" : "/signin"}
>
{type === "signIn" ? "회원 가입하기" : "로그인 하기"}
</a>
</div>
</div>
);
}
38 changes: 38 additions & 0 deletions pages/api/api.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,41 @@ export async function getFolderLink(id: number) {
const folderLink = await response.json();
return folderLink;
}

export async function postSignIn(id: string, password: string) {
const response = await fetch(`${BASE_URL}/api/sign-in`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
email: id,
password: password,
}),
});

return response;
}

export async function postCheckEmail(id: string) {
const response = await fetch(`${BASE_URL}/api/check-email`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
email: id,
}),
});

return response;
}

export async function postSignUp(id: string, password: string) {
const response = await fetch(`${BASE_URL}/api/sign-up`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
email: id,
password: password,
}),
});

return response;
}
12 changes: 6 additions & 6 deletions pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Inter } from "next/font/google";
import Link from "next/link";
import Input from "@/components/Input";

const inter = Inter({ subsets: ["latin"] });

Expand All @@ -13,11 +12,12 @@ export default function Home() {
<Link href="/folder">
<h1>folder페이지로 이동</h1>
</Link>
<br />
<Input inputType="id" />
<br />
<br />
<Input inputType="password" />
<Link href="/signin">
<h1>signin페이지로 이동</h1>
</Link>
<Link href="/signup">
<h1>signup페이지로 이동</h1>
</Link>
</>
);
}
110 changes: 110 additions & 0 deletions pages/signin.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import React, { FormEvent, useEffect, useState } from "react";
import { useRouter } from "next/router";
import Image from "next/image";
import Link from "next/link";
import Input from "@/components/Input";
import SignLogoFrame from "@/components/SignLogoFrame";
import { postSignIn } from "./api/api";
import styles from "@/styles/SignInPage.module.css";
import kakaoIcon from "@/public/images/kakao.svg";
import googleIcon from "@/public/images/google.svg";

export default function SignIn() {
const [emailValue, setEmailValue] = useState("");
const [passwordValue, setPasswordValue] = useState("");
const [emailError, setEmailError] = useState("");
const [passwordError, setPasswordError] = useState("");

const router = useRouter();

useEffect(() => {
const accessToken = localStorage.getItem("accessToken");
if (accessToken) {
router.push("/folder");
}
}, []);

const handleSubmit = async (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();

const response = await postSignIn(emailValue, passwordValue);

const { data } = await response.json();

if (response.status === 200) {
router.push("/folder");
localStorage.setItem("accessToken", data.accessToken);
} else {
setEmailError("이메일을 확인해 주세요.");
setPasswordError("비밀번호를 확인해 주세요.");
}
};

const handleEmailChange = (value: string) => {
setEmailValue(value);
};

const handlePasswordChange = (value: string) => {
setPasswordValue(value);
};

const handleSetIdErrMsg = (value: string) => {
setEmailError(value);
};

const handleSetPasswordErrMsg = (value: string) => {
setPasswordError(value);
};

return (
<div className={styles.container}>
<form className={styles.logInFrame} onSubmit={handleSubmit}>
<SignLogoFrame type="signIn" />
<div className={styles.inputCommonFrame}>
<div className={styles.inputFrame}>
<span>이메일</span>
<Input
inputType="id"
onChange={handleEmailChange}
onSetErrMsg={handleSetIdErrMsg}
isError={emailError}
/>
{emailError && <p className={styles.errMsg}>{emailError}</p>}
</div>

<div className={styles.inputFrame}>
<span>비밀번호</span>
<Input
inputType="password"
onChange={handlePasswordChange}
onSetErrMsg={handleSetPasswordErrMsg}
isError={passwordError}
/>
{passwordError && <p className={styles.errMsg}>{passwordError}</p>}
</div>
</div>

<button id={styles.logInButton} type="submit">
로그인
</button>

<div className={styles.socialLoginFrame}>
<span>소셜 로그인</span>
<div className={styles.socialLogin}>
<div className={styles.iconGoogleBox}>
<Link href="https://www.google.com">
<Image src={googleIcon} alt="구글 아이콘" />
</Link>
</div>

<div className={styles.iconKakaoBox}>
<Link href="https://www.kakaocorp.com/page">
<Image src={kakaoIcon} alt="카카오톡 아이콘" />
</Link>
</div>
</div>
</div>
</form>
</div>
);
}
Loading

0 comments on commit ce0afc9

Please sign in to comment.