Skip to content

Commit dd54f29

Browse files
authored
fix - 라우팅 구조 개선 및 UI 업데이트 (#12)
* feat: 라우팅 개선 및 기타 성별 제거 * refactor: 회원가입 이후 온보딩 페이지로 라우팅 * feat: 온보딩 UI 업데이트 * feat: 버전 업데이트 * fix: 오류 처리 개선 및 불필요한 코드 제거
1 parent 49306f2 commit dd54f29

File tree

11 files changed

+75
-57
lines changed

11 files changed

+75
-57
lines changed

frontend/app.config.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export default ({ config }: ConfigContext): ExpoConfig => ({
99
// ===== App 기본 정보 =====
1010
name: '운세한장',
1111
slug: 'dailyfate',
12-
version: '1.0.2',
12+
version: '1.0.3',
1313

1414
// ===== 환경 변수 =====
1515
extra: {
@@ -55,7 +55,7 @@ export default ({ config }: ConfigContext): ExpoConfig => ({
5555
...config.android,
5656
package: 'com.dailyfate.frontend',
5757

58-
// @ts-ignore — Expo에서 실제 지원하는 속성
58+
// @ts-expect-error - Expo config type does not include `label` yet.
5959
label: '운세한장',
6060

6161
adaptiveIcon: {

frontend/app/index.tsx

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,19 @@ export default function Home() {
2626
const [userSettings, setUserSettings] = useState<UserSettings | null>(null);
2727
const [isSettingsOpen, setIsSettingsOpen] = useState(false);
2828
const [needsProfileSetup, setNeedsProfileSetup] = useState(false);
29+
const [needsOnboarding, setNeedsOnboarding] = useState(false);
2930
const [profileSaving, setProfileSaving] = useState(false);
3031

3132
const { isBootstrapping: authBootstrapping, isSignedIn, signOut } = useAuth();
3233

34+
const canLoadFortune =
35+
isSignedIn && !!userSettings && !needsProfileSetup && (!needsOnboarding || hasOnboarded);
36+
3337
const {
3438
fortune,
3539
loading: loadingFortune,
3640
error,
37-
} = useFortune(currentDate, hasOnboarded && !!userSettings && isSignedIn);
41+
} = useFortune(currentDate, canLoadFortune);
3842

3943
// Load persisted state
4044
useEffect(() => {
@@ -61,6 +65,7 @@ export default function Home() {
6165
if (isSignedIn) return;
6266
setIsSettingsOpen(false);
6367
setNeedsProfileSetup(false);
68+
setNeedsOnboarding(false);
6469
}, [isSignedIn]);
6570

6671
// Header: show only when main screen is active
@@ -78,15 +83,22 @@ export default function Home() {
7883
await AsyncStorage.setItem(USER_SETTINGS_KEY, JSON.stringify(settings));
7984
};
8085

86+
const handleSignUpSuccess = useCallback(() => {
87+
setNeedsProfileSetup(true);
88+
setNeedsOnboarding(true);
89+
}, []);
90+
91+
const handleOnboardingComplete = () => {
92+
setNeedsOnboarding(false);
93+
void persistHasOnboarded();
94+
};
95+
8196
const handleUserInfoSubmit = async (settings: UserSettings) => {
8297
if (profileSaving) return;
8398
setProfileSaving(true);
8499
try {
85100
const updatedSettings = await updateUserProfile(settings);
86101
await persistUserSettings(updatedSettings);
87-
if (!hasOnboarded) {
88-
await persistHasOnboarded();
89-
}
90102
setNeedsProfileSetup(false);
91103
} catch (error) {
92104
if (error instanceof ProfileApiError && error.status === 401) {
@@ -136,15 +148,15 @@ export default function Home() {
136148
}
137149

138150
if (!isSignedIn) {
139-
return <LoginScreen />;
151+
return <LoginScreen onSignUpSuccess={handleSignUpSuccess} />;
140152
}
141153

142-
const showOnboarding = !hasOnboarded && !needsProfileSetup;
154+
const showOnboarding = needsOnboarding && !needsProfileSetup;
143155
const showUserForm = needsProfileSetup;
144156

145157
return (
146158
<View className="flex-1 bg-white">
147-
{showOnboarding && <Onboarding onComplete={persistHasOnboarded} />}
159+
{showOnboarding && <Onboarding onComplete={handleOnboardingComplete} />}
148160
{showUserForm && !showOnboarding && (
149161
<UserInfoForm
150162
initialValues={userSettings || undefined}

frontend/eslint.config.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ const prettierConfig = require('eslint-config-prettier');
88
const runtimeGlobals = {
99
console: 'readonly',
1010
process: 'readonly',
11+
fetch: 'readonly',
12+
Headers: 'readonly',
13+
Request: 'readonly',
14+
Response: 'readonly',
15+
AbortController: 'readonly',
1116
setTimeout: 'readonly',
1217
clearTimeout: 'readonly',
1318
setInterval: 'readonly',

frontend/src/components/CalendarPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ const CalendarPage: React.FC<Props> = ({
414414
</View>
415415
) : fortune ? (
416416
<Text className="text-center font-serif text-lg font-semibold leading-7 text-gray-600 font-noto">
417-
" {fortune.overview} "
417+
&quot; {fortune.overview} &quot;
418418
</Text>
419419
) : (
420420
<Text className="text-center font-serif text-sm text-gray-300">

frontend/src/components/Onboarding.tsx

Lines changed: 42 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,55 @@
11
import React from 'react';
22
import { Pressable, Text, View } from 'react-native';
33
import { Feather } from '@expo/vector-icons';
4+
import { SafeAreaView } from 'react-native-safe-area-context';
45

56
interface Props {
67
onComplete: () => void;
78
}
89

910
const Onboarding: React.FC<Props> = ({ onComplete }) => {
1011
return (
11-
<View className="absolute inset-0 z-10 items-center justify-center bg-stone-200 px-5 py-6">
12-
<View className="w-full max-w-xl rounded-2xl bg-white p-5 shadow-2xl shadow-black/10">
13-
<View className="items-center space-y-3.5">
14-
<View className="h-14 w-14 items-center justify-center rounded-full bg-gray-100">
15-
<Feather name="star" size={26} color="#111827" />
16-
</View>
17-
<Text className="text-2xl font-bold text-gray-900">하루 일력</Text>
18-
<Text className="text-center text-sm leading-5 text-gray-500">
19-
매일 아침, 종이 일력을 뜯듯 당신의 하루를 확인해보세요.
20-
</Text>
12+
<SafeAreaView edges={['top']} className="flex-1 bg-white p-4">
13+
<View>
14+
<View className="w-full rounded-2xl bg-white gap-8">
15+
<View className="items-center gap-6">
16+
<View className="h-14 w-14 items-center justify-center rounded-full bg-gray-100">
17+
<Feather name="star" size={26} color="#111827" />
18+
</View>
19+
<Text className="text-4xl font-bold text-gray-900">하루 일력</Text>
20+
<Text className="text-center text-lg leading-5 text-gray-500">
21+
매일 아침, 종이 일력을 뜯듯 당신의 하루를 확인해보세요.
22+
</Text>
2123

22-
<View className="w-full space-y-3 rounded-xl border border-gray-200 bg-gray-50 p-4">
23-
<GuideItem
24-
icon="scissors"
25-
title="다음 날로 넘기기"
26-
text="상단을 눌러 종이를 뜯듯 내일로 넘어가요."
27-
/>
28-
<GuideItem
29-
icon="calendar"
30-
title="오늘의 총평"
31-
text="큰 날짜 아래 핵심 운세를 바로 볼 수 있어요."
32-
/>
33-
<GuideItem
34-
icon="chevron-down"
35-
title="상세 운세"
36-
text="스크롤로 재물·애정·성공운을 확인하세요."
37-
/>
24+
<View className="w-full rounded-xl border border-gray-200 bg-gray-50 p-4 gap-8">
25+
<GuideItem
26+
icon="scissors"
27+
title="다음 날로 넘기기"
28+
text="상단을 눌러 종이를 뜯듯 내일로 넘어가요."
29+
/>
30+
<GuideItem
31+
icon="calendar"
32+
title="오늘의 총평"
33+
text="큰 날짜 아래 핵심 운세를 바로 볼 수 있어요."
34+
/>
35+
<GuideItem
36+
icon="chevron-down"
37+
title="상세 운세"
38+
text="스크롤로 재물·애정·성공운을 확인하세요."
39+
/>
40+
</View>
3841
</View>
39-
</View>
4042

41-
<Pressable
42-
className="mt-5 rounded-xl bg-gray-900 py-3.5 active:opacity-90"
43-
onPress={onComplete}
44-
accessibilityLabel="온보딩 완료"
45-
>
46-
<Text className="text-center text-lg font-bold text-white">시작하기</Text>
47-
</Pressable>
43+
<Pressable
44+
className="mt-5 rounded-xl bg-gray-900 py-3.5 active:opacity-90"
45+
onPress={onComplete}
46+
accessibilityLabel="온보딩 완료"
47+
>
48+
<Text className="text-center text-lg font-bold text-white">시작하기</Text>
49+
</Pressable>
50+
</View>
4851
</View>
49-
</View>
52+
</SafeAreaView>
5053
);
5154
};
5255

@@ -59,11 +62,11 @@ const GuideItem = ({
5962
title: string;
6063
text: string;
6164
}) => (
62-
<View className="flex-row space-x-3">
63-
<Feather name={icon} size={16} color="#6b7280" style={{ marginTop: 2 }} />
65+
<View className="flex-row gap-4 items-center">
66+
<Feather name={icon} size={25} color="#6b7280" style={{ marginTop: 2 }} />
6467
<View className="flex-1">
65-
<Text className="text-sm font-bold text-gray-900">{title}</Text>
66-
<Text className="mt-0.5 text-xs leading-5 text-gray-500">{text}</Text>
68+
<Text className="text-xl font-bold text-gray-900">{title}</Text>
69+
<Text className="mt-0.5 text-lg leading-5 text-gray-500">{text}</Text>
6770
</View>
6871
</View>
6972
);

frontend/src/components/SettingsSheet.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import {
66
Modal,
77
Platform,
88
Pressable,
9-
Switch,
109
Text,
1110
TextInput,
1211
View,

frontend/src/components/UserInfoForm.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ interface Props {
2020
const genderOptions: { val: Gender; label: string }[] = [
2121
{ val: 'male', label: '남성' },
2222
{ val: 'female', label: '여성' },
23-
{ val: 'other', label: '기타' },
2423
];
2524

2625
const ITEM_HEIGHT = 36;

frontend/src/providers/AuthProvider.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
3939
try {
4040
const token = await getAuthToken();
4141
if (active) setIsSignedIn(Boolean(token));
42-
} catch (_err) {
42+
} catch {
4343
if (active) setIsSignedIn(false);
4444
} finally {
4545
if (active) setIsBootstrapping(false);

frontend/src/services/authService.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ const loadCache = async () => {
9898
if (tokenRaw) {
9999
try {
100100
cachedTokens = JSON.parse(tokenRaw) as AuthTokens;
101-
} catch (_err) {
101+
} catch {
102102
cachedTokens = null;
103103
}
104104
} else {

frontend/src/services/fortuneService.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,10 @@ const readPayload = async (response: Response) => {
5050
if (!rawText) return { payload: null, rawText: null };
5151
try {
5252
return { payload: JSON.parse(rawText) as FortuneApiResponse, rawText };
53-
} catch (_error) {
53+
} catch {
5454
return { payload: null, rawText };
5555
}
56-
} catch (_error) {
56+
} catch {
5757
return { payload: null, rawText: null };
5858
}
5959
};

0 commit comments

Comments
 (0)