Skip to content
Binary file added front/public/images/googleLoginBtn.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added front/public/images/kakaoLoginBtn.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added front/public/images/naverLoginBtn.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions front/src/api/authApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
2 changes: 2 additions & 0 deletions front/src/components/RoutesComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -138,6 +139,7 @@ const RoutesComponent = () => {
<Route path="/redux" element={<ReduxPage />} />
<Route path="/button-test" element={<ButtonTest />} />
<Route path="/img-test" element={<ImgTest />} />
<Route path="/oauth/:site" element={<OauthPage />} />
<Route path="*" element={getElement(NoMatch, null)} />
</Routes>
);
Expand Down
16 changes: 8 additions & 8 deletions front/src/index.js
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -13,13 +13,13 @@ const container = document.getElementById('root');
const root = createRoot(container);

root.render(
<React.StrictMode>
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<App />
</PersistGate>
</Provider>
</React.StrictMode>
// <React.StrictMode>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

React.StrictMod 사용하면 안되는 이유가 있나요?

@serin-B serin-B Dec 8, 2022

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

<React.StrictMode> 때문에 get 요청이 2번씩 가더라고요!!
(검색해보니까 프로젝트의 src/index.js에서 <React.StrictMode> 태그로 이 감싸져있으면 개발모드에서 (개발 단계시 오류를 잘 잡기위해) 두 번씩 렌더링된다고 합니다!)
구현 과정에서 get 요청이 두 번 가서 오류가 나는 것 같다고 말씀해주셔서, 주석처리하고 테스트 해보았고, 그 뒤로 잘 되어서 일단 주석처리 하였습니다!
실제 서비스 배포할때에도 영향이 있는지는 조금 더 테스트해봐야할 것 같습니다!!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

논의 결과 수정이 필요한 부분으로 보입니다.

<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<App />
</PersistGate>
</Provider>
// </React.StrictMode>
);

reportWebVitals();
76 changes: 66 additions & 10 deletions front/src/pages/SignInPage/SignInPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -110,21 +140,47 @@ const SignInPage = () => {
입력하신 내용을 다시 확인해주세요.
</LoginErrorMsgStyled>
) : null}
<Grid container justifyContent="flex-end">
{/* <Grid container> */}
{/* <Grid item xs>
</Box>
<OauthBtns>
<BtnStyled className="google">
<a href="https://accounts.google.com/o/oauth2/v2/auth/oauthchooseaccount?response_type=code&client_id=293970161173-a059nllv4dpvc9quk4hqid4kservumh6.apps.googleusercontent.com&scope=email%20profile&redirect_uri=http://localhost:3000/oauth/google">
<img
src={process.env.PUBLIC_URL + '/images/googleLoginBtn.png'}
alt="google oauth login button"
/>
</a>
</BtnStyled>
<BtnStyled>
<a href="https://accounts.kakao.com/login/?continue=https%3A%2F%2Fkauth.kakao.com%2Foauth%2Fauthorize%3Fresponse_type%3Dcode%26redirect_uri%3Dhttp%253A%252F%252Flocalhost%253A3000%252Foauth%252Fkakao%26through_account%3Dtrue%26client_id%3De50e158c20358065eb3d6e2eabd76f5c">
<img
src={process.env.PUBLIC_URL + '/images/kakaoLoginBtn.png'}
alt="kakao oauth login button"
/>
</a>
</BtnStyled>
<BtnStyled>
<a href="https://nid.naver.com/oauth2.0/authorize?response_type=code&client_id=RZfvwjjGuUVmm8x8TDnY&redirect_uri=http://localhost:3000/oauth/naver">
<img
src={process.env.PUBLIC_URL + '/images/naverLoginBtn.png'}
alt="naver oauth login button"
/>
</a>
</BtnStyled>
</OauthBtns>
<Grid container justifyContent="flex-end">
{/* <Grid container> */}
{/* <Grid item xs>
<Link to="#" variant="body2">
Forgot password?
</Link>
</Grid> */}
<Grid item>
계정이 없으신가요?{' '}
<SignUpLinkStyled to="/user/signup" variant="body2">
회원가입
</SignUpLinkStyled>
</Grid>
<Grid item>
계정이 없으신가요?{' '}
<SignUpLinkStyled to="/user/signup" variant="body2">
회원가입
</SignUpLinkStyled>
</Grid>
</Box>
</Grid>
</PageContainer>
);
};
Expand Down
48 changes: 48 additions & 0 deletions front/src/pages/TestPage/OauthPage.js
Original file line number Diff line number Diff line change
@@ -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 (
<PageContainer>
<Loading />
</PageContainer>
);
};

export default OauthPage;
42 changes: 42 additions & 0 deletions front/src/store/modules/authSlice.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Comment thread
JinhuiKim marked this conversation as resolved.
} catch (error) {
return thunkAPI.rejectWithValue(error);
}
}
);

export const firstLoginAsync = createAsyncThunk(
'auth/firstLogin',
async (params, thunkAPI) => {
Expand Down Expand Up @@ -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;
Expand Down