Skip to content

Commit af2e104

Browse files
committed
feat: upgrade signal comparison UX and account settings flow
Improve the Signal Search graph experience with richer comparison controls and focused layouts, and streamline navigation by replacing legacy classic mode with a dedicated Classic Dashboard tab. Add a full Account Settings page backed by Clerk user data, plus account deletion and updated auth UI copy. Made-with: Cursor
1 parent 541b26f commit af2e104

14 files changed

Lines changed: 1692 additions & 577 deletions

app/(tabs)/_layout.js

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,17 @@ import { Tabs } from 'expo-router';
33
import { NativeTabs, Icon, Label, VectorIcon } from 'expo-router/unstable-native-tabs';
44
import Ionicons from '@expo/vector-icons/Ionicons';
55
import MaterialCommunityIcons from '@expo/vector-icons/MaterialCommunityIcons';
6-
import { Platform } from 'react-native';
6+
import { Image, Platform, View } from 'react-native';
77
import { useTheme } from '../../src/theme/ThemeProvider';
88
import { useAuthGuard } from '../../src/hooks/useAuthGuard';
99
import useDeviceType from '../../src/hooks/useDeviceType';
1010
import { useNavigation } from '../../src/context/NavigationContext';
11+
import { useUser } from '@clerk/expo';
1112

1213
export default function TabLayout() {
1314
const { isDark } = useTheme();
1415
const { isLoaded } = useAuthGuard();
16+
const { user } = useUser();
1517
const deviceType = useDeviceType();
1618
const { infotainmentLeftWidth, showInfotainmentMap } = useNavigation();
1719

@@ -62,7 +64,9 @@ export default function TabLayout() {
6264
6365
[role="tablist"] a[href="/"]::after { content: "Home"; }
6466
[role="tablist"] a[href="/systems"]::after { content: "Systems"; }
67+
[role="tablist"] a[href="/classic-dashboard"]::after { content: "Classic"; }
6568
[role="tablist"] a[href="/signal-search"]::after { content: "Signals"; }
69+
[role="tablist"] a[href="/account"]::after { content: "Account"; }
6670
[role="tablist"] a[href="/profile"]::after { content: "Settings"; }
6771
6872
[role="tablist"] a::after {
@@ -208,9 +212,17 @@ export default function TabLayout() {
208212
name="index"
209213
options={{
210214
title: 'Home',
215+
unmountOnBlur: true,
211216
tabBarIcon: ({ color, size }) => <Ionicons name="home" size={isDesktopSidebar ? 22 : size} color={color} />,
212217
}}
213218
/>
219+
<Tabs.Screen
220+
name="classic-dashboard"
221+
options={{
222+
title: 'Classic',
223+
tabBarIcon: ({ color, size }) => <Ionicons name="speedometer-outline" size={isDesktopSidebar ? 22 : size} color={color} />,
224+
}}
225+
/>
214226
<Tabs.Screen
215227
name="systems"
216228
options={{
@@ -225,6 +237,40 @@ export default function TabLayout() {
225237
tabBarIcon: ({ color, size }) => <MaterialCommunityIcons name="signal-variant" size={isDesktopSidebar ? 22 : size} color={color} />,
226238
}}
227239
/>
240+
<Tabs.Screen
241+
name="account"
242+
options={{
243+
title: 'Account',
244+
tabBarItemStyle: isDesktopSidebar ? { marginTop: 'auto' } : undefined,
245+
tabBarIcon: ({ color, size }) =>
246+
user?.imageUrl ? (
247+
<Image
248+
source={{ uri: user.imageUrl }}
249+
style={{
250+
width: isDesktopSidebar ? 24 : size,
251+
height: isDesktopSidebar ? 24 : size,
252+
borderRadius: 999,
253+
borderWidth: 1,
254+
borderColor: color,
255+
}}
256+
/>
257+
) : (
258+
<View
259+
style={{
260+
width: isDesktopSidebar ? 24 : size,
261+
height: isDesktopSidebar ? 24 : size,
262+
borderRadius: 999,
263+
borderWidth: 1,
264+
borderColor: color,
265+
alignItems: 'center',
266+
justifyContent: 'center',
267+
}}
268+
>
269+
<Ionicons name="person" size={isDesktopSidebar ? 14 : Math.max(12, size - 6)} color={color} />
270+
</View>
271+
),
272+
}}
273+
/>
228274
<Tabs.Screen
229275
name="profile"
230276
options={{
@@ -264,6 +310,14 @@ export default function TabLayout() {
264310
})}
265311
</NativeTabs.Trigger>
266312

313+
<NativeTabs.Trigger name="classic-dashboard">
314+
<Label>Classic</Label>
315+
{Platform.select({
316+
ios: <Icon sf={{ default: 'speedometer', selected: 'speedometer' }} />,
317+
android: <Icon src={<VectorIcon family={Ionicons} name="speedometer-outline" />} />,
318+
})}
319+
</NativeTabs.Trigger>
320+
267321
<NativeTabs.Trigger name="systems">
268322
<Label>Systems</Label>
269323
{Platform.select({
@@ -280,6 +334,14 @@ export default function TabLayout() {
280334
})}
281335
</NativeTabs.Trigger>
282336

337+
<NativeTabs.Trigger name="account">
338+
<Label>Account</Label>
339+
{Platform.select({
340+
ios: <Icon sf={{ default: 'person.circle', selected: 'person.circle.fill' }} />,
341+
android: <Icon src={<VectorIcon family={Ionicons} name="person-circle" />} />,
342+
})}
343+
</NativeTabs.Trigger>
344+
283345
<NativeTabs.Trigger name="profile">
284346
<Label>Settings</Label>
285347
{Platform.select({

app/(tabs)/account.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default } from '../account-settings';

app/(tabs)/classic-dashboard.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import React from 'react';
2+
import ClassicDashboardScreen from '../../src/screens/ClassicDashboardScreen';
3+
4+
export default function ClassicDashboardTab() {
5+
return <ClassicDashboardScreen />;
6+
}

app/_layout.js

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Slot, useRouter, useSegments } from 'expo-router';
2-
import { ThemeProvider, useTheme } from '../src/theme/ThemeProvider';
2+
import { ThemeProvider } from '../src/theme/ThemeProvider';
33
import { NavigationProvider } from '../src/context/NavigationContext';
44
import { TelemetryProvider } from '../src/context/TelemetryContext';
55
import { useFonts } from 'expo-font';
@@ -9,10 +9,8 @@ import { GestureHandlerRootView } from 'react-native-gesture-handler';
99
import { SafeAreaProvider } from 'react-native-safe-area-context';
1010
import { StyleSheet, View, Platform } from 'react-native';
1111
import SharedMapContainer from '../src/components/SharedMapContainer';
12-
import ClassicDashboardScreen from '../src/screens/ClassicDashboardScreen';
1312
import { ClerkProvider, ClerkLoaded, useUser } from '@clerk/expo';
1413
import * as SecureStore from 'expo-secure-store';
15-
import useDeviceType from '../src/hooks/useDeviceType';
1614
import { createClerkExpoWebRouter, getClerkWebProviderUrls } from '../src/lib/clerkWebProviderUrls';
1715

1816
// Token cache for Clerk
@@ -82,10 +80,8 @@ export default function RootLayout() {
8280
}
8381

8482
function AppContent() {
85-
const { classicView } = useTheme();
8683
const { user } = useUser();
8784
const segments = useSegments();
88-
const deviceType = useDeviceType();
8985
const currentTopSegment = segments[0];
9086
const isAuthFlowRoute =
9187
currentTopSegment === 'sign-in' ||
@@ -119,12 +115,7 @@ function AppContent() {
119115
return (
120116
<View style={styles.container}>
121117
<Slot />
122-
{!isAuthFlowRoute && !classicView && <SharedMapContainer />}
123-
{Platform.OS === 'web' && classicView && !deviceType.isPhone && !isAuthFlowRoute && (
124-
<View style={styles.classicOverlay}>
125-
<ClassicDashboardScreen />
126-
</View>
127-
)}
118+
{!isAuthFlowRoute && <SharedMapContainer />}
128119
</View>
129120
);
130121
}
@@ -133,8 +124,4 @@ const styles = StyleSheet.create({
133124
container: {
134125
flex: 1,
135126
},
136-
classicOverlay: {
137-
...StyleSheet.absoluteFillObject,
138-
zIndex: 2000,
139-
},
140127
});

0 commit comments

Comments
 (0)