proposal-system/mobile/src/navigation/RootNavigator.tsx

149 lines
4.6 KiB
TypeScript
Raw Normal View History

import React from 'react';
import { ActivityIndicator, View, StyleSheet } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import { useSelector } from 'react-redux';
import {
selectIsAuthenticated,
selectAuthLoading,
selectUser,
} from '../store/slices/authSlice';
import type {
RootStackParamList,
MainTabParamList,
ProposalsStackParamList,
} from './types';
import { LoginScreen } from '../screens/auth/LoginScreen';
import { DashboardScreen } from '../screens/dispatcher/DashboardScreen';
import { AdminDashboardScreen } from '../screens/admin/AdminDashboardScreen';
import { NewProposalScreen } from '../screens/dispatcher/NewProposalScreen';
import { ProposalDetailScreen } from '../screens/dispatcher/ProposalDetailScreen';
import { ProposalQueueScreen } from '../screens/admin/ProposalQueueScreen';
import { ProposalWorkspaceScreen } from '../screens/admin/ProposalWorkspaceScreen';
import { LineItemEditScreen } from '../screens/admin/LineItemEditScreen';
import { SettingsScreen } from '../screens/SettingsScreen';
const RootStack = createNativeStackNavigator<RootStackParamList>();
const Tab = createBottomTabNavigator<MainTabParamList>();
const ProposalsStack = createNativeStackNavigator<ProposalsStackParamList>();
function ProposalsNavigator() {
const user = useSelector(selectUser);
const isAdmin = user?.role === 'Admin' || user?.role === 'SysAdmin';
return (
<ProposalsStack.Navigator screenOptions={{ headerShown: true }}>
<ProposalsStack.Screen
name="ProposalList"
component={ProposalQueueScreen}
options={{ title: isAdmin ? 'Proposal Queue' : 'My Proposals' }}
/>
<ProposalsStack.Screen
name="NewProposal"
component={NewProposalScreen}
options={{ title: 'New Proposal' }}
/>
<ProposalsStack.Screen
name="ProposalDetail"
component={ProposalDetailScreen}
options={{ title: 'Proposal' }}
/>
<ProposalsStack.Screen
name="ProposalWorkspace"
component={ProposalWorkspaceScreen}
options={{ title: 'Proposal' }}
/>
<ProposalsStack.Screen
name="LineItemEdit"
component={LineItemEditScreen}
options={{ title: 'Edit Line Item' }}
/>
</ProposalsStack.Navigator>
);
}
function DashboardRouter() {
const user = useSelector(selectUser);
const isAdmin = user?.role === 'Admin' || user?.role === 'SysAdmin';
return isAdmin ? <AdminDashboardScreen /> : <DashboardScreen />;
}
function MainTabs() {
return (
<Tab.Navigator
screenOptions={({ route }) => ({
headerShown: route.name === 'DashboardTab',
tabBarIcon: ({ color, size }) => {
const icons: Record<string, string> = {
DashboardTab: 'view-dashboard',
ProposalsTab: 'file-document-outline',
SettingsTab: 'cog-outline',
};
return (
<Icon
name={icons[route.name] || 'circle'}
size={size}
color={color}
/>
);
},
tabBarActiveTintColor: '#1565C0',
tabBarInactiveTintColor: '#757575',
})}
>
<Tab.Screen
name="DashboardTab"
component={DashboardRouter}
options={{ title: 'Dashboard' }}
/>
<Tab.Screen
name="ProposalsTab"
component={ProposalsNavigator}
options={{ headerShown: false, title: 'Proposals' }}
/>
<Tab.Screen
name="SettingsTab"
component={SettingsScreen}
options={{ title: 'Settings' }}
/>
</Tab.Navigator>
);
}
export function RootNavigator() {
const isAuthenticated = useSelector(selectIsAuthenticated);
const loading = useSelector(selectAuthLoading);
if (loading) {
return (
<View style={styles.loading}>
<ActivityIndicator size="large" color="#1565C0" />
</View>
);
}
return (
<NavigationContainer>
<RootStack.Navigator screenOptions={{ headerShown: false }}>
{isAuthenticated ? (
<RootStack.Screen name="Main" component={MainTabs} />
) : (
<RootStack.Screen name="Auth" component={LoginScreen} />
)}
</RootStack.Navigator>
</NavigationContainer>
);
}
const styles = StyleSheet.create({
loading: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#FAFAFA',
},
});