Skip to content

Commit

Permalink
Feat: 기본 로그인 기능 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
jseo9732 committed Jan 6, 2024
1 parent d800153 commit 46ba74e
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 46 deletions.
4 changes: 2 additions & 2 deletions src/@types/auth.types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
interface AuthRequest {
export interface AuthRequest {
email: string;
password: string;
name: string;
Expand All @@ -9,7 +9,7 @@ interface AuthRequest {
survey: string;
}

interface LoginRequest {
export interface LoginFormVlaue {
email: string;
password: string;
}
9 changes: 9 additions & 0 deletions src/components/user/ErrorMessage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
interface Props {
children: string;
}

const ErrorMessage = ({ children }: Props) => {
return <p className="body6 text-red">{children}</p>;
};

export default ErrorMessage;
3 changes: 2 additions & 1 deletion src/components/user/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import UserInputBox from './useInputBox/UserInputBox';
import UserEmailInputBox from './useInputBox/UserEmailInputBox';
import UserPwInputBox from './useInputBox/UserPwInputBox';
import ErrorMessage from './ErrorMessage';

export { UserInputBox, UserEmailInputBox, UserPwInputBox };
export { UserInputBox, UserEmailInputBox, UserPwInputBox, ErrorMessage };
41 changes: 19 additions & 22 deletions src/components/user/useInputBox/UserInputBox.tsx
Original file line number Diff line number Diff line change
@@ -1,52 +1,49 @@
import { useState } from 'react';
import { CloseIcon } from '@components/common/icons/Icons';
import { UseFormRegisterReturn, UseFormSetValue } from 'react-hook-form';
import { LoginFormVlaue } from '@/@types/auth.types';

interface Props {
label: string;
type?: string;
name: string;
id: 'email' | 'password';
type?: 'text' | 'email' | 'password';
placeholder: string;
// children: React.ReactNode;
validifyCheckList?: string[];
// onInputBlur: VoidFunction;
register: UseFormRegisterReturn;
inputValue: string;
setValue: UseFormSetValue<LoginFormVlaue>;
marginB?: string;
// validifyCheckList?: string[];
// onInputBlur: VoidFunction;
// children: React.ReactNode;
}

const UserInputBox = ({
label,
type = 'password',
name,
id,
type = 'text',
placeholder,
// validifyCheckList,
register,
inputValue,
setValue,
marginB = 'mb-6',
}: Props) => {
const [inputValue, setInputValue] = useState('');

const onInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setInputValue(e.target.value);
};

return (
<div className={`${marginB} flex flex-col gap-2`}>
<div className="flex flex-col gap-2">
<label htmlFor={label} className="body3 text-main2">
<label htmlFor={id} className="body3 text-main2">
{label}
</label>
<div className="flex h-10 items-center border-b-[1.25px] border-solid border-gray3 focus-within:border-main1">
<input
id={label}
id={id}
className="w-full text-sm font-normal outline-none placeholder:text-gray3"
type={type}
name={name}
placeholder={placeholder}
required
value={inputValue}
onChange={onInputChange}
{...register}
/>
{inputValue && (
<div
onClick={() => {
setInputValue('');
setValue(id, '');
}}>
<CloseIcon size={20} color="white" fill="#888888" />
</div>
Expand Down
85 changes: 64 additions & 21 deletions src/pages/login/login.page.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,52 @@
import { postEmailLogin } from '@api/auth';
import authCient from '@api/authClient';
import SubmitBtn from '@components/common/button/SubmitBtn';
import Back from '@components/common/back/Back';
import { KakaoIcon, LogoIcon } from '@components/common/icons/Icons';
import { UserInputBox } from '@components/user';
import { ErrorMessage, UserInputBox } from '@components/user';
import { useNavigate } from 'react-router-dom';
import { SubmitHandler, useForm } from 'react-hook-form';
import { LoginFormVlaue } from '@/@types/auth.types';
import { useState } from 'react';
import { AxiosError } from 'axios';

const Login = () => {
const navigate = useNavigate();
const {
register,
handleSubmit,
watch,
setValue,
formState: { errors },
} = useForm<LoginFormVlaue>({
reValidateMode: 'onSubmit',
// 다른 옵션들...
});

const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
const emailValue = formData.get('email');
const pwValue = formData.get('pw');
const [isLoginFailed, setIsLoginFailed] = useState<boolean>(false);

const res = await postEmailLogin({
email: emailValue as string,
password: pwValue as string,
});

if (res.data.status === 200) {
window.localStorage.setItem(
'accessToken',
res.data.data.tokenInfo.accessToken,
);
navigate('/');
const onLoginSubmit: SubmitHandler<LoginFormVlaue> = async (data) => {
const { email, password } = data;
try {
const res = await postEmailLogin({
email,
password,
});
if (res.data.status === 200) {
authCient.defaults.headers.common['Authorization'] =
res.data.data.tokenInfo.accessToken;
navigate('/');
}
} catch (err) {
if (err instanceof AxiosError) {
console.error('로그인 중 에러 발생', err);
if (err.response?.data.errorMessage) {
setIsLoginFailed(true);
}
}
}
};

return (
<div className="flex h-[95vh] flex-col">
<Back />
Expand All @@ -39,18 +59,42 @@ const Login = () => {
위플랜플랜즈에 오신 것을 환영합니다.
</h1>
</div>
<form className="mb-auto" onSubmit={handleSubmit}>
<form className="mb-auto" onSubmit={handleSubmit(onLoginSubmit)}>
<UserInputBox
label={'이메일'}
id="email"
type="email"
name="email"
placeholder={'이메일을 입력하세요'}
register={register('email', { required: '아이디를 입력해주세요.' })}
inputValue={watch('email')}
setValue={setValue}
/>
<UserInputBox
label={'비밀번호'}
name="pw"
id="password"
type="password"
placeholder={'비밀번호를 입력하세요'}
register={register('password', {
required: '비밀번호를 입력해주세요.',
})}
inputValue={watch('password')}
setValue={setValue}
/>
{errors.email?.type === 'required' && (
<ErrorMessage>{`${errors.email?.message}`}</ErrorMessage>
)}
{!errors.email && errors.password?.type === 'required' && (
<ErrorMessage>비밀번호를 입력해 주세요!</ErrorMessage>
)}
{!errors.email && !errors.password && isLoginFailed && (
<>
<ErrorMessage>
아이디(로그인 전용 아이디) 또는 비밀번호를 잘못 입력했습니다.
</ErrorMessage>
<ErrorMessage>입력하신 내용을 다시 확인해주세요.</ErrorMessage>
</>
)}

<SubmitBtn>로그인</SubmitBtn>
</form>
</div>
Expand All @@ -65,7 +109,6 @@ const Login = () => {
<KakaoIcon />
카카오로 로그인
</button>

<SubmitBtn outline type="button">
회원가입
</SubmitBtn>
Expand Down

0 comments on commit 46ba74e

Please sign in to comment.