-
Notifications
You must be signed in to change notification settings - Fork 79
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
92ea784
commit 7c3ddfa
Showing
13 changed files
with
364 additions
and
2 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,153 @@ | ||
import React, { useEffect, useState } from 'react'; | ||
import { useRouter } from 'next/router'; | ||
import { useForm, SubmitHandler, FieldValues } from 'react-hook-form'; | ||
import { yupResolver } from '@hookform/resolvers/yup'; | ||
import * as yup from 'yup'; | ||
import style from './SignupForm.module.scss'; | ||
import Link from 'next/link'; | ||
import KakaoIcon from '../../public/icon/kakao-logo.png'; | ||
import GoogleIcon from '../../public/icon/google-logo.png'; | ||
import Image from 'next/image'; | ||
import axios from '../pages/api/axios'; | ||
|
||
const schema = yup.object().shape({ | ||
email: yup | ||
.string() | ||
.trim() | ||
.matches(/^[a-zA-Z0-9+-_.]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$/, '잘못된 이메일 형식입니다.') | ||
.required('이메일을 입력해주세요'), | ||
nickname: yup.string().required('닉네임을 입력해주세요'), | ||
password: yup.string().min(8, '비밀번호를 8자 이상 입력해주세요').required('비밀번호를 입력해주세요'), | ||
password_confirm: yup | ||
.string() | ||
.min(8, '비밀번호를 8자 이상 입력해주세요') | ||
.oneOf([yup.ref('password')], '비밀번호가 일치하지 않습니다.') | ||
.required('비밀번호를 입력해주세요'), | ||
}); | ||
|
||
export default function SignupForm() { | ||
const router = useRouter(); | ||
const { register, handleSubmit, getValues, formState } = useForm({ | ||
mode: 'onBlur', | ||
resolver: yupResolver(schema), | ||
}); | ||
const [validate, setValidate] = useState(false); | ||
|
||
const onSubmit: SubmitHandler<FieldValues> = async data => { | ||
const { email, nickname, password, password_confirm } = data; | ||
await axios.post('/auth/signUp', { | ||
email, | ||
nickname, | ||
password, | ||
passwordConfirmation: password_confirm, | ||
}); | ||
router.push('/signin'); | ||
}; | ||
|
||
useEffect(() => { | ||
if (localStorage.getItem('accessToken')) { | ||
router.push('/'); | ||
} | ||
}, [router]); | ||
|
||
const handleBlur = () => { | ||
console.log(formState.errors); | ||
console.log(Object.keys(formState.errors).length); | ||
if ( | ||
!getValues(['email', 'nickname', 'password', 'password_confirm']).includes('') && | ||
Object.keys(formState.errors).length === 0 | ||
) { | ||
setValidate(true); | ||
} else { | ||
setValidate(false); | ||
} | ||
}; | ||
|
||
return ( | ||
<> | ||
<form onSubmit={handleSubmit(onSubmit)} className={style.form_container}> | ||
<div className={style.form_top}> | ||
<div className={style.form_element}> | ||
<label className={style.form_label}>이메일</label> | ||
<input | ||
{...register('email', { | ||
onBlur: handleBlur, | ||
})} | ||
type="text" | ||
placeholder="이메일을 입력해주세요." | ||
className={formState.errors.email ? `${style.form_input} ${style.invalid}` : style.form_input} | ||
/> | ||
<div className={style.invalid_message}>{formState.errors.email?.message}</div> | ||
</div> | ||
<div className={style.form_element}> | ||
<label className={style.form_label}>닉네임</label> | ||
<input | ||
{...register('nickname', { | ||
onBlur: handleBlur, | ||
})} | ||
type="text" | ||
placeholder="닉네임을 입력해주세요." | ||
className={formState.errors.nickname ? `${style.form_input} ${style.invalid}` : style.form_input} | ||
/> | ||
<div className={style.invalid_message}>{formState.errors.nickname?.message}</div> | ||
</div> | ||
<div className={style.form_element}> | ||
<label className={style.form_label}>비밀번호</label> | ||
<input | ||
{...register('password', { | ||
onBlur: handleBlur, | ||
})} | ||
type="password" | ||
placeholder="비밀번호를 입력해주세요." | ||
className={formState.errors.password ? `${style.form_input} ${style.invalid}` : style.form_input} | ||
/> | ||
<div className={style.invalid_message}>{formState.errors.password?.message}</div> | ||
</div> | ||
<div className={style.form_element}> | ||
<label className={style.form_label}>비밀번호 확인</label> | ||
<input | ||
{...register('password_confirm', { | ||
onBlur: handleBlur, | ||
})} | ||
type="password" | ||
placeholder="비밀번호를 입력해주세요." | ||
className={formState.errors.password_confirm ? `${style.form_input} ${style.invalid}` : style.form_input} | ||
/> | ||
<div className={style.invalid_message}>{formState.errors.password_confirm?.message}</div> | ||
</div> | ||
</div> | ||
<div className={style.form_bottom}> | ||
<div className={style.submit_button_box}> | ||
<input | ||
type="submit" | ||
value="회원가입" | ||
className={validate ? `${style.submit_button} ${style.active}` : style.submit_button} | ||
disabled={!validate} | ||
/> | ||
</div> | ||
<div className={style.social_login_box}> | ||
<h3 className={style.social_login_title}>간편 로그인하기</h3> | ||
<div className={style.social_login_links}> | ||
<Link href="https://google.com"> | ||
<div className={style.image}> | ||
<Image fill src={GoogleIcon} alt="구글 로그인" /> | ||
</div> | ||
</Link> | ||
<Link href="https://kakao.com"> | ||
<div className={style.image}> | ||
<Image fill src={KakaoIcon} alt="카카오톡 로그인" /> | ||
</div> | ||
</Link> | ||
</div> | ||
</div> | ||
<div className={style.navigate_link_box}> | ||
<h3 className={style.navigate_link_title}>이미 회원이신가요?</h3> | ||
<Link href="/signin" className={style.navigate_link_content}> | ||
로그인 | ||
</Link> | ||
</div> | ||
</div> | ||
</form> | ||
</> | ||
); | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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
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,34 @@ | ||
import axios from 'axios'; | ||
|
||
const instance = axios.create({ | ||
baseURL: process.env.NEXT_PUBLIC_BASE_URL, | ||
// withCredentials: true, | ||
timeout: 30000, | ||
headers: { | ||
'Content-Type': 'application/json', | ||
}, | ||
}); | ||
|
||
instance.interceptors.request.use(config => { | ||
config.headers.Authorization = `Bearer ${localStorage.getItem('accessToken')}`; | ||
|
||
return config; | ||
}); | ||
|
||
instance.interceptors.response.use( | ||
res => res, | ||
async error => { | ||
const originalRequest = error.config; | ||
if (error.response?.status === 401 && !originalRequest._retry) { | ||
const res = await instance.post('/auth/refresh-token', { | ||
refreshToken: localStorage.getItem('accessToken'), | ||
}); | ||
localStorage.setItem('accessToken', res.data.accessToken); | ||
originalRequest._retry = true; | ||
return instance(originalRequest); | ||
} | ||
return Promise.reject(error); | ||
} | ||
); | ||
|
||
export default instance; |
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,12 @@ | ||
export const debounce = <T extends (...args: any[]) => any>(fn: T, delay: number) => { | ||
let timeout: ReturnType<typeof setTimeout>; | ||
|
||
return (...args: Parameters<T>): ReturnType<T> => { | ||
let result: any; | ||
if (timeout) clearTimeout(timeout); | ||
timeout = setTimeout(() => { | ||
result = fn(...args); | ||
}, delay); | ||
return result; | ||
}; | ||
}; |
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,33 @@ | ||
import React, { useEffect, useState } from 'react'; | ||
import style from './styles.module.scss'; | ||
// import SigninForm from '../../components/SigninForm'; | ||
import PandaMarketLogoLarge from '../../public/icon/logo-lg.svg'; | ||
import PandaMarketLogoSmall from '../../public/icon/logo-sm.svg'; | ||
import { debounce } from '../lib/debounce'; | ||
|
||
export default function Signup() { | ||
const [windowWidth, setWindowWidth] = useState(0); | ||
|
||
useEffect(() => { | ||
setWindowWidth(window.innerWidth); | ||
|
||
const handleResize = () => { | ||
setWindowWidth(window.innerWidth); | ||
}; | ||
|
||
const debouncedHandleResize = debounce(handleResize, 300); | ||
|
||
window.addEventListener('resize', debouncedHandleResize); | ||
|
||
return () => { | ||
window.removeEventListener('resize', debouncedHandleResize); | ||
}; | ||
}, [windowWidth]); | ||
|
||
return ( | ||
<div className={style.container}> | ||
{windowWidth > 376 ? <PandaMarketLogoLarge /> : <PandaMarketLogoSmall />} | ||
{/* <SigninForm /> */} | ||
</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,9 @@ | ||
@import '../../styles/index.scss'; | ||
|
||
.container { | ||
display: flex; | ||
flex-direction: column; | ||
justify-content: center; | ||
align-items: center; | ||
gap: 40px; | ||
} |
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,33 @@ | ||
import React, { useEffect, useState } from 'react'; | ||
import PandaMarketLogoLarge from '../../public/icon/logo-lg.svg'; | ||
import PandaMarketLogoSmall from '../../public/icon/logo-sm.svg'; //경로가 있는데도 왜 안되는지 모르겠네요... | ||
import style from './styles.module.scss'; | ||
import SignupForm from '../../components/SignupForm'; | ||
import { debounce } from '../lib/debounce'; | ||
|
||
export default function Signup() { | ||
const [windowWidth, setWindowWidth] = useState(0); | ||
|
||
useEffect(() => { | ||
setWindowWidth(window.innerWidth); | ||
|
||
const handleResize = () => { | ||
setWindowWidth(window.innerWidth); | ||
}; | ||
|
||
const debouncedHandleResize = debounce(handleResize, 300); | ||
|
||
window.addEventListener('resize', debouncedHandleResize); | ||
|
||
return () => { | ||
window.removeEventListener('resize', debouncedHandleResize); | ||
}; | ||
}, [windowWidth]); | ||
|
||
return ( | ||
<div className={style.container}> | ||
{windowWidth > 376 ? <PandaMarketLogoLarge /> : <PandaMarketLogoSmall />} | ||
<SignupForm /> | ||
</div> | ||
); | ||
} |
Oops, something went wrong.