feat: 로그인 기능 추가
This commit is contained in:
parent
8ade28a2ed
commit
6e312e8ecb
@ -1,15 +1,10 @@
|
||||
import styles from './AuthForm.module.css';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
export default function AuthForm({ children, title, buttonText, linkProps = null, submitFunction }) {
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
submitFunction();
|
||||
};
|
||||
|
||||
export default function AuthForm({ children, title, buttonText, linkProps = null, onSubmit }) {
|
||||
return (
|
||||
<form
|
||||
onSubmit={handleSubmit}
|
||||
onSubmit={onSubmit}
|
||||
className={styles.loginForm}
|
||||
>
|
||||
<span className={styles.loginText}>{title}</span>
|
||||
|
@ -8,6 +8,7 @@
|
||||
height: 64px;
|
||||
background-color: var(--background);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.nav {
|
||||
|
29
frontend/src/hooks/api/useAuth.js
Normal file
29
frontend/src/hooks/api/useAuth.js
Normal file
@ -0,0 +1,29 @@
|
||||
import { API_URL } from '../../constants';
|
||||
import useBoundStore from '../../store';
|
||||
import instance from '../../utils/axios/instance';
|
||||
|
||||
export function useAuth() {
|
||||
const setToken = useBoundStore((state) => state.setToken);
|
||||
const setUserType = useBoundStore((state) => state.setUserType);
|
||||
|
||||
const login = (userId, password, onError = () => {}) => {
|
||||
const formData = {
|
||||
userId,
|
||||
password,
|
||||
};
|
||||
return instance
|
||||
.post(`${API_URL}/user/login`, formData)
|
||||
.then(({ data }) => data['access-token'])
|
||||
.then((accessToken) => {
|
||||
setToken(accessToken);
|
||||
// TODO: userType 구분 추가
|
||||
setUserType('student');
|
||||
})
|
||||
.catch((e) => {
|
||||
alert('아이디 또는 비밀번호를 다시 확인해주세요.');
|
||||
onError(e);
|
||||
});
|
||||
};
|
||||
|
||||
return { login };
|
||||
}
|
@ -1,26 +1,42 @@
|
||||
import { AuthForm, InputBox } from '../../components/AuthForm';
|
||||
import { useRef } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { Link, useNavigate } from 'react-router-dom';
|
||||
import { useAuth } from '../../hooks/api/useAuth';
|
||||
import styles from './LoginPage.module.css';
|
||||
import useBoundStore from '../../store';
|
||||
|
||||
export default function LoginPage() {
|
||||
const navigate = useNavigate();
|
||||
const token = useBoundStore((state) => state.token);
|
||||
const { login } = useAuth();
|
||||
const idRef = useRef('');
|
||||
const passwordRef = useRef('');
|
||||
// linkProps : 버튼 아래 나오는 링크(회원가입 등)에 대한 props object
|
||||
const linkProps = {
|
||||
message: '아직 회원이 아니신가요?',
|
||||
path: '../register',
|
||||
title: '회원가입',
|
||||
};
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
const handleSubmit = () => {
|
||||
// TODO: 로그인 POST 기능 추가
|
||||
console.log('로그인', idRef.current.value, passwordRef.current.value);
|
||||
const id = idRef.current.value;
|
||||
const password = passwordRef.current.value;
|
||||
|
||||
login(id, password).then(() => {
|
||||
navigate('/', { replace: true });
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (token) {
|
||||
navigate('/', { replace: true });
|
||||
}
|
||||
}, [navigate, token]);
|
||||
|
||||
return (
|
||||
<div className={styles.wrapper}>
|
||||
<AuthForm
|
||||
submitFunction={handleSubmit}
|
||||
onSubmit={handleSubmit}
|
||||
title="로그인"
|
||||
buttonText="로그인"
|
||||
linkProps={linkProps}
|
||||
|
@ -7,7 +7,8 @@ export default function PasswordResetPage() {
|
||||
const [sendEmail, setSendEmail] = useState(false);
|
||||
const emailRef = useRef('');
|
||||
const buttonText = useRef('비밀번호 찾기');
|
||||
const handleSubmit = () => {
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
// TODO: 비밀번호 찾기 POST 기능 추가
|
||||
console.log('비밀번호 찾기', emailRef.current.value);
|
||||
// delay
|
||||
@ -34,7 +35,7 @@ export default function PasswordResetPage() {
|
||||
) : (
|
||||
<div className={styles.wrapper}>
|
||||
<AuthForm
|
||||
submitFunction={handleSubmit}
|
||||
onSubmit={handleSubmit}
|
||||
title="비밀번호 찾기"
|
||||
buttonText={buttonText.current}
|
||||
>
|
||||
|
@ -1,6 +1,8 @@
|
||||
import styles from './UserRegisterPage.module.css';
|
||||
import { useRef, useState } from 'react';
|
||||
import { AuthForm, InputBox } from '../../components/AuthForm';
|
||||
import instance from '../../utils/axios/instance';
|
||||
import { API_URL } from '../../constants';
|
||||
|
||||
export default function UserRegisterPage() {
|
||||
const idRef = useRef();
|
||||
@ -11,13 +13,25 @@ export default function UserRegisterPage() {
|
||||
|
||||
const [passwordMatch, setPasswordMatch] = useState(true);
|
||||
|
||||
const handleSubmit = () => {
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
// TODO: 회원가입 POST 기능 추가
|
||||
if (passwordRef.current.value !== passwordConfirmRef.current.value) {
|
||||
setPasswordMatch(false);
|
||||
} else {
|
||||
setPasswordMatch(true);
|
||||
const isPWMatch = passwordRef.current.value === passwordConfirmRef.current.value;
|
||||
|
||||
setPasswordMatch(isPWMatch);
|
||||
if (!isPWMatch) {
|
||||
return;
|
||||
}
|
||||
|
||||
const userData = {
|
||||
userId: idRef.current.value,
|
||||
name: nameRef.current.value,
|
||||
email: emailRef.current.value,
|
||||
password: passwordRef.current.value,
|
||||
};
|
||||
|
||||
const response = await instance.post(`${API_URL}/user/join`, userData);
|
||||
console.log(response);
|
||||
};
|
||||
|
||||
const linkProps = {
|
||||
@ -29,7 +43,7 @@ export default function UserRegisterPage() {
|
||||
return (
|
||||
<div className={styles.wrapper}>
|
||||
<AuthForm
|
||||
submitFunction={handleSubmit}
|
||||
onSubmit={handleSubmit}
|
||||
title="회원가입"
|
||||
buttonText="회원가입"
|
||||
linkProps={linkProps}
|
||||
|
@ -3,6 +3,7 @@ import { userTypeSlice } from './userTypeSlice';
|
||||
import { tokenSlice } from './tokenSlice';
|
||||
|
||||
const useBoundStore = create((...a) => ({
|
||||
// TODO: persist 옵션 추가
|
||||
...userTypeSlice(...a),
|
||||
...tokenSlice(...a),
|
||||
}));
|
||||
|
@ -4,7 +4,10 @@ import useBoundStore from '../../store';
|
||||
const instance = axios.create({
|
||||
baseURL: import.meta.env.VITE_API_URL,
|
||||
timeout: 1000,
|
||||
headers: { 'X-Custom-Header': 'foobar' },
|
||||
headers: {
|
||||
'Content-type': 'application/json;charset=utf-8',
|
||||
'Access-Control-Allow-Origin': import.meta.env.VITE_ORIGIN,
|
||||
},
|
||||
});
|
||||
|
||||
instance.interceptors.request.use((config) => {
|
||||
|
Loading…
Reference in New Issue
Block a user