Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ticket-v0.0.1-5) : 카카오 로그인 #49

Merged
merged 2 commits into from
Jan 11, 2023
Merged
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
3 changes: 2 additions & 1 deletion apps/admin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.6.1",
"recoil": "^0.7.6"
"recoil": "^0.7.6",
"vite-plugin-svgr": "^2.4.0"
},
"devDependencies": {
"@types/react": "^18.0.26",
Expand Down
2 changes: 1 addition & 1 deletion apps/admin/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import App from './App';
const queryClient = new QueryClient();

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<BrowserRouter>
<BrowserRouter basename="/admin">
<Global styles={globalStyle} />
<ThemeProvider theme={theme}>
<RecoilRoot>
Expand Down
2 changes: 1 addition & 1 deletion apps/admin/src/pages/Sample.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Button } from '@dudoong/ui';
const Sample = () => {
return (
<>
<Button>react + vite + typescript 어드민 보일러플레이트</Button>
<Button isLoading>react + vite + typescript 어드민 보일러플레이트</Button>
</>
);
};
Expand Down
2 changes: 2 additions & 0 deletions apps/admin/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import svgr from 'vite-plugin-svgr';

// https://vitejs.dev/config/
export default defineConfig({
plugins: [
svgr(),
react({
jsxImportSource: '@emotion/react',
babel: {
Expand Down
3 changes: 2 additions & 1 deletion apps/ticket/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"typescript": "4.9.4"
},
"devDependencies": {
"@emotion/babel-plugin": "^11.10.5"
"@emotion/babel-plugin": "^11.10.5",
"@svgr/webpack": "^6.5.1"
}
}
53 changes: 41 additions & 12 deletions apps/ticket/src/components/auth/Callback.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,50 @@
import useGlobalOverlay from '@lib/hooks/useGlobalOverlay';
import { FullScreen, SyncLoader } from '@dudoong/ui';
import { AuthApi, OauthTokenResponse } from '@dudoong/utils';
import { css } from '@emotion/react';
import { useMutation } from '@tanstack/react-query';
import { useRouter } from 'next/router';
import { useEffect } from 'react';
import { useEffect, useState } from 'react';
import useAuthMutate from './useAuthMutate';

//카카오 로그인 리다이렉트 페이지
const Callback = () => {
const [tokens, setTokens] = useState<OauthTokenResponse>({
accessToken: '',
idToken: '',
refreshToken: '',
});
const router = useRouter();
const { idToken, accessToken, refreshToken } = router.query;
const { openOverlay } = useGlobalOverlay();
console.log(idToken);
const openLoginTest = () => {
idToken && openOverlay({ content: 'register', props: { idToken } });
};
const { code } = router.query as unknown as { code: string };
const { oauthValidMutation } = useAuthMutate(tokens);

const oauthTokenMutation = useMutation(AuthApi.OAUTH_TOKEN, {
onSuccess: (data: OauthTokenResponse) => {
setTokens(data);
},
});

useEffect(() => {
if (code) {
oauthTokenMutation.mutate(code);
}
}, [code]);
useEffect(() => {
localStorage.setItem('accessToken', accessToken as string);
openLoginTest();
}, []);
return <>로그인중</>;
if (tokens.idToken.length > 0) {
oauthValidMutation.mutate(tokens.idToken);
}
}, [tokens]);

return (
<FullScreen
css={css`
display: flex;
align-items: center;
justify-content: center;
`}
>
<SyncLoader />
</FullScreen>
);
};

export default Callback;
73 changes: 73 additions & 0 deletions apps/ticket/src/components/auth/useAuthMutate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import {
AuthApi,
OauthInfoResponse,
OauthLoginResponse,
OauthTokenResponse,
} from '@dudoong/utils';
import useGlobalOverlay from '@lib/hooks/useGlobalOverlay';
import { authState } from '@store/auth';
import { useMutation } from '@tanstack/react-query';
import { useRouter } from 'next/router';
import { useRecoilState } from 'recoil';

const useAuthMutate = ({ idToken, accessToken }: OauthTokenResponse) => {
const { openOverlay, closeOverlay } = useGlobalOverlay();
const [auth, setAuth] = useRecoilState(authState);
const router = useRouter();

// 카카오 회원정보 가져오기
const ouathKakaoInfoMutation = useMutation(AuthApi.OAUTH_INFO, {
onSuccess: (data: OauthInfoResponse) => {
openOverlay({
content: 'register',
props: {
name: data.name,
onMainActionClick: () => {
ouathKakaoRegisterMutation.mutate({ idToken, payload: data });
},
},
});
},
});

// 회원가입
const ouathKakaoRegisterMutation = useMutation(AuthApi.OAUTH_REGISTER, {
onSuccess: (data: OauthLoginResponse) => {
localStorage.setItem('refreshToken', data.refreshToken);
onSuccessLogin(data);
closeOverlay();
router.push(auth.callbackUrl);
},
});

// 로그인
const ouathKakaoLoginMutation = useMutation(AuthApi.OAUTH_LOGIN, {
onSuccess: (data: OauthLoginResponse) => {
localStorage.setItem('refreshToken', data.refreshToken);
onSuccessLogin(data);
router.push(auth.callbackUrl);
},
});

// 회원가입 여부 (kakaoCallback 진입)
const oauthValidMutation = useMutation(AuthApi.OAUTH_VALID, {
onSuccess: (data: { canRegister: boolean }) => {
if (data.canRegister) {
// 회원가입 필요
ouathKakaoInfoMutation.mutate(accessToken);
} else {
// 바로 로그인
ouathKakaoLoginMutation.mutate(idToken);
}
},
});

const onSuccessLogin = (loginData: OauthLoginResponse) => {
console.log(loginData);
setAuth({ ...auth, isAuthenticated: true, ...loginData });
};

return { oauthValidMutation, ouathKakaoLoginMutation };
};

export default useAuthMutate;
4 changes: 2 additions & 2 deletions apps/ticket/src/components/mypage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ const Mypage = () => {
<>
<DDHead title="두둥! | 마이페이지" />
<LayoutContainer>
<ListHeader title={'마이페이지'} variant={'listHeader_28'} />
<ListHeader title={'마이페이지'} size={'listHeader_28'} />
<Padding size={[20, 24]}>
<Profile size="big" name="한규진" subText="010-5536-4937" />
</Padding>
<Divider />
<ListHeader title={'바로가기'} />
<ListHeader title={'바로가기'} size={'listHeader_20'} />
</LayoutContainer>
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ export interface OverlayBoxProps {
}
const OverlayBox = ({ open, onDismiss, children }: OverlayBoxProps) => {
const { isPC } = useResponsive();

return (
<>
{isPC ? (
Expand Down
15 changes: 2 additions & 13 deletions apps/ticket/src/components/shared/overlay/content/Login.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { Button, ButtonSet, ListHeader, Text, theme } from '@dudoong/ui';
import { Button, ButtonSet, ListHeader } from '@dudoong/ui';
import { AuthApi } from '@dudoong/utils';
import { css } from '@emotion/react';

const Login = () => {
const onLogin = async () => {
const data = await AuthApi.OAUTH_LINK();
window.location.href = data.data.link;
window.location.href = data.link;
};
return (
<>
Expand All @@ -15,16 +14,6 @@ const Login = () => {
<Button varient="kakao" onClick={onLogin}>
카카오로 로그인하기
</Button>
<button
css={css`
color: ${theme.palette.gray_300};
&:hover {
text-decoration: underline;
}
`}
>
<Text typo={'Text_16'}>또는, 회원가입하기</Text>
</button>
</>
</ButtonSet>
</>
Expand Down
25 changes: 11 additions & 14 deletions apps/ticket/src/components/shared/overlay/content/Register.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,42 +3,39 @@ import { css } from '@emotion/react';

interface RegisterProps {
name: string;
payload: any;
onMainActionClick: () => void;
}

const Register = ({ name, payload }: RegisterProps) => {
const onRegister = async () => {
console.log(payload);
};
const Register = ({ name, onMainActionClick }: RegisterProps) => {
return (
<>
<ListHeader
size="listHeader_20"
title={
<Text typo="Header_20" color="black">
`<span css={{ color: `${theme.palette.main_500}` }}>{name}</span>님,
안녕하세요!`
<span css={{ color: `${theme.palette.main_500}` }}>{name}</span>님,
안녕하세요!
</Text>
}
description={
<Text
css={css`
color: ${theme.palette.gray_500};
text-decoration: underline;
&:hover {
text-decoration: underline;
color: ${theme.palette.gray_400};
}
`}
typo="Text_16"
typo="Text_14"
>
두둥 서비스 약관
</Text>
}
/>
<ButtonSet varient="mono" padding={[20, 24]}>
<>
<Button varient="kakao" onClick={onRegister}>
약관 동의하고 시작하기
</Button>
</>
<Button varient="kakao" onClick={onMainActionClick}>
약관 동의하고 시작하기
</Button>
</ButtonSet>
</>
);
Expand Down
5 changes: 5 additions & 0 deletions apps/ticket/src/lib/hooks/useRefresh.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const useRefresh = () => {
return 1;
};

export default useRefresh;
5 changes: 0 additions & 5 deletions apps/ticket/src/lib/hooks/useSample.ts

This file was deleted.

49 changes: 24 additions & 25 deletions apps/ticket/src/store/auth.ts
Original file line number Diff line number Diff line change
@@ -1,43 +1,42 @@
import { axiosPrivate } from '@dudoong/utils';
import { isServer } from '@dudoong/utils/src/utils/isServer';
import { atom } from 'recoil';

export interface IAuthType {
export interface AuthStateType {
isAuthenticated: boolean;
registerToken: string;
phoneNumber: string;
inProcess: boolean;
callbackUrl: string;
accessToken: string;
refreshToken: string;
userProfile: {
id: number;
profileImage: string;
name: string;
} | null;
}

const initialState = {
const initialState: AuthStateType = {
isAuthenticated: false,
registerToken: '',
phoneNumber: '',
inProcess: false,
callbackUrl: '/',
accessToken: '',
refreshToken: '',
userProfile: null,
};

const getTokenFromLocalStorage = (): IAuthType => {
let accessToken = '';
let registerToken = '';
if (typeof window !== 'undefined') {
accessToken = localStorage.getItem('accessToken') || '';
registerToken = localStorage.getItem('registerToken') || '';
const getTokenFromLocalStorage = (): AuthStateType => {
let refreshToken = '';
if (isServer()) {
refreshToken = localStorage.getItem('refreshToken') || '';
}
if (accessToken) {
// 어세스토큰이 있으면 axios 인스턴스에 커먼 헤더로 집어넣음
axiosPrivate.defaults.headers.common[
'Authorization'
] = `Bearer ${accessToken}`;

if (refreshToken) {
//새로고침할때마다 토큰으로 유저정보(입금자명, 전화번호) 가져오는 과정 필요
return {
...initialState,
isAuthenticated: true,
registerToken,
refreshToken,
};
} else return { ...initialState, registerToken };
} else return { ...initialState, refreshToken };
};

export const authState = atom<IAuthType>({
key: 'auth',
export const authState = atom<AuthStateType>({
key: 'authState',
default: getTokenFromLocalStorage(),
});
10 changes: 2 additions & 8 deletions apps/ticket/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"target": "es5",
"target": "es2017",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
Expand All @@ -26,12 +26,6 @@
"@store/*": ["src/store/*"]
}
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
"../../**/*.d.ts",
"../../shared/utils/src/http/axios.ts"
],
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "../../**/*.d.ts"],
"exclude": ["node_modules"]
}
Loading