Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions src/components/Sign/SignIn/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ type InputsType = {
password: string;
};

function SignIn() {
type SignInPropsType = {
setIsSginUp: React.Dispatch<React.SetStateAction<boolean>>;
};

function SignIn({ setIsSginUp }: SignInPropsType) {
// TODO: errors에 대한 다양한 유형 처리하기 (ex) 아이디가 없는 경우, 비밀번호가 틀린 경우 등)
const {
register,
Expand Down Expand Up @@ -60,7 +64,14 @@ function SignIn() {

<button type="submit">로그인</button>
<p>
아직 회원이 아니신가요? <span>회원가입</span>
아직 회원이 아니신가요?{' '}
<span
onClick={() => {
setIsSginUp((pre) => !pre);
}}
>
회원가입
</span>
</p>
</form>
</article>
Expand Down
112 changes: 110 additions & 2 deletions src/components/Sign/SignUp/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,115 @@
import React from 'react';
import styles from './styles.module.scss';
import { SubmitHandler, useForm } from 'react-hook-form';

function SignUp() {
return <div>회원가입 컴포넌트</div>;
type SignUpPropsType = {
setIsSginUp: React.Dispatch<React.SetStateAction<boolean>>;
};

type InputsType = {
nickname: string;
id: string;
password: string;
passwordCheck: string;
};

function SignUp({ setIsSginUp }: SignUpPropsType) {
const {
register,
handleSubmit,
watch,
formState: { errors },
} = useForm<InputsType>();
Comment on lines +16 to +22

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기에는 useForm이라는 새로운 Hook이 하나가 보이네요! 혹시 이건 직관적으로 해석한 것처럼 폼과 관련된 훅인건가요??


const onSubmit: SubmitHandler<InputsType> = async (data: InputsType) => {
console.info(data);
// TODO: 실제 로그인 로직을 수행하고, 서버로부터 JWT 토큰을 받는다.
};

return (
<article className={styles.container}>
<form className={styles.form} onSubmit={handleSubmit(onSubmit)}>
<div>
<label htmlFor="nickname">닉네임</label>
<input
id="nickname"
type="text"
defaultValue={watch('nickname')}
placeholder={'닉네임을 입력하세요.'}
{...register('nickname', {
required: {
value: true,
message: '닉네임은 필수 입력항목입니다.',
},
})}
></input>
{errors.nickname && <span>{errors.nickname.message}</span>}
</div>

<div>
<label htmlFor="id">아이디</label>
<input
id="id"
type="text"
defaultValue={watch('id')}
placeholder={'아이디를 입력하세요.'}
{...register('id', {
required: {
value: true,
message: '아이디는 필수 입력항목입니다.',
},
})}
></input>
{errors.id && <span>{errors.id.message}</span>}
</div>
<div>
<label htmlFor="password">비밀번호</label>
<input
id="password"
type="password"
defaultValue={watch('password')}
placeholder={'비밀번호를 입력하세요.'}
{...register('password', {
required: {
value: true,
message: '비밀번호는 필수 입력항목입니다.',
},
})}
></input>
{errors.password && <span>{errors.password.message}</span>}
</div>

<div>
<label htmlFor="passwordCheck">비밀번호 재확인</label>
<input
id="passwordCheck"
type="password"
defaultValue={watch('passwordCheck')}
placeholder={'비밀번호 재입력하세요.'}
{...register('passwordCheck', {
required: {
value: true,
message: '비밀번호 재확인은 필수 입력항목입니다.',
},
})}
></input>
{errors.passwordCheck && <span>{errors.passwordCheck.message}</span>}
</div>

<button type="submit">회원가입</button>
<p>
아이디가 기억나셨나요?{' '}
<span
onClick={() => {
setIsSginUp((pre) => !pre);
}}
>
로그인
</span>
</p>
</form>
</article>
);
}

export default SignUp;
74 changes: 74 additions & 0 deletions src/components/Sign/SignUp/styles.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
.container {
display: flex;
flex-direction: column;
align-items: center;
gap: 3rem;
background-color: white;
}

.form {
display: flex;
flex-direction: column;
width: 100%;
gap: 2rem;
& > div {
display: flex;
flex-direction: column;

& > label {
margin-bottom: 1rem;
}
& > input {
@media screen and (max-width: 768px) {
height: auto;
padding: 3rem 1.5rem;
}
width: 100%;
height: 4.9rem;
padding: 0 1.5rem;
margin-bottom: 1rem;
font-weight: 500;
outline: none;
background: #f9f9f9;
box-shadow: 0px 1px 2px 3px rgba(0, 0, 0, 0.15),
0px 1px 1px rgba(0, 0, 0, 0.3);
border-radius: 4px;
}
& > span {
color: red;
font-size: 1.2rem;
}
}

& > button {
align-self: center;
width: 18rem;
height: 4.9rem;
margin-top: 5rem;
cursor: pointer;
color: white;
border: none;
background: #ff6835;
border-radius: 100px;
&:hover {
opacity: 0.8;
}
}

& > p {
align-self: center;
margin-top: 1rem;
font-size: 1.4rem;
color: #cecece;

& > span {
font-weight: 600;
cursor: pointer;
color: #ff6835;
&:hover {
text-decoration: underline;
opacity: 0.8;
}
}
}
}
10 changes: 8 additions & 2 deletions src/pages/sign/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
import React from 'react';
import React, { useState } from 'react';
import { Player } from '@lottiefiles/react-lottie-player';
import styles from './styles.module.scss';
import SignIn from '@/components/Sign/SignIn';
import SignUp from '@/components/Sign/SignUp';

function SignPage() {
const [isSignUp, setIsSginUp] = useState<boolean>(false);
return (
<section className={styles.signinContainer}>
<section className={styles.signinContainer__box}>
<article className={styles.signinContainer__left}>
<h1>HQ Rutine</h1>
<SignIn />
{isSignUp ? (
<SignUp setIsSginUp={setIsSginUp} />
) : (
<SignIn setIsSginUp={setIsSginUp} />
)}
</article>
<article className={styles.signinContainer__right}>
<Player
Expand Down
6 changes: 5 additions & 1 deletion src/pages/sign/styles.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,17 @@
background-color: #f5f5f5;

&__box {
@media screen and (max-width: 768px) {
max-height: 100%;
}
display: flex;
align-items: center;
justify-content: center;
width: 100%;
max-width: 118rem;
height: 100%;
max-height: 72rem;
max-height: 80rem;

border-radius: 16px;
background-color: white;
}
Expand Down