Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion app/(auth)/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ import { useAuth } from '@clerk/expo';
import { Redirect } from 'expo-router';
import { Stack } from 'expo-router/stack';

import { AppLoadingScreen } from '@/components/ui/app-loading-screen';

export default function AuthLayout() {
const { isLoaded, isSignedIn } = useAuth();

if (!isLoaded) {
return null;
return <AppLoadingScreen />;
}

if (isSignedIn) {
Expand Down
32 changes: 23 additions & 9 deletions app/(auth)/login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import { router, useLocalSearchParams } from 'expo-router';
import { useShareIntentContext } from 'expo-share-intent';
import * as WebBrowser from 'expo-web-browser';
import { useEffect, useRef, useState } from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { Platform, StyleSheet, Text, View } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';

import { ApiError } from '@/api/api-client';
import { SocialLoginButton } from '@/components/ui/social-login-button';
import { SocialLoginButton, type SocialLoginProvider } from '@/components/ui/social-login-button';
import { Colors, Typography } from '@/constants/theme';
import { syncAuthenticatedMember } from '@/services/auth-api';
import { showAlert } from '@/utils/guarded-alert';
Expand All @@ -21,6 +21,10 @@ const CLERK_REDIRECT_URL = AuthSession.makeRedirectUri({
path: 'sso-callback',
});
const MEMBER_SYNC_RETRY_DELAYS_MS = [200, 500, 1000];
const SSO_STRATEGY_BY_PROVIDER = {
google: 'oauth_google',
apple: 'oauth_apple',
} as const;

WebBrowser.maybeCompleteAuthSession();

Expand Down Expand Up @@ -50,7 +54,9 @@ export default function LoginScreen() {
const { hasShareIntent, resetShareIntent, shareIntent } = useShareIntentContext();
const { notice } = useLocalSearchParams<{ notice?: LoginNotice }>();
const shownNoticeRef = useRef<LoginNotice | null>(null);
const [isSigningIn, setIsSigningIn] = useState(false);
const [signingInProvider, setSigningInProvider] = useState<SocialLoginProvider | null>(null);
const isSigningIn = signingInProvider !== null;
const shouldShowAppleLogin = Platform.OS === 'ios';

useEffect(() => {
if (!notice || shownNoticeRef.current === notice) {
Expand All @@ -66,17 +72,17 @@ export default function LoginScreen() {
showAlert(alert.title, alert.message);
}, [notice]);

const handleGoogleLogin = async () => {
const handleSocialLogin = async (provider: SocialLoginProvider) => {
if (isSigningIn) {
return;
}

setIsSigningIn(true);
setSigningInProvider(provider);
let sessionActivated = false;

try {
const { createdSessionId, setActive } = await startSSOFlow({
strategy: 'oauth_google',
strategy: SSO_STRATEGY_BY_PROVIDER[provider],
redirectUrl: CLERK_REDIRECT_URL,
});

Expand Down Expand Up @@ -104,7 +110,7 @@ export default function LoginScreen() {
'계정 연결 중 서버와 통신하지 못했습니다. 잠시 후 다시 시도해주세요.'
);
} finally {
setIsSigningIn(false);
setSigningInProvider(null);
}
};

Expand Down Expand Up @@ -157,10 +163,18 @@ export default function LoginScreen() {
<View style={styles.bottomSection}>
<SocialLoginButton
provider="google"
label={isSigningIn ? 'Google 로그인 중...' : 'Google로 계속하기'}
onPress={handleGoogleLogin}
label={signingInProvider === 'google' ? 'Google 로그인 중...' : 'Google로 계속하기'}
onPress={() => handleSocialLogin('google')}
disabled={isSigningIn}
/>
{shouldShowAppleLogin && (
<SocialLoginButton
provider="apple"
label={signingInProvider === 'apple' ? 'Apple 로그인 중...' : 'Apple로 계속하기'}
onPress={() => handleSocialLogin('apple')}
disabled={isSigningIn}
/>
)}

<Text style={styles.terms}>
계속 진행하면 서비스 이용약관 및 개인정보 처리방침에 동의하는 것으로 간주합니다.
Expand Down
35 changes: 14 additions & 21 deletions app/(tabs)/(folder)/folder-add-url.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import {
Text,
View,
} from 'react-native';
import { router, Stack, useLocalSearchParams } from 'expo-router';
import { router, useLocalSearchParams } from 'expo-router';
import { SafeAreaView } from 'react-native-safe-area-context';

import { Button } from '@/components/ui/button';
import { ScreenHeader } from '@/components/ui/screen-header';
import { SelectableLinkCard } from '@/components/ui/selectable-link-card';
import { Colors, Typography } from '@/constants/theme';
import { getFolderErrorMessage, useFolders } from '@/context/folders-context';
Expand Down Expand Up @@ -68,25 +70,17 @@ export default function FolderAddUrlScreen() {
const selectedCount = selectedIds.size;
const name = folderName ?? '폴더';

const handleBack = () => {
if (router.canGoBack()) {
router.back();
} else {
router.replace({ pathname: '/(tabs)/(folder)/[id]', params: { id: folderId } });
}
};

return (
<>
<Stack.Screen
options={{
headerShown: true,
title: 'URL 추가',
headerBackTitle: '',
headerTransparent: false,
headerStyle: { backgroundColor: Colors.brand.background },
headerTitleStyle: {
...Typography.title,
color: Colors.brand.text,
},
headerTintColor: Colors.brand.text,
headerShadowVisible: false,
}}
/>

<View style={styles.container}>
<SafeAreaView style={styles.container} edges={['top']}>
<ScreenHeader title="URL 추가" onBack={handleBack} />
{/* ── 폴더명 표시 ── */}
<View style={styles.folderNameRow}>
<Text style={styles.folderNameLabel}>추가할 폴더</Text>
Expand Down Expand Up @@ -138,8 +132,7 @@ export default function FolderAddUrlScreen() {
/>
</View>
</View>
</View>
</>
</SafeAreaView>
);
}

Expand Down
34 changes: 14 additions & 20 deletions app/(tabs)/(folder)/folder-name.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ import {
TouchableOpacity,
View,
} from 'react-native';
import { router, Stack } from 'expo-router';
import { router } from 'expo-router';
import { SafeAreaView } from 'react-native-safe-area-context';

import { Button } from '@/components/ui/button';
import { ScreenHeader } from '@/components/ui/screen-header';
import { Colors, Typography } from '@/constants/theme';
import { useFolders } from '@/context/folders-context';
import { useGuardedPress } from '@/utils/press-guard';
Expand Down Expand Up @@ -58,24 +60,17 @@ export default function FolderNameScreen() {
};
const guardedClearFolderName = useGuardedPress(() => setFolderName(''), { lockMs: 250 });

const handleBack = () => {
if (router.canGoBack()) {
router.back();
} else {
router.replace('/(tabs)/(folder)');
}
};

return (
<>
<Stack.Screen
options={{
headerShown: true,
title: '새 폴더 만들기',
headerBackTitle: '',
headerTransparent: false,
headerStyle: { backgroundColor: Colors.brand.background },
headerTitleStyle: {
...Typography.title,
color: Colors.brand.text,
},
headerTintColor: Colors.brand.text,
headerShadowVisible: false,
}}
/>
<View style={styles.safeArea}>
<SafeAreaView style={styles.safeArea} edges={['top']}>
<ScreenHeader title="새 폴더 만들기" onBack={handleBack} />
<KeyboardAvoidingView
style={styles.flex}
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
Expand Down Expand Up @@ -130,8 +125,7 @@ export default function FolderNameScreen() {
</View>
</View>
</KeyboardAvoidingView>
</View>
</>
</SafeAreaView>
);
}

Expand Down
35 changes: 14 additions & 21 deletions app/(tabs)/(folder)/folder-url-select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import {
Text,
View,
} from 'react-native';
import { router, Stack, useLocalSearchParams } from 'expo-router';
import { router, useLocalSearchParams } from 'expo-router';
import { SafeAreaView } from 'react-native-safe-area-context';

import { Button } from '@/components/ui/button';
import { ScreenHeader } from '@/components/ui/screen-header';
import { SelectableLinkCard } from '@/components/ui/selectable-link-card';
import { Colors, Typography } from '@/constants/theme';
import { getFolderErrorMessage, useFolders } from '@/context/folders-context';
Expand Down Expand Up @@ -71,25 +73,17 @@ export default function FolderUrlSelectScreen() {

const selectedCount = selectedIds.size;

const handleBack = () => {
if (router.canGoBack()) {
router.back();
} else {
router.replace('/(tabs)/(folder)');
}
};

return (
<>
<Stack.Screen
options={{
headerShown: true,
title: '새 폴더 만들기',
headerBackTitle: '',
headerTransparent: false,
headerStyle: { backgroundColor: Colors.brand.background },
headerTitleStyle: {
...Typography.title,
color: Colors.brand.text,
},
headerTintColor: Colors.brand.text,
headerShadowVisible: false,
}}
/>

<View style={styles.container}>
<SafeAreaView style={styles.container} edges={['top']}>
<ScreenHeader title="새 폴더 만들기" onBack={handleBack} />
{/* ── 폴더명 표시 ── */}
<View style={styles.folderNameRow}>
<Text style={styles.folderNameLabel}>현재 폴더명</Text>
Expand Down Expand Up @@ -141,8 +135,7 @@ export default function FolderUrlSelectScreen() {
/>
</View>
</View>
</View>
</>
</SafeAreaView>
);
}

Expand Down
5 changes: 2 additions & 3 deletions app/(tabs)/(folder)/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,6 @@ export default function FolderScreen() {
urlCount={folder.linkCount}
width={folderCardWidth}
variant="plain"
compactFolderName={isCompactWidth}
onPress={() => router.push({ pathname: '/(tabs)/(folder)/[id]' as any, params: { id: folder.id } })}
onMorePress={(anchor) => handleMorePress(folder.id, anchor)}
/>
Expand Down Expand Up @@ -436,11 +435,11 @@ const styles = StyleSheet.create({
content: {
paddingHorizontal: CONTENT_HORIZONTAL_PADDING,
paddingBottom: 32,
gap: 20,
gap: 12,
},

header: {
paddingTop: 16,
paddingTop: 6,
gap: 4,
},
title: {
Expand Down
34 changes: 14 additions & 20 deletions app/(tabs)/(home)/add-link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ import {
useWindowDimensions,
View,
} from 'react-native';
import { Stack, router, useLocalSearchParams } from 'expo-router';
import { router, useLocalSearchParams } from 'expo-router';
import { SafeAreaView } from 'react-native-safe-area-context';

import { ApiError } from '@/api/api-client';
import { checkSavedLinkUrl } from '@/api/saved-links';
import { ScanButton } from '@/components/ui/scan-button';
import { ScreenHeader } from '@/components/ui/screen-header';
import { Colors, Typography } from '@/constants/theme';
import { useGuardedPress } from '@/utils/press-guard';
import { normalizeHttpUrlInput } from '@/utils/shared-url';
Expand Down Expand Up @@ -160,24 +162,17 @@ export default function AddLinkScreen() {
setError('');
}, { lockMs: 250 });

const handleBack = () => {
if (router.canGoBack()) {
router.back();
} else {
router.replace('/(tabs)/(home)');
}
};

return (
<>
<Stack.Screen
options={{
headerShown: true,
title: '링크 추가',
headerBackTitle: '',
headerTransparent: false,
headerStyle: { backgroundColor: Colors.brand.background },
headerTitleStyle: {
...Typography.title,
color: Colors.brand.text,
},
headerTintColor: Colors.brand.text,
headerShadowVisible: false,
}}
/>
<View style={styles.safeArea}>
<SafeAreaView style={styles.safeArea} edges={['top']}>
<ScreenHeader title="링크 추가" onBack={handleBack} />
<KeyboardAvoidingView
style={styles.flex}
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
Expand Down Expand Up @@ -243,8 +238,7 @@ export default function AddLinkScreen() {
</View>
</View>
</KeyboardAvoidingView>
</View>
</>
</SafeAreaView>
);
}

Expand Down
5 changes: 3 additions & 2 deletions app/(tabs)/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Redirect, router, Tabs } from 'expo-router';
import { useEffect, useRef, useState } from 'react';

import { ShareIntentRouter } from '@/components/share-intent-router';
import { AppLoadingScreen } from '@/components/ui/app-loading-screen';
import { BottomTabBar, type TabVariant } from '@/components/ui/bottom-tab-bar';
import { FoldersProvider } from '@/context/folders-context';
import { SavedLinksProvider } from '@/context/saved-links-context';
Expand Down Expand Up @@ -136,15 +137,15 @@ export default function TabLayout() {
}, [isLoaded, isSignedIn, sessionId]);

if (!isLoaded) {
return null;
return <AppLoadingScreen />;
}

if (!isSignedIn) {
return <Redirect href="/login" />;
}

if (!hasSyncedMember) {
return null;
return <AppLoadingScreen />;
}

return (
Expand Down
Loading
Loading