Skip to content

Commit 57fa663

Browse files
committed
feat: sign-in page
1 parent 79050f5 commit 57fa663

23 files changed

+561
-266
lines changed

.eslintrc.js

-20
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,9 @@ module.exports = {
44
root: true,
55
extends: [
66
'@dooboo/eslint-config-react-native',
7-
'plugin:i18n-json/recommended',
87
],
98
rules: {
109
'eslint-comments/no-unlimited-disable': 0,
1110
'eslint-comments/no-unused-disable': 0,
12-
'i18n-json/identical-keys': [
13-
2,
14-
{
15-
filePath: path.resolve('./assets/langs/ko.json'),
16-
},
17-
],
18-
'i18n-json/sorted-keys': [
19-
2,
20-
{
21-
order: 'asc',
22-
indentSpaces: 2,
23-
},
24-
],
25-
'i18n-json/valid-message-syntax': [
26-
2,
27-
{
28-
syntax: path.resolve('./custom-syntax-validator.ts'),
29-
},
30-
],
3111
},
3212
};

.github/workflows/ci.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424
run: bun install --immutable
2525

2626
- name: Check linting
27-
run: bun lint:all
27+
run: bun lint
2828

2929
- name: Build typescript
3030
run: bun tsc

.vscode/settings.json

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
},
3939
"cSpell.words": [
4040
"crossplatformkorea",
41+
"CROSSPLATFORMS",
4142
"dooboo",
4243
"lotties",
4344
"Pressable",

app.config.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export default ({config}: ConfigContext): ExpoConfig => ({
3535
version,
3636
orientation: 'default',
3737
icon: './assets/icon.png',
38+
backgroundColor: '#343434',
3839
plugins: [
3940
[
4041
'expo-build-properties',
@@ -66,7 +67,7 @@ export default ({config}: ConfigContext): ExpoConfig => ({
6667
splash: {
6768
image: './assets/splash.png',
6869
resizeMode: 'cover',
69-
backgroundColor: '#1B1B1B',
70+
backgroundColor: '#343434',
7071
},
7172
extra: {
7273
supabaseUrl: process.env.supabaseUrl,
@@ -111,7 +112,7 @@ export default ({config}: ConfigContext): ExpoConfig => ({
111112
],
112113
adaptiveIcon: {
113114
foregroundImage: './assets/adaptive_icon.png',
114-
backgroundColor: '#2F2F2F',
115+
backgroundColor: '#343434',
115116
},
116117
package: 'com.crossplatformkorea',
117118
intentFilters: [

app/details.tsx renamed to app/(app)/details.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import styled from '@emotion/native';
22
import {Typography} from 'dooboo-ui';
33
import {Stack} from 'expo-router';
44

5-
import {t} from '../src/STRINGS';
5+
import {t} from '../../src/STRINGS';
66

77
const Container = styled.View`
88
flex: 1;

app/index.tsx renamed to app/(app)/index.tsx

+14-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import styled, {css} from '@emotion/native';
22
import AsyncStorage from '@react-native-async-storage/async-storage';
33
import {Button, SwitchToggle, useDooboo} from 'dooboo-ui';
4-
import {Stack, useRouter} from 'expo-router';
4+
import {Redirect, Stack, useRouter} from 'expo-router';
5+
import {useRecoilValue} from 'recoil';
56

6-
import {t} from '../src/STRINGS';
7-
import {AsyncStorageKey} from '../src/utils/constants';
7+
import {authRecoilState} from '../../src/recoil/atoms';
8+
import {t} from '../../src/STRINGS';
9+
import {AsyncStorageKey} from '../../src/utils/constants';
810

911
const Container = styled.View`
1012
background-color: ${({theme}) => theme.bg.basic};
@@ -25,6 +27,15 @@ const Content = styled.View`
2527
export default function Index(): JSX.Element {
2628
const {themeType, changeThemeType} = useDooboo();
2729
const {push} = useRouter();
30+
const authId = useRecoilValue(authRecoilState);
31+
32+
if (!authId) {
33+
return <Redirect href="/sign-in" />;
34+
}
35+
36+
// if (loading) {
37+
// return <LottieView />;
38+
// }
2839

2940
return (
3041
<Container>

app/(auth)/sign-in.tsx

+229
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
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+
}

app/_layout.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,15 @@ SplashScreen.preventAutoHideAsync();
2525
const Container = styled.View`
2626
flex: 1;
2727
align-self: stretch;
28-
background-color: ${({theme}) => theme.bg.paper};
28+
background-color: ${({theme}) => theme.brand};
2929
`;
3030

3131
const Content = styled.View`
3232
align-self: center;
3333
width: 100%;
3434
flex: 1;
3535
max-width: ${COMPONENT_WIDTH + 'px'};
36-
background-color: ${({theme}) => theme.bg.basic};
36+
background-color: ${({theme}) => theme.brand};
3737
`;
3838

3939
function Layout(): JSX.Element | null {

assets/icons/crossplatforms.png

29.3 KB
Loading

assets/icons/[email protected]

75.4 KB
Loading

assets/icons/[email protected]

144 KB
Loading

assets/splash.png

-47.1 KB
Loading

bun.lockb

-7.46 KB
Binary file not shown.

0 commit comments

Comments
 (0)