Front: Navigation: Use actual routes to build a typed navigator

This commit is contained in:
Arthur Jamet
2023-04-14 11:46:40 +01:00
parent 9cd6c90188
commit b0e01ffbed
10 changed files with 52 additions and 32 deletions
+37 -16
View File
@@ -1,4 +1,5 @@
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { NavigationProp, useNavigation as navigationHook } from "@react-navigation/native";
import React from 'react';
import { DarkTheme, DefaultTheme, NavigationContainer } from '@react-navigation/native';
import { RootState, useSelector } from './state/Store';
@@ -17,21 +18,39 @@ import LoadingComponent from './components/Loading';
import ProfileView from './views/ProfileView';
import useColorScheme from './hooks/colorScheme';
const Stack = createNativeStackNavigator();
const protectedRoutes = () => ({
Home: { component: HomeView, options: { title: translate('welcome') } },
Settings: { component: SetttingsNavigator, options: { title: 'Settings' } },
Song: { component: SongLobbyView, options: { title: translate('play') } },
Play: { component: PlayView, options: { title: translate('play') } },
Score: { component: ScoreView, options: { title: translate('score') } },
Search: { component: SearchView, options: { title: translate('search') } },
User: { component: ProfileView, options: { title: translate('user') } },
}) as const;
export const protectedRoutes = <>
<Stack.Screen name="Home" component={HomeView} options={{ title: translate('welcome') }} />
<Stack.Screen name="Settings" component={SetttingsNavigator} options={{ title: 'Settings' }} />
<Stack.Screen name="Song" component={SongLobbyView} options={{ title: translate('play') }} />
<Stack.Screen name="Play" component={PlayView} options={{ title: translate('play') }} />
<Stack.Screen name="Score" component={ScoreView} options={{ title: translate('score') }} />
<Stack.Screen name="Search" component={SearchView} options={{ title: translate('search') }} />
<Stack.Screen name="User" component={ProfileView} options={{ title: translate('user') }} />
</>;
const publicRoutes = () => ({
Login: { component: AuthenticationView, options: { title: translate('signInBtn') } },
}) as const;
export const publicRoutes = <React.Fragment>
<Stack.Screen name="Login" component={AuthenticationView} options={{ title: translate('signInBtn')}} />
</React.Fragment>;
type Route<Args extends any[] = any[]> = {
component: (...args: Args) => JSX.Element,
options: any
}
type RouteParams<Routes extends Record<string, Route>> = {
[RouteName in keyof Routes]: Parameters<Routes[RouteName]['component']>[0];
}
type PrivateRoutesParams = RouteParams<ReturnType<typeof protectedRoutes>>;
type PublicRoutesParams = RouteParams<ReturnType<typeof publicRoutes>>;
type AppRouteParams = PrivateRoutesParams & PublicRoutesParams;
const Stack = createNativeStackNavigator<AppRouteParams & { Loading: never }>();
const routesToScreens = (routes: Record<string, Route>) => Object.entries(routes)
.map(([name, route]) => (
<Stack.Screen name={name as any} {...route}/>
))
export const Router = () => {
const accessToken = useSelector((state: RootState) => state.user.accessToken);
@@ -53,11 +72,13 @@ export const Router = () => {
<LoadingComponent/>
</Center>
}/>
: userProfile.isSuccess && accessToken
? protectedRoutes
: publicRoutes
: routesToScreens(userProfile.isSuccess && accessToken
? protectedRoutes()
: publicRoutes())
}
</Stack.Navigator>
</NavigationContainer>
);
}
export const useNavigation = () => navigationHook<NavigationProp<AppRouteParams>>();