Skip to content

Commit 82640a9

Browse files
authored
Merge pull request #6 from Retsomm/dev
implement state management and bottom navigation
2 parents 8785803 + f451e5d commit 82640a9

17 files changed

Lines changed: 1024 additions & 415 deletions

.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY=YOUR_CLERK_PUBLISHABLE_KEY

app/(tabs)/_layout.tsx

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { BottomTabBar } from "@/components/bottom-tab-bar";
2+
import { useLanguageStore } from "@/store/UseLanguageStore";
3+
import { useAuth } from "@clerk/expo";
4+
import { Redirect, Tabs } from "expo-router";
5+
6+
export default function TabsLayout() {
7+
const { isLoaded, isSignedIn } = useAuth();
8+
const hasHydratedLanguage = useLanguageStore((state) => state.hasHydrated);
9+
const selectedLanguageId = useLanguageStore((state) => state.selectedLanguageId);
10+
11+
if (!isLoaded || !hasHydratedLanguage) {
12+
return null;
13+
}
14+
15+
if (!isSignedIn) {
16+
return <Redirect href="/onboarding" />;
17+
}
18+
19+
if (!selectedLanguageId) {
20+
return <Redirect href="/LanguageSelection" />;
21+
}
22+
23+
return (
24+
<Tabs
25+
initialRouteName="home"
26+
screenOptions={{ headerShown: false }}
27+
tabBar={(props) => <BottomTabBar {...props} />}
28+
>
29+
<Tabs.Screen name="home" options={{ title: "Home" }} />
30+
<Tabs.Screen name="learn" options={{ title: "Learn" }} />
31+
<Tabs.Screen name="ai-teacher" options={{ title: "AI Teacher" }} />
32+
<Tabs.Screen name="chat" options={{ title: "Chat" }} />
33+
<Tabs.Screen name="profile" options={{ title: "Profile" }} />
34+
</Tabs>
35+
);
36+
}

app/(tabs)/ai-teacher.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { TabPlaceholderScreen } from "@/components/tab-placeholder-screen";
2+
3+
export default function AiTeacherScreen() {
4+
return (
5+
<TabPlaceholderScreen
6+
title="AI Teacher"
7+
subtitle="Video teacher sessions will live here."
8+
/>
9+
);
10+
}

app/(tabs)/chat.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { TabPlaceholderScreen } from "@/components/tab-placeholder-screen";
2+
3+
export default function ChatScreen() {
4+
return (
5+
<TabPlaceholderScreen
6+
title="Chat"
7+
subtitle="AI tutor conversations will live here."
8+
/>
9+
);
10+
}

app/(tabs)/home.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { TabPlaceholderScreen } from "@/components/tab-placeholder-screen";
2+
3+
export default function HomeScreen() {
4+
return (
5+
<TabPlaceholderScreen
6+
title="Home"
7+
subtitle="Home content will be implemented in the next step."
8+
/>
9+
);
10+
}

app/(tabs)/learn.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { TabPlaceholderScreen } from "@/components/tab-placeholder-screen";
2+
3+
export default function LearnScreen() {
4+
return (
5+
<TabPlaceholderScreen
6+
title="Learn"
7+
subtitle="Lesson browsing and practice will live here."
8+
/>
9+
);
10+
}

app/(tabs)/profile.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { TabPlaceholderScreen } from "@/components/tab-placeholder-screen";
2+
3+
export default function ProfileScreen() {
4+
return (
5+
<TabPlaceholderScreen
6+
title="Profile"
7+
subtitle="Account details and learning stats will live here."
8+
/>
9+
);
10+
}
Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { images } from "@/constants/images";
22
import { defaultLanguageId, languages } from "@/data/languages";
3+
import { useLanguageStore } from "@/store/UseLanguageStore";
34
import type { SupportedLanguage } from "@/types/learning";
45
import { Ionicons } from "@expo/vector-icons";
56
import { router } from "expo-router";
@@ -19,8 +20,14 @@ import { useSafeAreaInsets } from "react-native-safe-area-context";
1920
export default function LanguageSelectionScreen() {
2021
const insets = useSafeAreaInsets();
2122
const { width } = useWindowDimensions();
23+
const persistedLanguageId = useLanguageStore((state) => state.selectedLanguageId);
24+
const setSelectedLanguage = useLanguageStore(
25+
(state) => state.setSelectedLanguageId,
26+
);
2227
const [searchQuery, setSearchQuery] = useState("");
23-
const [selectedLanguageId, setSelectedLanguageId] = useState(defaultLanguageId);
28+
const [selectedLanguageId, setSelectedLanguageId] = useState(
29+
persistedLanguageId ?? defaultLanguageId,
30+
);
2431
const earthWidth = Math.min(width * 0.95, 520);
2532
const earthHeight = earthWidth * (828 / 1127);
2633

@@ -51,6 +58,15 @@ export default function LanguageSelectionScreen() {
5158
[selectedLanguageId],
5259
);
5360

61+
const handleConfirmLanguage = () => {
62+
if (!selectedLanguage) {
63+
return;
64+
}
65+
66+
setSelectedLanguage(selectedLanguage.id);
67+
router.replace("/");
68+
};
69+
5470
return (
5571
<View className="flex-1 bg-white">
5672
<ScrollView
@@ -133,6 +149,8 @@ export default function LanguageSelectionScreen() {
133149
<Pressable
134150
accessibilityLabel={`Confirm ${selectedLanguage.name}`}
135151
className="mt-[24px] flex-row items-center justify-center gap-[12px] rounded-[26px] bg-lingua-deep-purple px-[22px] py-[18px]"
152+
disabled={!selectedLanguage}
153+
onPress={handleConfirmLanguage}
136154
style={({ pressed }) => [styles.confirmButton, pressed && styles.pressed]}
137155
>
138156
<Ionicons name="checkmark-circle" size={26} color="#FFFFFF" />

0 commit comments

Comments
 (0)