feat: 로그인 기능 추가

This commit is contained in:
jhynsoo 2024-07-24 15:03:33 +09:00
parent 8ade28a2ed
commit 6e312e8ecb
8 changed files with 83 additions and 23 deletions

View File

@ -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>

View File

@ -8,6 +8,7 @@
height: 64px;
background-color: var(--background);
border-bottom: 1px solid var(--border-color);
z-index: 9999;
}
.nav {

View 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 };
}

View File

@ -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}

View File

@ -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}
>

View File

@ -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}

View File

@ -3,6 +3,7 @@ import { userTypeSlice } from './userTypeSlice';
import { tokenSlice } from './tokenSlice';
const useBoundStore = create((...a) => ({
// TODO: persist 옵션 추가
...userTypeSlice(...a),
...tokenSlice(...a),
}));

View File

@ -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) => {