Skip to content

Commit

Permalink
Merge pull request #229 from Team-TIFY/dev
Browse files Browse the repository at this point in the history
[Deploy]: 애플 로그인 구현 배포 테스트
  • Loading branch information
eugene028 authored Dec 28, 2023
2 parents de4b8ee + 1f31df2 commit 4d6f304
Show file tree
Hide file tree
Showing 19 changed files with 234 additions and 88 deletions.
9 changes: 8 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,20 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="appleid-signin-client-id" content="[CLIENT_ID]">
<meta name="appleid-signin-scope" content="[SCOPES]">
<meta name="appleid-signin-redirect-uri" content="[REDIRECT_URI]">
<meta name="appleid-signin-state" content="[STATE]">
<meta name="appleid-signin-nonce" content="[NONCE]">
<meta name="appleid-signin-use-popup" content="true">
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<base href="https://tify-client.vercel.app/">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"/>
<!-- <base href="https://tify-client.vercel.app/"> -->
<title>TIFY</title>
</head>
<body>
<div id="root"></div>
<script type="text/javascript" src="https://appleid.cdn-apple.com/appleauth/static/jsapi/appleid/1/en_US/appleid.auth.js"></script>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
6 changes: 4 additions & 2 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Routes, Route } from 'react-router-dom'
import Layout from '@components/layouts/Layout'
import Login from '@pages/home/Login'
import { Redirect } from '@pages/home/Redirect'
import { KaKaoRedirect } from '@pages/home/Redirect/KaKaoRedirect'
import { AppleRedirect } from '@pages/home/Redirect/AppleRedirect'
import { CheckUserAuth } from '@components/auth/CheckUserAuth'
import RequireAuth from '@components/auth/RequireAuth'
import ProfileRouter from '@pages/profile'
Expand All @@ -24,7 +25,8 @@ function App() {
<Route element={<CheckUserAuth />}>
<Route path="/login" element={<Login />} />
</Route>
<Route path="/kakao/callback" element={<Redirect />} />
<Route path="/kakao/callback" element={<KaKaoRedirect />} />
<Route path="/apple/callback" element={<AppleRedirect />} />
</Route>
</Routes>
)
Expand Down
7 changes: 4 additions & 3 deletions src/components/atoms/Category/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { SubCategoryName } from '@utils/apis/user/UserType'
* @param allCategoryAnswered + 아이콘을 보여줄지 말지를 나타냄 (모든 detailCategory를 다 답변했는지 여부를 나타냄)
* @param onPlusButtonClick + / 선물 버튼 클릭 시 발생하는 이벤트를 넘겨주는 함수임
*/

export type CategoryNameType =
| 'MAKEUP'
| 'FRAGRANCE'
Expand Down Expand Up @@ -77,9 +78,9 @@ export const Category = ({
) : null}
</Heading>
<TagWrapper>
{children.map((child, index) => (
<TagItem key={index}>{child}</TagItem>
))}
{children.map((child, index) =>
child ? <TagItem key={index}>{child}</TagItem> : null,
)}
</TagWrapper>
</Wrapper>
)
Expand Down
19 changes: 10 additions & 9 deletions src/components/atoms/ProfileBox/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,23 @@ import shadow from '@assets/image/profile_shadow.png'
import backgroundImage from '@assets/image/profile_background.png'
import profileBoxImage from '@assets/image/profile_box.png'
import { useEffect, useState } from 'react'

export type VariantType = 'profile' | 'shareProfile'

export type ProfileBoxProps = {
variant?: VariantType
favorList: TasteBoxVariantType[]
}
const ProfileBox = ({
variant = 'profile',
favorList = [],
}: ProfileBoxProps) => {
const [myFavorList, setFavorList] = useState<TasteBoxVariantType[]>([])
const ProfileBox = ({ variant = 'profile', favorList }: ProfileBoxProps) => {
const [myFavorList, setMyFavorList] = useState<TasteBoxVariantType[]>([])

useEffect(() => {
if (favorList.length < 3) {
setFavorList([])
} else {
setFavorList([...favorList.slice(-3)])
if (Array.isArray(favorList)) {
if (favorList?.length < 3) {
setMyFavorList([])
} else {
setMyFavorList([...favorList.slice(-3)])
}
}
}, [favorList])

Expand Down
5 changes: 3 additions & 2 deletions src/components/auth/RequireAuth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const RequireAuth = () => {
setAuth({
isAuthenticated: true,
callbackUrl: '/',
loginType: auth.loginType,
accessToken: accessToken,
userProfile: {
id: data.id,
Expand Down Expand Up @@ -62,6 +63,7 @@ const RequireAuth = () => {
if (accessToken) {
if (isOnboard === false) {
setStatus('needOnboarding')
setSnackBar({ comment: '온보딩이 필요해요', type: 'error' })
} else setStatus('succeed')
} else {
setStatus('failed')
Expand All @@ -71,8 +73,7 @@ const RequireAuth = () => {
if (status === 'succeed') {
return <Outlet />
} else if (status === 'needOnboarding') {
setSnackBar({ comment: '온보딩이 필요해요', type: 'error' })
setTimeout(() => setStatus('succeed'), 500)
setTimeout(() => setStatus('succeed'), 100)
return <Navigate replace to="/onboarding" />
} else if (status === 'failed') {
setSnackBar({ comment: '로그인이 필요해요', type: 'error' })
Expand Down
25 changes: 9 additions & 16 deletions src/components/profile/UserTagDataListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import { useNavigate } from 'react-router-dom'
import { questionMenu } from '@utils/questionMenu'
import { useSetRecoilState } from 'recoil'
import { friendState } from '@libs/store/friend'
import { question } from '@utils/question'
import { TasteBoxVariantType } from '@utils/apis/favor/TasteType'

export interface UserTagDataProps {
selectedProps: SelectedProps
Expand All @@ -30,19 +32,11 @@ export const UserTagDataListItem = ({
const setFriendStateData = useSetRecoilState(friendState)

const handleClickPlusButton = (
categoryName: SubCategoryName,
smallCategory: string,
categoryValue: SubCategoryType,
notAnsweredDetailCategories: TasteBoxVariantType[],
) => {
if (categoryName === '프레그런스' && smallCategory === 'PERFUME') {
navigate(questionMenu[categoryValue][0])
} else if (categoryName === '프레그런스' && smallCategory === 'MOISTURE') {
navigate(questionMenu[categoryValue][1])
} else if (categoryName === '프레그런스' && smallCategory === 'PLACE') {
navigate(questionMenu[categoryValue][2])
} else {
navigate(questionMenu[categoryValue])
}
console.log(notAnsweredDetailCategories)

navigate(`/profile/newTaste/${question[notAnsweredDetailCategories[0]]}`)
}

const handleClickPresentButton = (categoryValue: SubCategoryType) => {
Expand All @@ -65,17 +59,16 @@ export const UserTagDataListItem = ({
? matchingProp.name
: ('' as SubCategoryName)
const categoryValue = matchingProp?.value ?? ('' as SubCategoryType)
const smallCategory = tag[1].smallCategory ?? tag[0].smallCategory
const allCategoryAnswered = tag[0]?.allDetailCategoryAnswered
const notAnsweredDetailCategories = tag[0]?.notAnsweredDetailCategories

return (
<Category
key={idx}
categoryName={categoryName}
isFriend={isFriend}
allCategoryAnswered={allCategoryAnswered}
allCategoryAnswered={notAnsweredDetailCategories.length === 0}
onPlusButtonClick={() =>
handleClickPlusButton(categoryName, smallCategory, categoryValue)
handleClickPlusButton(notAnsweredDetailCategories)
}
onPresentButtonClick={() => handleClickPresentButton(categoryValue)}
children={tag.map((tagData, index) =>
Expand Down
58 changes: 48 additions & 10 deletions src/libs/hooks/useAuthMutate.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {
KakaoLoginResponse,
KakaoCodeResponse,
OauthLoginResponse,
OauthCodeResponse,
} from '@utils/apis/auth/AuthType'
import { authState } from '@libs/store/auth'
import { useRecoilState } from 'recoil'
Expand All @@ -11,28 +11,42 @@ import { axiosApi } from '@utils/apis/axios'
import { setCookie } from '@utils/cookies'
import { UserApi } from '@utils/apis/user/UserApi'

const useAuthMutate = ({ idToken }: KakaoCodeResponse) => {
const useAuthMutate = ({ idToken, refreshToken }: OauthCodeResponse) => {
const [auth, setAuth] = useRecoilState(authState)
const navigate = useNavigate()

//회원가입 mutation
const ouathKakaoRegisterMutation = useMutation(AuthApi.KAKAO_REGISTER, {
onSuccess: (data: KakaoLoginResponse) => {
onSuccessLogin(data)
onSuccess: (data: OauthLoginResponse) => {
onSuccessLogin({ loginData: data, loginType: 'KAKAO' })
navigate(auth.callbackUrl)
},
})

const oauthAppleRegisterMutation = useMutation(AuthApi.APPLE_REGISTER, {
onSuccess: (data: OauthLoginResponse) => {
onSuccessLogin({ loginData: data, loginType: 'APPLE' })
navigate(auth.callbackUrl)
},
})

//로그인 mutation
const ouathKakaoLoginMutation = useMutation(AuthApi.KAKAO_LOGIN, {
onSuccess: (data: KakaoLoginResponse) => {
onSuccessLogin(data)
onSuccess: (data: OauthLoginResponse) => {
onSuccessLogin({ loginData: data, loginType: 'KAKAO' })
navigate(auth.callbackUrl)
},
})

const ouathAppleLoginMutation = useMutation(AuthApi.APPLE_LOGIN, {
onSuccess: (data: OauthLoginResponse) => {
onSuccessLogin({ loginData: data, loginType: 'APPLE' })
navigate(auth.callbackUrl)
},
})

//회원가입 여부 검증
const ouathValidMutation = useMutation(AuthApi.KAKAO_VALID, {
const ouathKakaoValidMutation = useMutation(AuthApi.KAKAO_VALID, {
onSuccess: (data: { canRegister: boolean }) => {
//회원가입이 필요한 사람
if (data.canRegister) {
Expand All @@ -46,7 +60,30 @@ const useAuthMutate = ({ idToken }: KakaoCodeResponse) => {
},
})

const onSuccessLogin = async (loginData: KakaoLoginResponse) => {
const oauthAppleValidMutation = useMutation(AuthApi.APPLE_VALID, {
onSuccess: (data: { canRegister: boolean }) => {
//회원가입이 필요한 사람
if (data.canRegister) {
oauthAppleRegisterMutation.mutate({
idToken: idToken,
refreshToken: refreshToken,
})
//회원가입 직후 온보딩페이지로 이동
navigate('/onboarding')
} else {
//회원가입이 필요 없으면 그냥 로그인합니다.
ouathAppleLoginMutation.mutate(idToken)
}
},
})

const onSuccessLogin = async ({
loginData,
loginType,
}: {
loginData: OauthLoginResponse
loginType: 'KAKAO' | 'APPLE'
}) => {
axiosApi.defaults.headers.common[
'Authorization'
] = `Bearer ${loginData.accessToken}`
Expand All @@ -62,6 +99,7 @@ const useAuthMutate = ({ idToken }: KakaoCodeResponse) => {
//TODO: 백엔드 명세 바뀌면 바뀌어야
setAuth({
isAuthenticated: true,
loginType: loginType,
callbackUrl: '/',
accessToken: loginData.accessToken,
userProfile: {
Expand All @@ -78,6 +116,6 @@ const useAuthMutate = ({ idToken }: KakaoCodeResponse) => {
},
})
}
return { ouathValidMutation }
return { ouathKakaoValidMutation, oauthAppleValidMutation }
}
export default useAuthMutate
2 changes: 2 additions & 0 deletions src/libs/hooks/useRefresh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ import { AuthApi } from '@utils/apis/auth/AuthApi'

const useRefresh = () => {
const [auth, setAuth] = useRecoilState(authState)

const { mutate: refreshMutate, status } = useMutation(AuthApi.REFRESH, {
onSuccess: (data) => {
axiosApi.defaults.headers.common[
'Authorization'
] = `Bearer ${data.accessToken}`
setAuth({
userProfile: { ...auth.userProfile },
loginType: 'KAKAO',
accessToken: data.accessToken,
isAuthenticated: true,
callbackUrl: '/',
Expand Down
2 changes: 2 additions & 0 deletions src/libs/store/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ import { recoilPersist } from 'recoil-persist'
const { persistAtom } = recoilPersist()
export interface AuthStateType {
isAuthenticated: boolean
loginType: 'APPLE' | 'KAKAO'
callbackUrl: string
accessToken: string
userProfile: UserInfoToken
}

const initialState: AuthStateType = {
isAuthenticated: false,
loginType: 'KAKAO',
callbackUrl: '/',
accessToken: '',
userProfile: {
Expand Down
5 changes: 5 additions & 0 deletions src/pages/home/Login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ const Login = () => {
const data = await AuthApi.KAKAO_LINK()
window.location.href = data.link
}
const appleLogin = async () => {
const data = await AuthApi.APPLE_LINK()
window.location.href = data.link
}
return (
<div>
<MainIconContainer>
Expand All @@ -30,6 +34,7 @@ const Login = () => {
variant="kakao"
fullWidth={true}
style={{ height: '49px', backgroundColor: 'white' }}
onClick={appleLogin}
>
Apple로 로그인
</RoundButton>
Expand Down
43 changes: 43 additions & 0 deletions src/pages/home/Redirect/AppleRedirect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { useState, useEffect } from 'react'
import { OauthCodeResponse } from '@utils/apis/auth/AuthType'
import { useMutation } from '@tanstack/react-query'
import { useLocation } from 'react-router-dom'
import { AuthApi } from '@utils/apis/auth/AuthApi'
import useAuthMutate from '@libs/hooks/useAuthMutate'
import Loading from '@components/atoms/Loading'

export const AppleRedirect = () => {
const [token, setToken] = useState<OauthCodeResponse>({
accessToken: '',
idToken: '',
refreshToken: '',
})
const query = useLocation().search
const code = new URLSearchParams(query).get('code')

const appleTokenMutation = useMutation(AuthApi.APPLE_TOKEN, {
onSuccess: (data: OauthCodeResponse) => {
setToken(data)
},
})

const { oauthAppleValidMutation } = useAuthMutate(token)

useEffect(() => {
if (code) {
appleTokenMutation.mutate(code)
}
}, [code])

useEffect(() => {
if (token.idToken.length > 0) {
oauthAppleValidMutation.mutate(token.idToken)
}
}, [token])

return (
<>
<Loading />
</>
)
}
Loading

0 comments on commit 4d6f304

Please sign in to comment.