-
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
Conversation
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.
몇가지 comment 남겼는데, 반영 여부 판단해서 반영해주시면 감사하겠습니다~!
전체적으로 너무 잘 작성해 주신 것 같숨당 👍
client/src/assets/image/kakao.svg
Outdated
@@ -0,0 +1,3 @@ | |||
<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg"> | |||
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.5 9.00012C0.5 4.14312 5.156 0.500122 10.5 0.500122C15.844 0.500122 20.5 4.14312 20.5 9.00012C20.5 13.8571 15.844 17.5001 10.5 17.5001C9.974 17.5001 9.45867 17.4668 8.954 17.4001L6.054 19.3321C5.88945 19.4417 5.6961 19.5001 5.49839 19.4998C5.30068 19.4996 5.10749 19.4407 4.94321 19.3307C4.77894 19.2207 4.65097 19.0645 4.57546 18.8817C4.49995 18.699 4.48031 18.498 4.519 18.3041L4.964 16.0831C2.328 14.5901 0.5 12.0171 0.5 9.00012Z" fill="#181600"/> |
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.
fill attribute
를 currentColor로 변경하면, 부모의 속성과 같은 값으로 변경해서 유연하게 사용할 수 있어요~
Icon
component들과 그 하위의 svg 값들을 참고해보면 좋을 것 같숨당
@@ -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 comment
The reason will be displayed to describe this comment to others. Learn more.
@assets/image/kakao.svg
에서 comment를 단 것 처럼, currentColor로 변경해 주지 않았기 때문에, IconComponent에서 iconColor를 prop으로 받아도 아마 변경되지 않을거에요
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.
fill currentColor로 설정되어야 여기서 default 색상을 넣었을 때 적용이 되고 나중에 iconColor를 넣었을 때 그 값이 적용된다! 감사합니다~
@@ -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 comment
The reason will be displayed to describe this comment to others. Learn more.
음... PRIMITIVE에 별도로 값을 추가하지 않고, SEMENTIC에 바로 값을 넣어주는 것이 좋아보여요!
RPIMITIVE에 kakao라는 키가 있는것이 어색하기도 하고, 의미상 맞지 않아요 ㅜㅜ
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.
이거 어떻게 넣어야할까 고민했었는데 바로 SEMENTIC에 넣어도 되겠군요! 좋습니다
client/src/pages/LoginPage/index.tsx
Outdated
<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 comment
The 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 comment
The reason will be displayed to describe this comment to others. Learn more.
그 내용을 직접 표현해도 되겠네요!
로그인 장점이 자주 사용하는 계좌번호 등록, 내가 만든 행사 열람, 행사 비밀번호 플로우 생략인데 이를 더 표현해봐도 좋을 것 같아요. 이를 어떻게 다 담을 수 있을지는 고민해볼게요!
client/src/hooks/useLoginPage.ts
Outdated
const redirectUri = | ||
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 comment
The reason will be displayed to describe this comment to others. Learn more.
저희 app.haengdong.pro도 있긴한데, 그냥 haengdong.pro로 리다이렉션해도 괜찮겠죠?
그리고, dev.haengdong.pro에서는 어떻게 되는지 궁금해용
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.
이게 개발 환경에서 테스트할 때는 localhost:3000이라서 이렇게 해뒀어요. cypress 테스트를 할 때도 localhost:3000으로 열리니깐 문제 없다고 생각했습니다!
prod는 고민이 되네요... 근데 크게 무리는 없을 것 같아요
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.
크게 수정해야 할 것들은 보이지 않네요! 멋지게 잘 만들어줘서 고마우ㅕ용
cy.url().should('include', ROUTER_URLS.login); | ||
cy.get('button').contains('비회원으로 진행하기').click(); |
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.
오~ 잊지 않고 추가! 멋져용
kakao: '#FEE500', | ||
onKakao: '#181600', |
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.
조금 번거로울 수 있긴 하지만, 해당 컬러들도 위에 PRIMITIVE_COLORS 처럼 객체로 관리해서 넣어주는게 통일성 있고 좋을 것 같아요!
다만 해당 컬러는 카카오와 같은 회사의 지정 컬러니까 PRIMITIVE_COLORS가 아닌 새로운 객체를 만들어서 넣어주는건 어떠세용?
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.
오매. 이전에 토다리가 저와 약간 반대 의견을 내주셔서 수정했던 거군요! 호홍
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.
소하의 의견도 좋은 아이디어네요~ BRAND_COLORS 와 같은 것을 만들어서 넣어줘도 되겠네요~
client/src/hooks/useLoginPage.ts
Outdated
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 comment
The reason will be displayed to describe this comment to others. Learn more.
auth.ts에서도 동일하게 사용하던데 하나의 constants 파일에서 관리하는 건 어떤가용?
client/src/hooks/useLoginPage.ts
Outdated
? 'http://localhost:3000' + process.env.KAKAO_REDIRECT_URI | ||
: 'https://haengdong.pro' + process.env.KAKAO_REDIRECT_URI; | ||
|
||
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 comment
The reason will be displayed to describe this comment to others. Learn more.
얘도 마찬가지로 나중에 관리할 것을 생각해서 constnats 파일에 따로 분리해두는 것도 좋을 것 같아용
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.
로그인에 관련된 여러 가지를 구현해내느라 고생많았어요~ 쿡히~ 생각할 것들이 많아서 고민을 오래 했을 것 같네요. 감사합니다
const kakaoLogin = async () => { | ||
if (code) { | ||
await requestGetKakaoLogin(); | ||
updateAuth(true); |
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.
비회원 관리자와 회원 관리자의 인증여부를 하나의 auth 상태로 관리해도 부작용이 없나요?
@@ -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 comment
The reason will be displayed to describe this comment to others. Learn more.
👍
|
||
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 comment
The reason will be displayed to describe this comment to others. Learn more.
hr이라는 태그가 있는걸 처음 알았네요 🥹 새로운걸 배웠습니당
export const hrStyle = (theme: Theme) => | ||
css({ | ||
width: '100%', | ||
height: 1, |
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.
오 근데 height에 단위없이 1만 쓰면 어떻게 되나요? 그냥 px붙인 걸로 스타일계산이 되나요?
? '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 comment
The 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 comment
The reason will be displayed to describe this comment to others. Learn more.
근데 그럼 또 궁금한게 바디없는 POST로 만들면 안됐던걸까요!?
headers = {}, | ||
errorHandlingStrategy, | ||
...args | ||
}: WithErrorHandlingStrategy<RequestMethodProps>) => { |
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.
신경써서 구현해줘서 고맙습니다. 더 편리한 방법을 찾고 싶은데 마땅히 떠오르는게 없네요 ㅜㅜ....
? '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 comment
The reason will be displayed to describe this comment to others. Learn more.
근데 그럼 또 궁금한게 바디없는 POST로 만들면 안됐던걸까요!?
@@ -0,0 +1,49 @@ | |||
import Image from '@components/Design/components/Image/Image'; |
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.
혹시 이 페이지만 페이지 이름.tsx가 아니라 index.tsx인 이유가 있나요?
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.
번영된 것 확인했슴다~
취준땜에 바쁜 와중에도 태스크 가져가서 열심히 해줘서 고마워용 쿠키 🚀
* feat: kakao 이미지 추가 * feat: 정산 시작하기 로그인 페이지로 이동 및 로그인 페이지 제작 * feat: 카카오 로그인 기능 구현 * feat: Amplitude 로그인 한 유저와 아닌 유저 구분하는 기능 구현 * fix: get 응답이 없는 함수를 생성해서 json 오류가 나지 않도록 설정 * test: 카카오 로그인 핸들러 설정 * fix: redirect 설정오류 수정 * feat: tanstack query로 카카오 로그인 불러서 에러처리 되도록 설정 * feat: 이미지 width 설정해서 layout shift 생기지 않도록 설정 * fix: 정산 시작하기 버튼 누를 때 플로우가 바뀌어 cypress 코드 수정 * style: primitive kakao 값 semantic으로 이동 * fix: svg fill currentColor로 변경해서 Icon 컴포넌트에서 색상을 넣어줄 수 있도록 변경 * fix: 카카오 아이콘 색상 변경 * feat: 로그인 유도 멘트 변경 * refactor: redirect uri 도메인 오리진을 얻어서 붙이는 방식으로 변경
issue
구현 사항
로그인 페이지 구현
로그인 기능이 추가됨에 따라 로그인을 할 수 있는 화면을 만들었습니다.
"로그인을 사용하면 더 편하게 사용할 수 있어요"라는 멘트로 설정해두었는데 이 멘트 피드백 부탁드려요!
카카오 로그인을 누르면 카카오 로그인이 되며, 비회원으로 시작하기를 누르면 기존의 플로우대로 이용할 수 있습니다.
카카오 로그인 구현 흐름
아래 흐름을 전체적으로 그림으로 표현하자면
준비물
카카오 로그인을 사용하기 위해서 카카오 client ID, Redirect uri가 필요합니다. client id는 서버가 가지고 있으며 redirect uri는 클라이언트가 환경변수로 가지고 있습니다.
서버로부터 client id 받아오기
카카오 로그인 버튼을 누르면 서버로부터 카카오 클라이언트 ID를 받아옵니다. https://kauth.kakao~~로 client id, redirect uri를 채워서 link를 만든 뒤 페이지를 대체합니다.
사용자 계정정보 입력
사용자는 거기서 본인의 카카오계정 ID와 PW를 입력해서 로그인을 하면 카카오 서버로부터 redirect uri에 인가코드를 붙여서 우리 사이트로 되돌아오게 됩니다.
인가코드 서버로 요청
사이트로 되돌아온 뒤 https://~~?code=djsjs url에서 code 쿼리 파라미터 값을 추출해서 서버로 카카오로그인 요청을 보내게 됩니다. 이 때도 code와 redirect url을 같이 보냅니다.
로그인 성공
서버로부터 로그인 성공 응답을 받으면 쿠키에 엑세스 토큰이 생기게 됩니다. 그 후에 회원 행사 생성 페이지로 이동하게 됩니다.
로그인 유지방법
로그인 유지 방법은 비회원 로그인과 동일하게 서버로 auth 확인 요청을 날리면 됩니다.
로그인 실패 시
로그인이 실패하게 되면 로그인 페이지에 머무르게 됩니다.
amplitude 행사 생성 속성 값 추가
로그인이 추가된만큼 로그인을 한 유저와 비회원으로 이용하는 유저가 얼마나 되는지 구분하기 위해 속성으로 login을 추가했습니다. 나중에 이를 활용하여 유저 테스트를 해볼 수 있을 듯 합니다.
서버로부터 GET 요청을 날리며
기존 비회원 비밀번호 로그인은 post요청이지만 이번 카카오 로그인 요청은 GET입니다.
우리 에러 처리 구조가 tanstack query를 의존하기 때문에 에러 처리를 하기 위해서 tanstack query를 사용해야합니다.
하지만 tanstack query useQuery로 get 요청을 하게되면 컴포넌트가 마운트되고 훅이 실행될 때 서버로 요청을 날리게 됩니다. 이로 인해 카카오 로그인을 누르지 않았지만 카카오 client id 요청이 페이지에 포함되어있어 카카오 client id를 불러오게 되는 문제가 생길 수 있습니다.
useQuery를 사용하고도 우리가 원하는 시점에만 get 요청을 해야하는 요구사항입니다. tanstack query는 이런 요구사항을 만족할 수 있도록 useQuery 훅에 enabled 옵션을 제공합니다.
enabled: false를 주게 되면 훅이 최초에 실행될 때 서버로 요청을 날리지 않고 사용자가 특정 액션을 취할 때 get 요청을 할 수 있습니다. 특정 액션을 취할 때 서버로부터 다시 요청을 하기 위해 useQuery가 제공하는 함수 중 refetch 함수를 이용하면 됩니다.
최초에 서버로 요청을 하지 않고 카카오 로그인 버튼을 누를 때 refetch 함수를 호출해서 useQuery를 사용하고도 요청 시기를 결정할 수 있습니다.
앞으로 남은 것
🫡 참고사항