Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 12 additions & 60 deletions src/apis/auth.api.ts
Original file line number Diff line number Diff line change
@@ -1,70 +1,22 @@
import httpClient from './http.api'; // Axios 인스턴스 가져오기
import { JoinProps } from '@/pages/JoinPage';
import { LoginProps } from '@/pages/LoginPage';
import { JoinProps } from '@/pages/JoinPage';
import httpClient from './http.api';

// 회원가입 요청
export const join = async (userData: JoinProps) => {
try {
const { data, status } = await httpClient.post('/api/users/join', userData);

if (status === 200) {
console.log('회원가입 성공:', data);
return data;
} else if (status === 400 && data.message.includes('입력해주세요')) {
console.error('필수 입력값 없음:', data.message);
throw new Error(data.message);
} else if (status === 400 && data.message.includes('중복된')) {
console.error('중복 오류:', data.message);
throw new Error(data.message);
} else {
throw new Error('알 수 없는 회원가입 에러가 발생했습니다.');
}
} catch (error) {
console.error('회원가입 요청 중 에러 발생:', error);
throw new Error('회원가입 요청에 실패했습니다. 관리자에게 문의하세요.');
}
export const join = async (data: JoinProps) => {
const response = await httpClient.post('/api/users/join', data);
return response.data;
};

interface LoginResponse {
export interface LoginResponse {
message: any;
success: boolean;
token?: string;
}

// 로그인 요청
export const login = async (data: LoginProps): Promise<LoginResponse> => {
try {
const { data: responseData, status } = await httpClient.post<LoginResponse>(
'/api/users/login',
data
);

if (status === 200 && responseData.success) {
console.log('로그인 성공:', responseData);
return responseData;
} else if (
status === 400 &&
responseData.message.includes('입력해주세요')
) {
console.error('필수 입력값 없음:', responseData.message);
throw new Error(responseData.message);
} else if (
status === 404 &&
responseData.message.includes('등록되지 않은 이메일')
) {
console.error('등록되지 않은 이메일:', responseData.message);
throw new Error(responseData.message);
} else if (
status === 401 &&
responseData.message.includes('비밀번호가 틀렸습니다')
) {
console.error('비밀번호 오류:', responseData.message);
throw new Error(responseData.message);
} else {
throw new Error('알 수 없는 로그인 에러가 발생했습니다.');
}
} catch (error) {
console.error('로그인 요청 중 에러 발생:', error);
throw new Error('로그인 요청에 실패했습니다. 관리자에게 문의하세요.');
}
export const login = async (data: LoginProps) => {
const response = await httpClient.post<LoginResponse>(
'/api/users/login',
data
);
return response.data;
};
41 changes: 2 additions & 39 deletions src/apis/http.api.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import axios, { AxiosInstance, AxiosRequestConfig } from 'axios';
import { getToken, removeToken } from '@/store/slices/authSlice'; // 토큰 유틸리티 함수 import
import axios, { AxiosInstance, AxiosRequestConfig, AxiosHeaders } from 'axios';
import { getToken, removeToken } from '@/utils/token'; // 토큰 유틸리티 함수 import
import { logout } from '@/store/slices/authSlice';
import { store } from '@/store/store';

Expand Down Expand Up @@ -64,42 +64,5 @@ export const createClient = (config?: AxiosRequestConfig): AxiosInstance => {
// 기본 Axios 인스턴스 생성
export const httpClient = createClient();

// API 요청 함수
export const authApi = {
join: async (data: { email: string; password: string; nickname: string }) => {
try {
const response = await httpClient.post('/api/signup', data);
return response.data;
} catch (error) {
console.error('Signup API Error:', error);
throw error;
}
},
login: async (data: { email: string; password: string }) => {
try {
const response = await httpClient.post('/api/login', data);
const { token } = response.data;

// 토큰 저장
localStorage.setItem('accessToken', token); // 필요 시 유틸리티 함수 사용 가능
return response.data;
} catch (error) {
console.error('Login API Error:', error);
throw error;
}
},
logout: async () => {
try {
await httpClient.post('/api/logout');
removeToken(); // 토큰 삭제
store.dispatch(logout()); // Redux 상태 초기화
window.location.href = '/login'; // 로그인 페이지로 리다이렉트
} catch (error) {
console.error('Logout API Error:', error);
throw error;
}
},
};

// 기본 Axios 인스턴스 내보내기
export default httpClient;
36 changes: 22 additions & 14 deletions src/pages/LoginPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import { useNavigate } from 'react-router';
import qublogo from '@/assets/qublogo.svg';
import Input from '@/components/atoms/Input';
import { useForm } from 'react-hook-form';
import { login } from '@/apis/auth.api';
import { useState } from 'react';
import { useDispatch, useSelector } from 'react-redux'; // Redux 추가
import { AppDispatch, RootState } from '@/store/store'; // Redux 타입 가져오기
import { loginThunk } from '@/store/slices/authSlice'; // Thunk 가져오기

export interface LoginProps {
email: string;
Expand All @@ -13,28 +14,33 @@ export interface LoginProps {

function LoginPage() {
const navigate = useNavigate();
const dispatch = useDispatch<AppDispatch>();

const { loading, error, isLoggedIn } = useSelector(
(state: RootState) => state.auth
);

const {
register,
handleSubmit,
formState: { errors },
} = useForm<LoginProps>();

const [isLoading, setIsLoading] = useState(false); // 로딩 상태 추가

const onSubmit = async (data: LoginProps) => {
setIsLoading(true);
try {
await login(data);
const result = await dispatch(loginThunk(data));

if (loginThunk.fulfilled.match(result)) {
alert('로그인에 성공했습니다!');
navigate('/'); // 로그인 성공 시 메인 페이지로 이동
} catch (error: any) {
console.error('로그인 실패:', error);
alert(error.message || '로그인에 실패했습니다. 다시 시도해주세요.');
} finally {
setIsLoading(false);
} else {
alert(result.payload || '로그인에 실패했습니다. 다시 시도해주세요.');
}
};

// 로그인 상태 확인 후 리다이렉트 처리
if (isLoggedIn) {
navigate('/');
}
Comment on lines +41 to +43
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

컴포넌트 렌더링 시에 영향을 끼치는 작업들은 useEffect 내부에서 처리해야합니다.

물론 지금은 아무런 문제가 없어 보이고 잘 리다이렉트 되는 것 같지만,
이는 불필요한 렌더링을 야기할 수 있기 때문에 react에서는 권장하지 않는 형태입니다 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning이 떠서 삭제했습니다!

return (
<Container>
<InnerWrapper>
Expand All @@ -61,8 +67,10 @@ function LoginPage() {
</InputWrapper>
{errors.password && <ErrorText>{errors.password.message}</ErrorText>}

<SubmitButton type='submit' disabled={isLoading}>
{isLoading ? '로그인 중...' : '로그인'}
{error && <ErrorText>{error}</ErrorText>}

<SubmitButton type='submit' disabled={loading}>
{loading ? '로그인 중...' : '로그인'}
</SubmitButton>
</Form>

Expand Down
Loading