|
| 1 | +import {useCallback, useState} from 'react'; |
| 2 | +import {Image, Platform, ScrollView} from 'react-native'; |
| 3 | +import styled, {css} from '@emotion/native'; |
| 4 | +import { |
| 5 | + GoogleSignin, |
| 6 | + GoogleSigninButton, |
| 7 | + statusCodes, |
| 8 | +} from '@react-native-google-signin/google-signin'; |
| 9 | +import {Typography, useDooboo} from 'dooboo-ui'; |
| 10 | +import StatusBarBrightness from 'dooboo-ui/uis/StatusbarBrightness'; |
| 11 | +import * as AppleAuthentication from 'expo-apple-authentication'; |
| 12 | +import {Redirect, Stack} from 'expo-router'; |
| 13 | +import {useRecoilValue} from 'recoil'; |
| 14 | + |
| 15 | +import {googleClientIdIOS, googleClientIdWeb} from '../../config'; |
| 16 | +import {IC_CROSSPLATFORMS, IC_ICON} from '../../src/icons'; |
| 17 | +import {authRecoilState} from '../../src/recoil/atoms'; |
| 18 | +import {supabase} from '../../src/supabase'; |
| 19 | +import {showAlert} from '../../src/utils/alert'; |
| 20 | +import {openURL} from '../../src/utils/common'; |
| 21 | +import {DOOBOO_PRIVACY_URL, DOOBOO_TERM_URL} from '../../src/utils/constants'; |
| 22 | + |
| 23 | +const Container = styled.SafeAreaView` |
| 24 | + flex: 1; |
| 25 | + align-self: stretch; |
| 26 | + background-color: ${({theme}) => theme.brand}; |
| 27 | +
|
| 28 | + justify-content: center; |
| 29 | + align-items: center; |
| 30 | +`; |
| 31 | + |
| 32 | +const Content = styled.View` |
| 33 | + gap: 20px; |
| 34 | + justify-content: center; |
| 35 | + align-items: center; |
| 36 | +`; |
| 37 | + |
| 38 | +const Buttons = styled.View` |
| 39 | + padding: 40px; |
| 40 | + gap: 12px; |
| 41 | +`; |
| 42 | + |
| 43 | +export default function SignIn(): JSX.Element { |
| 44 | + const {theme, themeType} = useDooboo(); |
| 45 | + const authId = useRecoilValue(authRecoilState); |
| 46 | + const [isHorizontal, setIsHorizontal] = useState(false); |
| 47 | + |
| 48 | + GoogleSignin.configure({ |
| 49 | + scopes: ['https://www.googleapis.com/auth/drive.readonly'], |
| 50 | + webClientId: googleClientIdWeb, |
| 51 | + iosClientId: googleClientIdIOS, |
| 52 | + }); |
| 53 | + |
| 54 | + const googleSignIn = useCallback(async () => { |
| 55 | + try { |
| 56 | + await GoogleSignin.hasPlayServices(); |
| 57 | + |
| 58 | + const userInfo = await GoogleSignin.signIn(); |
| 59 | + |
| 60 | + if (userInfo.idToken) { |
| 61 | + const {error} = await supabase.auth.signInWithIdToken({ |
| 62 | + provider: 'google', |
| 63 | + token: userInfo.idToken, |
| 64 | + }); |
| 65 | + |
| 66 | + if (error && __DEV__) { |
| 67 | + // eslint-disable-next-line no-console |
| 68 | + console.error(error); |
| 69 | + |
| 70 | + return; |
| 71 | + } |
| 72 | + |
| 73 | + return; |
| 74 | + } |
| 75 | + |
| 76 | + showAlert('구글 ID가 존재하지 않습니다.'); |
| 77 | + } catch (error: any) { |
| 78 | + if (error.code === statusCodes.SIGN_IN_CANCELLED) { |
| 79 | + } else if (error.code === statusCodes.IN_PROGRESS) { |
| 80 | + } else if (error.code === statusCodes.PLAY_SERVICES_NOT_AVAILABLE) { |
| 81 | + // play services not available or outdated |
| 82 | + showAlert('플레이 서비스가 사용 불가능합니다.'); |
| 83 | + } else { |
| 84 | + showAlert('오류가 발생했습니다.'); |
| 85 | + } |
| 86 | + } |
| 87 | + }, []); |
| 88 | + |
| 89 | + const appleSignIn = useCallback(async (): Promise<void> => { |
| 90 | + try { |
| 91 | + const {identityToken} = await AppleAuthentication.signInAsync({ |
| 92 | + requestedScopes: [ |
| 93 | + AppleAuthentication.AppleAuthenticationScope.FULL_NAME, |
| 94 | + AppleAuthentication.AppleAuthenticationScope.EMAIL, |
| 95 | + ], |
| 96 | + }); |
| 97 | + |
| 98 | + if (identityToken) { |
| 99 | + await supabase.auth.signInWithIdToken({ |
| 100 | + provider: 'apple', |
| 101 | + token: identityToken, |
| 102 | + }); |
| 103 | + } |
| 104 | + } catch (e: any) { |
| 105 | + if ( |
| 106 | + e.code === 'ERR_REQUEST_CANCELED' || |
| 107 | + e.code === 'ERR_CANCELED' || |
| 108 | + e.code === 'ERR_REQUEST_UNKNOWN' |
| 109 | + ) { |
| 110 | + return; |
| 111 | + } |
| 112 | + |
| 113 | + showAlert('오류 발생'); |
| 114 | + } |
| 115 | + }, []); |
| 116 | + |
| 117 | + if (authId) { |
| 118 | + return <Redirect href="/" />; |
| 119 | + } |
| 120 | + |
| 121 | + return ( |
| 122 | + <Container |
| 123 | + onLayout={(e) => { |
| 124 | + setIsHorizontal( |
| 125 | + e.nativeEvent.layout.width > e.nativeEvent.layout.height, |
| 126 | + ); |
| 127 | + }} |
| 128 | + > |
| 129 | + <StatusBarBrightness type="dark-content" /> |
| 130 | + <Stack.Screen options={{headerShown: false}} /> |
| 131 | + <ScrollView> |
| 132 | + <Content |
| 133 | + style={css` |
| 134 | + padding-top: ${!isHorizontal ? '20%' : '5%'}; |
| 135 | + `} |
| 136 | + > |
| 137 | + <Image |
| 138 | + source={IC_ICON} |
| 139 | + style={css` |
| 140 | + align-self: center; |
| 141 | + width: 60px; |
| 142 | + height: 60px; |
| 143 | + `} |
| 144 | + /> |
| 145 | + |
| 146 | + <Typography.Heading5 |
| 147 | + style={css` |
| 148 | + color: white; |
| 149 | + font-size: 16px; |
| 150 | + `} |
| 151 | + > |
| 152 | + 한국의 크로스플랫폼 개발자들이 소통하는 곳! |
| 153 | + </Typography.Heading5> |
| 154 | + <Image |
| 155 | + source={IC_CROSSPLATFORMS} |
| 156 | + style={css` |
| 157 | + height: 240px; |
| 158 | + `} |
| 159 | + /> |
| 160 | + <Buttons> |
| 161 | + <GoogleSigninButton |
| 162 | + color={ |
| 163 | + themeType === 'light' |
| 164 | + ? GoogleSigninButton.Color.Light |
| 165 | + : GoogleSigninButton.Color.Dark |
| 166 | + } |
| 167 | + onPress={googleSignIn} |
| 168 | + size={GoogleSigninButton.Size.Wide} |
| 169 | + /> |
| 170 | + {Platform.OS === 'ios' ? ( |
| 171 | + <AppleAuthentication.AppleAuthenticationButton |
| 172 | + buttonStyle={ |
| 173 | + themeType === 'light' |
| 174 | + ? AppleAuthentication.AppleAuthenticationButtonStyle.BLACK |
| 175 | + : AppleAuthentication.AppleAuthenticationButtonStyle.WHITE |
| 176 | + } |
| 177 | + buttonType={ |
| 178 | + AppleAuthentication.AppleAuthenticationButtonType.SIGN_IN |
| 179 | + } |
| 180 | + cornerRadius={4} |
| 181 | + onPress={appleSignIn} |
| 182 | + style={css` |
| 183 | + height: 40px; |
| 184 | + flex-direction: row; |
| 185 | + justify-content: flex-start; |
| 186 | + `} |
| 187 | + /> |
| 188 | + ) : null} |
| 189 | + <Typography.Body4 |
| 190 | + style={css` |
| 191 | + margin-top: 4px; |
| 192 | + text-align: center; |
| 193 | + line-height: 20px; |
| 194 | + color: ${theme.text.placeholderContrast}; |
| 195 | + `} |
| 196 | + > |
| 197 | + 다음 단계로 진행함과 동시에{' '} |
| 198 | + <Typography.Body3 |
| 199 | + onPress={() => { |
| 200 | + openURL(DOOBOO_PRIVACY_URL); |
| 201 | + }} |
| 202 | + style={css` |
| 203 | + color: white; |
| 204 | + text-decoration-line: underline; |
| 205 | + `} |
| 206 | + > |
| 207 | + 개인정보 보호정책 |
| 208 | + </Typography.Body3>{' '} |
| 209 | + 및{' '} |
| 210 | + <Typography.Body3 |
| 211 | + onPress={() => { |
| 212 | + openURL(DOOBOO_TERM_URL); |
| 213 | + }} |
| 214 | + style={css` |
| 215 | + text-decoration-line: underline; |
| 216 | + color: white; |
| 217 | + text-decoration-line: underline; |
| 218 | + `} |
| 219 | + > |
| 220 | + 서비스 약관 |
| 221 | + </Typography.Body3> |
| 222 | + 에 동의하는 것으로 간주합니다. |
| 223 | + </Typography.Body4> |
| 224 | + </Buttons> |
| 225 | + </Content> |
| 226 | + </ScrollView> |
| 227 | + </Container> |
| 228 | + ); |
| 229 | +} |
0 commit comments