React native disable StackNavigator and DrawerNavigator - react-native

I'm trying to disable some of the menus of my app according to the user access level.
Here are my Navigators:
const MainStackNavigator = createStackNavigator({
Home,
Company: {
screen: CompanyDetails,
navigationOptions: {
headerTitle: 'Company Details'
}
},
Tenants: {
screen: Tenants,
navigationOptions: {
headerTitle: 'Tenants'
}
}
}, {
defaultNavigationOptions: ({ navigation }) => {
return {
headerLeft: (
<Ionicons
style={{ paddingLeft: 10 }}
onPress={() => navigation.openDrawer()}
name="md-menu"
size={30}
/>
)
};
}
});
const AppDrawerNavigator = createDrawerNavigator({
myApp: {
screen: MainStackNavigator
},
Home: {
screen: Home,
navigationOptions: {
drawerIcon: <FontAwesome name="home" size={20} />
}
},
Company: {
screen: CompanyDetails,
navigationOptions: {
drawerIcon: <FontAwesome name="building-o" size={20} />
}
},
Tenants: {
screen: TenantDetails,
navigationOptions: {
drawerIcon: <Ionicons name="ios-person" size={20} />
}
},
LogOut: {
screen: Login,
navigationOptions: {
title: 'Log Out',
drawerIcon: <Entypo name="log-out" size={20} />
}
}
});
I would like to disable the Company menu (showing but no clickable) if the userAccessLevel is not 1. I can get the userAccessLevel from my authentication: AsyncStorage.getItem('UserLevel')
Is it possible?
Thanks

It's possible, You can use customdrawernaivgation.
const AppDrawerNavigator = createDrawerNavigator({
myApp: {
screen: MainStackNavigator
},
Home: {
screen: Home,
navigationOptions: {
drawerIcon: <FontAwesome name="home" size={20} />
}
},
Company: {
screen: CompanyDetails,
navigationOptions: {
drawerIcon: <FontAwesome name="building-o" size={20} />
}
},
Tenants: {
screen: TenantDetails,
navigationOptions: {
drawerIcon: <Ionicons name="ios-person" size={20} />
}
},
LogOut: {
screen: Login,
navigationOptions: {
title: 'Log Out',
drawerIcon: <Entypo name="log-out" size={20} />
}
}
}, {
drawerPosition: 'left',
drawerType: 'slide',
contentComponent: CustomDrawerNavigation,
drawerBackgroundColor: '#091b40',
drawerOpenRoute: 'DrawerOpen',
drawerCloseRoute: 'DrawerClose',
drawerToggleRoute: 'DrawerToggle',
drawerWidth: (width / 3) * 2,
});
class CustomDrawerNavigation extends React.Component {
render() {
return (
<SafeAreaView>
<ScrollView>
{data.map((each, index) => {
if(each.name === 'Company' && level !== 1) {
return <View/>;
}
return (
<TouchableOpacity
key={each.name}
onPress={() => this.props.navigation.navigate(each.route)}>
<View style={styles.menuContainer}>
<Icon style={styles.iconStyle} name={each.icon} />
<Text style={styles.textStyle}>{translate(each.name)}</Text>
</View>
</TouchableOpacity>
);
});
}
)};
}
Hope this will help you

Related

createStackNavigator with submenu

How can I create a submenu in createStackNavigator?
I created my navigation as below:
const MainStackNavigator = createStackNavigator({
Home: {
screen: HomeScreen,
navigationOptions: {
headerTitle: 'iRent'
}
},
Company: {
screen: CompanyDetails,
navigationOptions: {
headerTitle: 'Company Details'
}
},
Snapshots: {
screen: PropSnapshot,
navigationOptions: {
headerTitle: 'Property Snapshots'
}
}
}, {
defaultNavigationOptions: ({ navigation }) => {
return {
headerLeft: (
<Ionicons
style={{ paddingLeft: 10 }}
onPress={() => navigation.openDrawer()}
name="md-menu"
size={30}
/>
)
};
}
});
const AppDrawerNavigator = createDrawerNavigator({
myApp: {
screen: MainStackNavigator
},
Home: {
screen: HomeScreen,
navigationOptions: {
drawerIcon: <FontAwesome name="home" size={20} />
}
},
Company: {
screen: CompanyDetails,
navigationOptions: {
drawerIcon: <FontAwesome name="building-o" size={20} />
}
},
Snapshots: {
screen: PropSnapshot,
navigationOptions: {
drawerIcon: <MaterialIcons name="data-usage" size={20} />
}
},
LogOut: {
screen: Login,
navigationOptions: {
title: 'Log Out',
drawerIcon: <Entypo name="log-out" size={20} />
}
}
});
const AppSwitchNavigator = createSwitchNavigator({
Login: { screen: Login },
ForgotPassword: { screen: ForgotPassword },
Main: { screen: AppDrawerNavigator }
});
const AppContainer = createAppContainer(AppSwitchNavigator);
It is working perfect, but how can I add submenus to the Company menu. I would like to have "Company Details", "Company Test" under the Company menu in the left menu bar. Is it possible to do using the createStackNavigator?
Thanks!
As far I understand, you need a dropdown menu which will contain your companies details when you click on company.
If you want this, then try to do with drawer navigation.
When you click on company a drawer will open between company and snapshot.
Rest navigate as you want.

React Native render() not being called after navigation

I have a Footer component which is shared to all my screens. It has a method that updates the current property and returns to Home Page
...
class FooterComp extends Component {
changeProperty = async (data) => {
await AsyncStorage.setItem('CurrentPropertyID', data.toString());
await this.setState({ CurrentPropertyID: data.toString() });
NavigationService.navigate('Home');
}
}
...
My navigation service:
import { NavigationActions } from 'react-navigation';
let _navigator;
function setTopLevelNavigator(navigatorRef) {
_navigator = navigatorRef;
}
function navigate(routeName, params) {
_navigator.dispatch(
NavigationActions.navigate({
routeName,
params,
})
);
}
// add other navigation functions that you need and export them
export default {
navigate,
setTopLevelNavigator,
};
My App.js
class App extends Component {
render() {
const store = createStore(reducers, {}, applyMiddleware(ReduxThunk));
return (
<Provider store={store}>
<AppContainer
ref={navigatorRef => {
NavigationService.setTopLevelNavigator(navigatorRef);
}}
/>
</Provider>
);
}
}
export default App;
const MainStackNavigator = createStackNavigator({
Home: {
screen: HomeScreen,
navigationOptions: {
headerTitle: 'iRent'
}
},
Company: {
screen: CompanyDetails,
navigationOptions: {
headerTitle: 'Company Details'
}
},
Tenants: {
screen: Tenants,
navigationOptions: {
headerTitle: 'Tenants'
}
},
WorkOrders: {
screen: WorkOrders,
navigationOptions: {
headerTitle: 'Work Orders'
}
},
Applicants: {
screen: Applicants,
navigationOptions: {
headerTitle: 'Applicants'
}
},
Bills: {
screen: Bills,
navigationOptions: {
headerTitle: 'Bills'
}
}
}, {
defaultNavigationOptions: ({ navigation }) => {
return {
headerLeft: (
<Ionicons
style={{ paddingLeft: 10 }}
onPress={() => navigation.openDrawer()}
name="md-menu"
size={30}
/>
)
};
}
});
const AppDrawerNavigator = createDrawerNavigator({
iRent: {
screen: MainStackNavigator
},
Home: {
screen: HomeScreen,
navigationOptions: {
drawerIcon: <FontAwesome name="home" size={20} />
}
},
Company: {
screen: CompanyDetails,
navigationOptions: {
drawerIcon: <FontAwesome name="building-o" size={20} />
}
},
Tenants: {
screen: TenantDetails,
navigationOptions: {
drawerIcon: <Ionicons name="ios-person" size={20} />
}
},
Applicants: {
screen: Applicants,
navigationOptions: {
drawerIcon: <MaterialCommunityIcons name="account-search" size={20} />
}
},
WorkOrders: {
screen: WorkOrders,
navigationOptions: {
title: 'Work Orders',
drawerIcon: <Octicons name="checklist" size={20} />
}
},
Bills: {
screen: Bills,
navigationOptions: {
title: 'Bills',
drawerIcon: <Entypo name="text-document" size={20} />
}
},
LogOut: {
screen: Login,
navigationOptions: {
title: 'Log Out',
drawerIcon: <Entypo name="log-out" size={20} />
}
}
});
const AppSwitchNavigator = createSwitchNavigator({
Login: { screen: Login },
ForgotPassword: { screen: ForgotPassword },
Main: { screen: AppDrawerNavigator },
TenantDetails: { screen: TenantDetails },
EditData: { screen: EditData },
EditReview: { screen: EditReview },
ApplicantDetails: { screen: ApplicantDetails },
RunScreening: { screen: RunScreening },
OpenBGReport: { screen: OpenBGReport },
WorkOrderDetails: { screen: WorkOrderDetails },
ConvertToTenant: { screen: ConvertToTenant },
EditBill: { screen: EditBill },
NoAccess: { screen: NoAccess },
});
const AppContainer = createAppContainer(AppSwitchNavigator);
My HomeScreen
class HomeScreen extends Component {
constructor(props) {
super(props);
this.state = {
data: [
{ id: 1, title: 'Tenants', nav: 'Tenants', image: 'http://myirent.com/rent/appImg/tenants.jpg' },
{ id: 2, title: 'Applicants', nav: 'Applicants', image: 'http://myirent.com/rent/appImg/applicants.png' },
{ id: 3, title: 'Work Orders', nav: 'WorkOrders', image: 'http://myirent.com/rent/appImg/workOrders.png' },
{ id: 4, title: 'Bills', nav: 'Bills', image: 'http://myirent.com/rent/appImg/bills.png' }
],
currentPropertyID: null
};
}
componentDidMount = async () => {
await AsyncStorage.getItem('CurrentPropertyID')
.then((value) => {
const propID = JSON.parse(value);
this.setState({
currentPropertyID: propID.toString()
});
});
}
render() {
console.log('Render Main. PID: ' + this.state.currentPropertyID);
return (
<View style={styles.container}>
<FlatList
style={styles.list}
data={this.state.data}
keyExtractor={(item) => {
return item.id.toString();
}}
ItemSeparatorComponent={() => {
return (
<View style={styles.separator} />
);
}}
renderItem={(post) => {
const item = post.item;
return (
<TouchableOpacity
onPress={() => { this.props.navigation.navigate(item.nav); }}
>
<View style={styles.card}>
<Image style={styles.cardImage} source={{ uri: item.image }} />
<View style={styles.cardContent}>
<View>
<Text style={styles.title}>{item.title}</Text>
</View>
</View>
</View>
</TouchableOpacity>
);
}}
/>
<FooterComp />
</View>
);
}
}
The odd things is that after The FooterComp navigate to 'Home', the console.log() inside the render() method of HomeScreen component is not called. Shouldn't it be rendered after navigate to the component? I need to call the render() method to update screen.
Is not being called because the component hasn't been updated. I mean, with react-navigation the screens doesn't get unmounted, they just get blurred.
There is a component in react-navigation that will help you to solve this, just wrap your view with:
<View>
<NavigationEvents
onDidFocus={payload => console.log('Render Main. PID: ' + this.state.currentPropertyID)}
/>
{/*
Your view code
*/}
</View>

React Navigation: Is it possible to navigate to the same screen from different stackNavigators?

I'm coding an app that uses react-navigation. My app has a bottom TabNavigator in which each tab consists of a stackNavigator, like so:
Routes.js:
const FirstStack = createStackNavigator({
First: {
screen: FirstScreen,
navigationOptions: {
header: props => <AppToolbar />
}
}
});
const SecondStack = createStackNavigator({
Second: {
screen: SecondScreen,
navigationOptions: {
header: props => <AppToolbar />
}
}
});
const ThirdStack = createStackNavigator({
Third: {
screen: ThirdScreen,
navigationOptions: {
header: props => <AppToolbar />
}
}
});
const FourthStack = createStackNavigator({
Fourth: {
screen: FourthScreen,
navigationOptions: {
header: props => <AppToolbar />
}
}
});
const FifthStack = createStackNavigator({
Fifth: {
screen: FifthScreen,
navigationOptions: {
header: props => <AppToolbar />
}
}
});
export const AppStack = createBottomTabNavigator(
{
First: {
screen: FirstStack,
navigationOptions: {
title: "First",
tabBarLabel: "First",
tabBarIcon: ({ tintColor }) => (
<Icon name="ios-home" color={tintColor} size={24} />
)
}
},
Second: {
screen: SecondStack,
navigationOptions: {
title: "Second",
tabBarLabel: "Second",
tabBarIcon: ({ tintColor }) => (
<Icon name="ios-clock" color={tintColor} size={24} />
)
}
},
Third: {
screen: ThirdStack,
navigationOptions: {
title: "Third",
tabBarLabel: "Third",
tabBarIcon: ({ tintColor }) => (
<Icon name="ios-fitness" color={tintColor} size={24} />
)
}
},
Fourth: {
screen: FourthStack,
navigationOptions: {
title: "Fourth",
tabBarLabel: "Fourth",
tabBarIcon: ({ tintColor }) => (
<Icon
name="ios-cloud-download"
color={tintColor}
size={24}
/>
)
}
},
Fifth: {
screen: FifthStack,
navigationOptions: {
title: "Fifth",
tabBarLabel: "Fifth",
tabBarIcon: ({ tintColor }) => (
<Icon name="ios-person" color={tintColor} size={24} />
)
}
}
},
{
initialRouteName: "First",
order: ["First", "Second", "Third", "Fourth", "Fifth"],
tabBarOptions: {
activeTintColor: "white",
inactiveTintColor: "grey",
style: {
backgroundColor: "#121212",
borderTopColor: "#303030"
}
}
}
);
Each stackNavigator inside the tabs in the tabNavigator has its own header so that I can customize the header for each tab, but all headers have a button which should navigate to the profile screen (in this example its the contact icon).
AppToolbar.js:
const appToolbar = props => {
return (
<View style={styles.toolbar}>
<Text style={styles.toolbarTitle}>Title</Text>
<TouchableOpacity onPress={...}>
<Icon
name="ios-contact"
color="grey"
size={30}
style={{ padding: 0, margin: 0, marginRight: 10 }}
/>
</TouchableOpacity>
</View>
);
};
What I want to do is that by pressing the contact icon the app should navigate to the profile screen, what I don't know is if its possible to define like a global route thats accesible from everywhere, Or do I have to add the profile screen to all the stackNavigators so that it is accesible from every screen in every stack?
Thanks in advance!
Found the answer here https://stackoverflow.com/a/50701940/1276438
Use a stackNavigator with the profile stack and the tabNavigator as children, making the tabNavigator the default route.

Change app background color in React Native

I'm trying to change the color of the background in my react native app, from grey to white. I'm using react-navigation to make a TabNavigator after I render it. I tried to put this TabNavigator in a view and set backgroundColor but all screen became white. How can I solve this?
index.js
...
render() {
return (
<View style={{ backgroundColor: '#FFFFFF'}}>
<Tabs />
</View>
)
}
...
Tabs
...
const Tabs = TabNavigator(
{
Home: {
screen: HomeStack,
navigationOptions: {
title: 'Acasa',
},
},
...
Account: {
screen: AccountScreen,
navigationOptions: {
title: 'Contul meu',
},
},
},
{
tabBarComponent: props => <FooterNavigation {...props} />,
tabBarPosition: 'bottom',
initialRouteName: 'Home',
},
);
...
Home Screen
render() {
const {
data, refreshing, loading, error,
} = this.state;
return (
<ScrollView>
<Container>
{error && <Text>Error</Text>}
{loading && <ActivityIndicator animating size="large" />}
<List>
<FlatList
data={data}
renderItem={({ item }) => (
<ListItem onPress={() => this.props.navigation.navigate('Item', item)}>
<Item data={item} />
</ListItem>
)}
// ID from database as a key
keyExtractor={item => item.title}
ItemSeparatorComponent={this.renderSeparator}
ListFooterComponent={this.renderFooter}
ListHeaderComponent={this.renderHeader}
refreshing={refreshing}
onRefresh={this.handleRefresh}
onEndReached={this.handleLoadMore}
onEndReachedThreshold={0}
/>
</List>
</Container>
</ScrollView>
);
}
I've solved my problem, it was caused by StackNavigator. To solve it , just add some extra options
const HomeStack = StackNavigator(
{
Home: {
screen: HomeScreen,
},
Item: {
screen: ItemScreen,
navigationOptions: ({ navigation }) => ({
title: `${navigation.state.params.title}`,
}),
},
},
**
{
headerMode: 'screen',
cardStyle: { backgroundColor: '#FFFFFF' },
},
**
);
For React Navigation 5 and above
<Stack.Navigator
initialRouteName='dashboard'
screenOptions={{
headerStyle: { elevation: 0 },
cardStyle: { backgroundColor: '#fff' }
}}
>
<Stack.Screen name="Home" component={HomeStack} />
</Stack.Navigator>
For React Navigation 4 and earlier
const HomeStack = StackNavigator(
{
Home: {
screen: HomeScreen,
},
},
{
headerMode: 'screen',
cardStyle: { backgroundColor: '#fff' },
},
);
For React Navigation 6,
<Stack.Navigator screenOptions={{
contentStyle:{
backgroundColor:'#FFFFFF'
}
}} initialRouteName="Home">
Edit your View tag like this,
<View style={{flex: 1,backgroundColor: '#6ED4C8'}}></View>
The following will no longer work due to deprecation.
const HomeStack = StackNavigator(
{
Home: {
screen: HomeScreen,
},
Item: {
screen: ItemScreen,
navigationOptions: ({ navigation }) => ({
title: `${navigation.state.params.title}`,
}),
},
},
**
{
headerMode: 'screen',
cardStyle: { backgroundColor: '#FFFFFF' },
},
**
);
You now have to use defaultNavigationOptions (see below).
const HomeStack = StackNavigator(
{
Home: {
screen: HomeScreen,
},
Item: {
screen: ItemScreen,
navigationOptions: ({ navigation }) => ({
title: `${navigation.state.params.title}`,
}),
},
},
**
{
headerMode: 'screen',
defaultNavigationOptions: {
cardStyle: { backgroundColor: '#FFFFFF' },
},
},
**
);
The correct prop to be set is sceneContainerStyle:
<BottomTab.Navigator
...
sceneContainerStyle={{ backgroundColor: 'white' }}
>
...
</BottomTab.Navigator>
Set in view that's where you want to set background colour
view: {
backgroundColor: '#FFFFFF'
}

open pupop when select a tab react native

i'm new to react native and i want to have a tabNavigator that when 'Other' tab is selected a popup shows up . its my code but it don't recognize 'this' in 'ModalExample' class.
any help would be appreciated.
export const Tabs = TabNavigator({
Notifications: {
screen: Notifications,
navigationOptions: {
tabBarIcon: ({ tintColor }) => <Icon name="access-alarms" size={25} color={tintColor} />
},
},
Home: {
screen: Home,
navigationOptions: {
tabBarIcon: ({ tintColor }) => <Icon name="home" size={25} color={tintColor} />
},
},
Other: {
screen: ModalExample,
navigationOptions: {
tabBarIcon: ({ tintColor }) => <Icon name="more" size={25} color={tintColor} />
},
},
},
{
tabBarOptions: {
showIcon: true,
showLabel: false,
scrollEnabled: false
},
tabBarPosition: 'bottom',
});
and its other class:
export default class ModalExample extends Component {
constructor(props){
super(props);
this.popupDialog.show();
}
render() {
return (
<View>
<PopupDialog
ref={(popupDialog) => { this.popupDialog = popupDialog; }}
>
<View>
<Text>Hello</Text>
</View>
</PopupDialog>
</View>
);
}
}
I didn't understand how you are using <PopupDialog/>. But i think this link can help you with your requirement.