-
Notifications
You must be signed in to change notification settings - Fork 5
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
[FE] 카카오 로그인 기능 추가 #833
[FE] 카카오 로그인 기능 추가 #833
Changes from 10 commits
00969c8
eb8cca3
635d9bc
c495266
a0a0cfd
f14a9a1
bf80262
b727e1f
25b4690
b7bd3b3
558acfd
27adf0c
da4f5dc
6c6ab93
4587836
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -63,6 +63,19 @@ export const requestGet = async <T>({ | |
return data; | ||
}; | ||
|
||
export const requestGetWithoutResponse = async ({ | ||
headers = {}, | ||
errorHandlingStrategy, | ||
...args | ||
}: WithErrorHandlingStrategy<RequestMethodProps>) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 신경써서 구현해줘서 고맙습니다. 더 편리한 방법을 찾고 싶은데 마땅히 떠오르는게 없네요 ㅜㅜ.... |
||
await request({ | ||
...args, | ||
method: 'GET', | ||
headers, | ||
errorHandlingStrategy, | ||
}); | ||
}; | ||
|
||
export const requestPatch = ({headers = {}, ...args}: RequestMethodProps) => { | ||
return request({method: 'PATCH', headers, ...args}); | ||
}; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
import {BASE_URL} from '@apis/baseUrl'; | ||
import {ADMIN_API_PREFIX, USER_API_PREFIX} from '@apis/endpointPrefix'; | ||
import {requestPostWithoutResponse} from '@apis/fetcher'; | ||
import {requestGet, requestGetWithoutResponse, requestPostWithoutResponse} from '@apis/fetcher'; | ||
import {WithEventId} from '@apis/withId.type'; | ||
|
||
export const requestPostAuthentication = async ({eventId}: WithEventId) => { | ||
|
@@ -23,3 +23,24 @@ export const requestPostToken = async ({eventId, password}: WithEventId<RequestP | |
}, | ||
}); | ||
}; | ||
|
||
export const requestKakaoClientId = async () => { | ||
return await requestGet<{clientId: string}>({ | ||
baseUrl: BASE_URL.HD, | ||
endpoint: '/api/kakao-client-id', | ||
}); | ||
}; | ||
|
||
export const requestGetKakaoLogin = async (code: string) => { | ||
const redirectUri = | ||
process.env.NODE_ENV === 'development' | ||
? 'http://localhost:3000' + process.env.KAKAO_REDIRECT_URI | ||
: 'https://haengdong.pro' + process.env.KAKAO_REDIRECT_URI; | ||
|
||
await requestGetWithoutResponse({ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. GET인데 바디가없는 GET도 있었군요!.. 쿠키만 세팅해주고 끝나기 때문인가보네요. 새로 알아갑니다~ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 근데 그럼 또 궁금한게 바디없는 POST로 만들면 안됐던걸까요!? |
||
baseUrl: BASE_URL.HD, | ||
endpoint: `/api/login/kakao?code=${code}&redirect_uri=${redirectUri}`, | ||
}); | ||
|
||
return null; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,6 +20,7 @@ const ICON_DEFAULT_COLOR: Record<IconType, IconColor> = { | |
heundeut: 'gray', | ||
photoButton: 'white', | ||
chevronDown: 'tertiary', | ||
kakao: 'kakao', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fill currentColor로 설정되어야 여기서 default 색상을 넣었을 때 적용이 되고 나중에 iconColor를 넣었을 때 그 값이 적용된다! 감사합니다~ |
||
}; | ||
|
||
export const iconStyle = ({iconType, theme, iconColor}: IconStylePropsWithTheme) => { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,6 +35,7 @@ const PRIMITIVE_COLORS = { | |
700: '#c9d323', | ||
800: '#b9bb17', | ||
900: '#9e9305', | ||
kakao: '#FEE500', | ||
}, | ||
green: { | ||
50: '#f4ffe8', | ||
|
@@ -59,6 +60,7 @@ const PRIMITIVE_COLORS = { | |
700: '#56555A', | ||
800: '#38373B', | ||
900: '#18171B', | ||
kakao: '#181600', | ||
}, | ||
}; | ||
|
||
|
@@ -81,7 +83,9 @@ export type ColorKeys = | |
| 'errorContainer' | ||
| 'onErrorContainer' | ||
| 'warn' | ||
| 'complete'; | ||
| 'complete' | ||
| 'kakao' | ||
| 'onKakao'; | ||
export type ColorTokens = Record<ColorKeys, Color>; | ||
|
||
// TODO: (@soha) 대괄호 사용에 대해 논의 | ||
|
@@ -106,6 +110,9 @@ export const COLORS: ColorTokens = { | |
onErrorContainer: PRIMITIVE_COLORS.pink[300], | ||
warn: PRIMITIVE_COLORS.yellow[400], | ||
complete: PRIMITIVE_COLORS.green[300], | ||
|
||
kakao: PRIMITIVE_COLORS.yellow['kakao'], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 음... PRIMITIVE에 별도로 값을 추가하지 않고, SEMENTIC에 바로 값을 넣어주는 것이 좋아보여요! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이거 어떻게 넣어야할까 고민했었는데 바로 SEMENTIC에 넣어도 되겠군요! 좋습니다 |
||
onKakao: PRIMITIVE_COLORS.gray['kakao'], | ||
}; | ||
|
||
export const PRIMARY_COLORS = PRIMITIVE_COLORS.purple; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import {useQuery} from '@tanstack/react-query'; | ||
|
||
import {requestKakaoClientId} from '@apis/request/auth'; | ||
|
||
import QUERY_KEYS from '@constants/queryKeys'; | ||
|
||
const useRequestGetKakaoClientId = () => { | ||
const {refetch, ...rest} = useQuery({ | ||
queryKey: [QUERY_KEYS.kakaoClientId], | ||
queryFn: requestKakaoClientId, | ||
enabled: false, | ||
}); | ||
|
||
return { | ||
requestGetClientId: refetch, | ||
...rest, | ||
}; | ||
}; | ||
|
||
export default useRequestGetKakaoClientId; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import {useQuery} from '@tanstack/react-query'; | ||
|
||
import {requestGetKakaoLogin} from '@apis/request/auth'; | ||
|
||
import QUERY_KEYS from '@constants/queryKeys'; | ||
|
||
const useRequestGetKakaoLogin = () => { | ||
const code = new URLSearchParams(location.search).get('code'); | ||
|
||
const {refetch, ...rest} = useQuery({ | ||
queryKey: [QUERY_KEYS.kakaoLogin, code], | ||
queryFn: () => requestGetKakaoLogin(code ?? ''), | ||
enabled: false, | ||
}); | ||
|
||
return { | ||
requestGetKakaoLogin: refetch, | ||
...rest, | ||
}; | ||
}; | ||
|
||
export default useRequestGetKakaoLogin; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import {useEffect} from 'react'; | ||
import {useLocation, useNavigate} from 'react-router-dom'; | ||
|
||
import {useAuthStore} from '@store/authStore'; | ||
|
||
import {ROUTER_URLS} from '@constants/routerUrls'; | ||
|
||
import useRequestGetKakaoClientId from './queries/auth/useRequestGetKakaoClientId'; | ||
import useAmplitude from './useAmplitude'; | ||
import useRequestGetKakaoLogin from './queries/auth/useRequestGetKakaoLogin'; | ||
|
||
const useLoginPage = () => { | ||
const navigate = useNavigate(); | ||
const location = useLocation(); | ||
const {trackStartCreateEvent} = useAmplitude(); | ||
const {updateAuth} = useAuthStore(); | ||
const {requestGetKakaoLogin} = useRequestGetKakaoLogin(); | ||
|
||
const {requestGetClientId} = useRequestGetKakaoClientId(); | ||
|
||
const goKakaoLogin = async () => { | ||
const queryResult = await requestGetClientId(); | ||
const clientId = queryResult.data?.clientId; | ||
const redirectUri = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. auth.ts에서도 동일하게 사용하던데 하나의 constants 파일에서 관리하는 건 어떤가용? |
||
process.env.NODE_ENV === 'development' | ||
? 'http://localhost:3000' + process.env.KAKAO_REDIRECT_URI | ||
: 'https://haengdong.pro' + process.env.KAKAO_REDIRECT_URI; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 저희 app.haengdong.pro도 있긴한데, 그냥 haengdong.pro로 리다이렉션해도 괜찮겠죠? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이게 개발 환경에서 테스트할 때는 localhost:3000이라서 이렇게 해뒀어요. cypress 테스트를 할 때도 localhost:3000으로 열리니깐 문제 없다고 생각했습니다! prod는 고민이 되네요... 근데 크게 무리는 없을 것 같아요 |
||
|
||
const link = `https://kauth.kakao.com/oauth/authorize?client_id=${clientId}&redirect_uri=${redirectUri}&response_type=code`; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 얘도 마찬가지로 나중에 관리할 것을 생각해서 constnats 파일에 따로 분리해두는 것도 좋을 것 같아용 |
||
window.location.href = link; | ||
}; | ||
|
||
const goNonLoginCreateEvent = () => { | ||
trackStartCreateEvent({login: false}); | ||
navigate(ROUTER_URLS.createEvent); | ||
}; | ||
|
||
useEffect(() => { | ||
if (location.search === '') return; | ||
|
||
const code = new URLSearchParams(location.search).get('code'); | ||
|
||
const kakaoLogin = async () => { | ||
if (code) { | ||
await requestGetKakaoLogin(); | ||
updateAuth(true); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 비회원 관리자와 회원 관리자의 인증여부를 하나의 auth 상태로 관리해도 부작용이 없나요? |
||
|
||
// 추후에 업데이트 하는 로직 필요 | ||
trackStartCreateEvent({login: true}); | ||
navigate(ROUTER_URLS.createEvent); | ||
} | ||
}; | ||
|
||
kakaoLogin(); | ||
}, [location.search]); | ||
|
||
return {goKakaoLogin, goNonLoginCreateEvent}; | ||
}; | ||
|
||
export default useLoginPage; |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,10 @@ export const authHandler = [ | |
return new HttpResponse(null, {status: 200}); | ||
}), | ||
|
||
http.get(`${MOCK_API_PREFIX}/api/login/kakao`, () => { | ||
return new HttpResponse(null, {status: 200}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
}), | ||
|
||
// POST /api/eventId/login (requestPostToken) | ||
http.post<{eventId: string}, {password: string}>( | ||
`${MOCK_API_PREFIX}${USER_API_PREFIX}/:eventId/login`, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import {css} from '@emotion/react'; | ||
|
||
import {Theme} from '@components/Design/theme/theme.type'; | ||
|
||
export const hrStyle = (theme: Theme) => | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hr이라는 태그가 있는걸 처음 알았네요 🥹 새로운걸 배웠습니당 |
||
css({ | ||
width: '100%', | ||
height: 1, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 오 근데 height에 단위없이 1만 쓰면 어떻게 되나요? 그냥 px붙인 걸로 스타일계산이 되나요? |
||
|
||
backgroundColor: theme.colors.tertiary, | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import Image from '@components/Design/components/Image/Image'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 혹시 이 페이지만 페이지 이름.tsx가 아니라 index.tsx인 이유가 있나요? |
||
|
||
import useLoginPage from '@hooks/useLoginPage'; | ||
|
||
import {Button, Flex, FunnelLayout, Icon, MainLayout, Text, TopNav, useTheme} from '@components/Design'; | ||
|
||
import getImageUrl from '@utils/getImageUrl'; | ||
|
||
import {hrStyle} from './LoginPage.style'; | ||
|
||
const LoginPage = () => { | ||
const {theme} = useTheme(); | ||
|
||
const {goKakaoLogin, goNonLoginCreateEvent} = useLoginPage(); | ||
|
||
return ( | ||
<MainLayout backgroundColor="white"> | ||
<TopNav> | ||
<TopNav.Item displayName="뒤로가기" noEmphasis routePath="-1" /> | ||
</TopNav> | ||
<FunnelLayout> | ||
<Flex flexDirection="column" justifyContent="spaceBetween" height="100%"> | ||
<Flex flexDirection="column" justifyContent="center" alignItems="center" gap="1rem" margin="0 0 6rem 0"> | ||
<Image src={getImageUrl('heundeut', 'webp')} fallbackSrc={getImageUrl('heundeut', 'png')} width={109} /> | ||
<Text size="bodyBold" css={{whiteSpace: 'pre-line', textAlign: 'center'}}> | ||
{`로그인을 사용하면\n더 편하게 사용할 수 있어요`} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 로그인을 사용했을 때, 더 디테일한 베네핏들이 있으면 좋을 것 같아요. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 그 내용을 직접 표현해도 되겠네요! |
||
</Text> | ||
</Flex> | ||
<Flex flexDirection="column" gap="1rem" width="100%" padding="0 2rem" paddingInline="auto"> | ||
<Button variants="kakao" size="large" onClick={goKakaoLogin}> | ||
<Flex alignItems="center" gap="0.625rem"> | ||
<Icon iconType="kakao" /> | ||
카카오 로그인 | ||
</Flex> | ||
</Button> | ||
<hr css={hrStyle(theme)} /> | ||
<Button variants="secondary" size="large" onClick={goNonLoginCreateEvent}> | ||
비회원으로 진행하기 | ||
</Button> | ||
</Flex> | ||
</Flex> | ||
</FunnelLayout> | ||
</MainLayout> | ||
); | ||
}; | ||
|
||
export default LoginPage; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
오~ 잊지 않고 추가! 멋져용