Skip to content

Commit

Permalink
feat : 로그인 페이지 1차 개발 완료 (#124)
Browse files Browse the repository at this point in the history
* chore : [임시] 인풋폼 배경색 추가

* feat : 로그인 관련 msw 핸들러 작성

* feat : axios instance 생성

* feat : 로그인 관련 타입 추가

* feat : 로그인 함수 추가

* feat : 로그인 페이지 작성

* chore : 경로 수정

* chore : 환경변수 ignore

* fix : 변수명 수정

* chore : 콘솔 제거

* fix : login 핸들러 누락된 status 추가
  • Loading branch information
cmlim0070 authored Nov 29, 2024
1 parent bb6c2b0 commit fc8e3a7
Show file tree
Hide file tree
Showing 10 changed files with 214 additions and 6 deletions.
9 changes: 8 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,11 @@ dist-ssr
!.yarn/sdks
!.yarn/versions
*storybook.log
vite_cache
vite_cache


# env files
.env
.env.local
.env.development
.env.production
1 change: 1 addition & 0 deletions src/components/Common/Input/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export const Input = ({
<p className="mb-3 text-14 text-secondary md:text-16">{text}</p>
)}
<input
className="bg-slate-100"
autoComplete="off"
name={name}
value={value}
Expand Down
92 changes: 92 additions & 0 deletions src/mocks/handlers/LoginHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { http, HttpResponse } from 'msw';
import { UserType } from '@/types/user';

type LoginRequestBody = {
email: string;
password: string;
};

type LoginResponseBody = {
code: number;
status: string;
message: string;
data: string | UserType;
};

export const LoginHandler = [
http.post<never, LoginRequestBody, LoginResponseBody, '*/auth/signin'>(
'*/auth/signin',
async ({ request }) => {
const { email } = await request.json();
console.log(email);
// 로그인 성공
if (email === '[email protected]') {
return HttpResponse.json(
{
code: 200,
status: 'OK',
message: '로그인 성공',
data: {
email: email,
nickname: '테스트유저',
profileImageUrl: 'sample.jpg'
}
},
{
status: 200
},
{
headers: {
'Content-Type': 'application/json',
'Set-Cookie':
'accessToken=test-token123; Path=/; HttpOnly'
}
}
);
}

// 존재하지 않는 유저
if (email === '[email protected]') {
return HttpResponse.json(
{
code: 400,
status: 'USER_NOT_FOUND',
message: '존재하지 않는 유저',
data: null
},
{
status: 400
}
);
}

// 오류
if (email === '[email protected]') {
return HttpResponse.json(
{
code: 500,
status: 'INTERNER_SERVER_ERROR',
message: '로그인 실패',
data: null
},
{
status: 500
}
);
}

// 기본 에러
return HttpResponse.json(
{
code: 400,
status: 'BAD_REQUEST',
message: '잘못된 요청입니다',
data: null
},
{
status: 400
}
);
}
)
];
3 changes: 2 additions & 1 deletion src/mocks/handlers/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { signUpHandler } from './signUpHandler';
import { LoginHandler } from './LoginHandler';

export const handlers = [...signUpHandler];
export const handlers = [...signUpHandler, ...LoginHandler];
3 changes: 0 additions & 3 deletions src/pages/LoginPage.tsx

This file was deleted.

47 changes: 47 additions & 0 deletions src/pages/User/Login/LoginPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React from 'react';
import { useNavigate } from 'react-router-dom';
import { EmailInput } from '@/components/Common/Input/EmailInput';
import { PasswordInput } from '@/components/Common/Input/PasswordInput';
import { useUserStore } from '@/stores/useUserStore';
import { login } from '@/service/auth/login';

// 성공 시나리오 [email protected]
// 존재하지 않는 유저 [email protected]
// 서버 오류 [email protected]
export const LoginPage = () => {
const navigate = useNavigate();
const { setUser } = useUserStore();

const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
const $loginForm = e.target as HTMLFormElement;
const loginFormData = new FormData($loginForm);
const [email, password] = [
loginFormData.get('email'),
loginFormData.get('password')
];

login({ email, password }).then((response) => {
setUser(response.data);
console.log('로그인 완료 : ', response.data);
navigate('/');
});
};

return (
<div className="p-3 flex flex-col gap-3">
<form className=" flex flex-col gap-5" onSubmit={handleSubmit}>
<h2 className="font-bold text-2xl ">로그인</h2>
<div className="flex flex-col gap-10">
<EmailInput></EmailInput>
<PasswordInput></PasswordInput>
<button className="bg-slate-200">로그인</button>
</div>
</form>
<div className="flex flex-col gap-3">
<div className="bg-slate-200">회원가입</div>
<div className="bg-slate-200">회원 정보 찾기</div>
</div>
</div>
);
};
2 changes: 1 addition & 1 deletion src/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { HomePage } from '@/pages/Home/HomePage';
import { CreateLetterPage } from '@/pages/Letter/Create/CreateLetterPage';
import { MapExplorerPage } from '@/pages/MapExplorerPage';
import { MyPage } from '@/pages/User/MyPage/Mypage';
import { LoginPage } from '@/pages/LoginPage';
import { LoginPage } from '@/pages/User/Login/LoginPage';
import { RegisterPage } from '@/pages/RegisterPage';
import { ArchivedPage } from '@/pages/ArchivedPage';
import { LabelCollectionsPage } from '@/pages/LabelCollectionsPage';
Expand Down
12 changes: 12 additions & 0 deletions src/service/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import axios, { AxiosRequestConfig, AxiosInstance } from 'axios';

const baseUrl = import.meta.env.VITE_API_URL as string;

export const defaultApi = (option?: AxiosRequestConfig): AxiosInstance => {
const instance = axios.create({
baseURL: baseUrl,
withCredentials: true,
...option
});
return instance;
};
43 changes: 43 additions & 0 deletions src/service/auth/login.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { AxiosError } from 'axios';
import { LoginType } from '@/types/login';
import { defaultApi } from '@/service/api';

type LoginProps = {
email: string;
password: string;
};

type AuthError = {
message: string;
statusCode?: number;
code?: string;
};

export async function login({
email,
password
}: LoginProps): Promise<LoginType> {
const api = defaultApi();

try {
const response = await api.post('/auth/signin', { email, password });
return response.data;
} catch (error) {
if (error instanceof AxiosError) {
if (error.response?.status === 400) {
const authError: AuthError = {
message: '존재하지 않는 사용자입니다.',
statusCode: error.response.status,
code: 'USER_NOT_FOUND'
};
throw authError;
}
}
const unknownError: AuthError = {
message: '로그인 중 오류가 발생했습니다.',
statusCode: 500,
code: 'UNKNOWN_ERROR'
};
throw unknownError;
}
}
8 changes: 8 additions & 0 deletions src/types/login.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
type LoginType = {
code: number;
status: string;
message: string;
data: string;
};

export type { LoginType };

0 comments on commit fc8e3a7

Please sign in to comment.