diff --git a/front/public/images/googleLoginBtn.png b/front/public/images/googleLoginBtn.png
new file mode 100644
index 00000000..be552342
Binary files /dev/null and b/front/public/images/googleLoginBtn.png differ
diff --git a/front/public/images/kakaoLoginBtn.png b/front/public/images/kakaoLoginBtn.png
new file mode 100644
index 00000000..8d4d93cb
Binary files /dev/null and b/front/public/images/kakaoLoginBtn.png differ
diff --git a/front/public/images/naverLoginBtn.png b/front/public/images/naverLoginBtn.png
new file mode 100644
index 00000000..b7aa18ba
Binary files /dev/null and b/front/public/images/naverLoginBtn.png differ
diff --git a/front/src/api/authApi.js b/front/src/api/authApi.js
index c366f70b..bfadb202 100644
--- a/front/src/api/authApi.js
+++ b/front/src/api/authApi.js
@@ -77,6 +77,20 @@ const authApi = {
.catch((error) => reject(error));
});
},
+ oauth: ({ path, code }) => {
+ return new Promise((resolve, reject) => {
+ return axios
+ .get(`${path}${code}`)
+ .then((response) => {
+ signInSuccess(response);
+ setTimeout(authApi.logout, REFRESH_EXPIRY_TIME);
+ return resolve(response);
+ })
+ .catch((error) => {
+ return reject(error);
+ });
+ });
+ },
};
export default authApi;
diff --git a/front/src/components/RoutesComponent.js b/front/src/components/RoutesComponent.js
index 1dead1e3..231deeea 100644
--- a/front/src/components/RoutesComponent.js
+++ b/front/src/components/RoutesComponent.js
@@ -2,6 +2,7 @@ import { Routes, Route, Navigate } from 'react-router-dom';
import { useSelector } from 'react-redux';
import { selectFirstLogin, selectIsLogin } from 'store/modules/authSlice';
import LandingPage from 'pages/LandingPage';
+import OauthPage from 'pages/TestPage/OauthPage';
import {
MainPage,
SignUpPage,
@@ -138,6 +139,7 @@ const RoutesComponent = () => {
} />
} />
} />
+ } />
);
diff --git a/front/src/index.js b/front/src/index.js
index 99c8271a..86fa9c5f 100644
--- a/front/src/index.js
+++ b/front/src/index.js
@@ -1,4 +1,4 @@
-import React from 'react';
+// import React from 'react';
import { createRoot } from 'react-dom/client';
import { Provider } from 'react-redux';
import { store } from './store/store';
@@ -13,13 +13,13 @@ const container = document.getElementById('root');
const root = createRoot(container);
root.render(
-
-
-
-
-
-
-
+ //
+
+
+
+
+
+ //
);
reportWebVitals();
diff --git a/front/src/pages/SignInPage/SignInPage.js b/front/src/pages/SignInPage/SignInPage.js
index 9049b920..26b6ad50 100644
--- a/front/src/pages/SignInPage/SignInPage.js
+++ b/front/src/pages/SignInPage/SignInPage.js
@@ -34,6 +34,36 @@ const AvatarStyled = styled(Avatar)`
background-color: ${({ theme }) => theme.colors.purple_2};
`;
+const OauthBtns = styled.div`
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ width: 100%;
+ margin-top: -5px;
+ .google {
+ border: 1px solid rgba(0, 0, 0, 0.1);
+ }
+`;
+
+const BtnStyled = styled.div`
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: 100%;
+ height: 40px;
+ margin: 5px;
+ border-radius: 20px;
+ overflow: hidden;
+ &:hover {
+ box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
+ }
+ img {
+ margin-top: 5px;
+ height: 45px;
+ }
+`;
+
const SignInPage = () => {
const navigate = useNavigate();
const dispatch = useDispatch();
@@ -110,21 +140,47 @@ const SignInPage = () => {
입력하신 내용을 다시 확인해주세요.
) : null}
-
- {/* */}
- {/*
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* */}
+ {/*
Forgot password?
*/}
-
- 계정이 없으신가요?{' '}
-
- 회원가입
-
-
+
+ 계정이 없으신가요?{' '}
+
+ 회원가입
+
-
+
);
};
diff --git a/front/src/pages/TestPage/OauthPage.js b/front/src/pages/TestPage/OauthPage.js
new file mode 100644
index 00000000..8efa7875
--- /dev/null
+++ b/front/src/pages/TestPage/OauthPage.js
@@ -0,0 +1,48 @@
+import { useEffect } from 'react';
+import { useDispatch } from 'react-redux';
+import { useNavigate } from 'react-router-dom';
+import { oauthAsync } from 'store/modules/authSlice';
+import { setOpenSnackbar } from 'store/modules/snackbarSlice';
+import PageContainer from 'containers/PageContainer';
+import Loading from 'components/Loading';
+
+const OauthPage = () => {
+ const dispatch = useDispatch();
+ const navigate = useNavigate();
+ useEffect(() => {
+ const path = location.pathname;
+ const code = location.search;
+ getOauthCode(path, code);
+ }, []);
+
+ const getOauthCode = (path, code) => {
+ dispatch(oauthAsync({ path, code }))
+ .unwrap()
+ .then(() => {
+ dispatch(
+ setOpenSnackbar({
+ severity: 'success',
+ message: '로그인이 완료되었습니다.',
+ })
+ );
+ navigate('/', { replace: true });
+ })
+ .catch((err) => {
+ console.log(err);
+ dispatch(
+ setOpenSnackbar({
+ severity: 'error',
+ message: `${err.message}로 인해 로그인 실패하였습니다`,
+ })
+ );
+ navigate('/', { replace: true });
+ });
+ };
+ return (
+
+
+
+ );
+};
+
+export default OauthPage;
diff --git a/front/src/store/modules/authSlice.js b/front/src/store/modules/authSlice.js
index 380ff33a..58c3464f 100644
--- a/front/src/store/modules/authSlice.js
+++ b/front/src/store/modules/authSlice.js
@@ -24,6 +24,21 @@ export const signInAsync = createAsyncThunk(
}
);
+export const oauthAsync = createAsyncThunk(
+ 'auth/oauth',
+ async ({ path, code }, thunkAPI) => {
+ console.log('path', path);
+ console.log('code', code);
+ try {
+ const response = await authApi.oauth({ path, code });
+ console.log('성공하면 오는 res', response.data);
+ return response.data.data;
+ } catch (error) {
+ return thunkAPI.rejectWithValue(error);
+ }
+ }
+);
+
export const firstLoginAsync = createAsyncThunk(
'auth/firstLogin',
async (params, thunkAPI) => {
@@ -81,6 +96,33 @@ export const authSlice = createSlice({
state.roles = [];
state.profileImage = '';
})
+ .addCase(oauthAsync.pending, (state) => {
+ state.loading = true;
+ state.isLogin = false;
+ state.firstLogin = false;
+ state.nickName = '';
+ state.email = '';
+ state.roles = [];
+ state.profileImage = '';
+ })
+ .addCase(oauthAsync.fulfilled, (state, { payload }) => {
+ state.loading = false;
+ state.isLogin = true;
+ state.firstLogin = payload.firstLogin;
+ state.nickName = payload.nickName;
+ state.email = payload.email;
+ state.roles = payload.roles;
+ state.profileImage = payload.profileImage;
+ })
+ .addCase(oauthAsync.rejected, (state) => {
+ state.loading = false;
+ state.isLogin = false;
+ state.firstLogin = false;
+ state.nickName = '';
+ state.email = '';
+ state.roles = [];
+ state.profileImage = '';
+ })
.addCase(firstLoginAsync.pending, (state) => {
state.loading = true;
state.isLogin = false;