How To Add Logout Button in React native Drawer.Navigator? - react-native

I am creating Drawer in react native using Drawer.Navigator. But the issue is that how to move to Login screen if click on Logout button?
Any suggestion? my code is below. All remaining code is working fine. I only want to navigate the login screen by clicking on logout button.
import * as React from 'react';
import { Button, View, Text, TouchableOpacity } from 'react-native';
import {
createDrawerNavigator, DrawerContentScrollView,
DrawerItemList,
DrawerItem,
} from '#react-navigation/drawer';
import { NavigationContainer } from '#react-navigation/native';
import Resources from '../DrawerScreens/Resources';
import Themes from '../DrawerScreens/Themes';
import AboutUs from '../DrawerScreens/AboutUs';
import CustomSidebarMenu from './CustomSidebarMenu';
import Login from '../Validation/Login';
const Drawer = createDrawerNavigator();
export default function DrawerSetting({ navigation }) {
return (
<NavigationContainer independent={true} >
<Drawer.Navigator initialRouteName="Resources" drawerContent={(props) => <CustomSidebarMenu {...props} />}
>
<Drawer.Screen name="Resources" component={Resources}
options={{ drawerLabelStyle: { fontSize: 16, color: 'black', } }}
/>
<Drawer.Screen name="Themes" component={Themes}
options={{ drawerLabelStyle: { fontSize: 16, color: 'black', } }}
/>
<Drawer.Screen name="About Us" component={AboutUs}
options={{ drawerLabelStyle: { fontSize: 16, color: 'black', } }}
/>
</Drawer.Navigator>
</NavigationContainer>
);
}
I used to create Another component for creating the logout button,
import React from 'react';
import {
SafeAreaView,
View,
StyleSheet,
Image,
Text,
Linking,
TouchableOpacity,
BackHandler
} from 'react-native';
import {
DrawerContentScrollView,
DrawerItemList,
DrawerItem, Drawer,
} from '#react-navigation/drawer';
const CustomSidebarMenu = (props) => {
const BASE_PATH = '';
function logout(){
alert("Hello");
// props.navigation.navigate("Login");
// BackHandler.exitApp();
}
return (
<SafeAreaView style={{ flex: 1 }}>
{/*Top Large Image */}
<Image
source={require("../../assets/images/g_logo_blue.png")}
style={styles.sideMenuProfileIcon}
/>
<DrawerContentScrollView {...props}>
<DrawerItemList {...props} />
{/* { <DrawerItem
label="Visit Us"
onPress={() => {props.navigation.navigate('Login')}}
/> } */}
{/* <View style={styles.customItem}>
<Text
onPress={() => {
Linking.openURL('https://aboutreact.com/');
}}>
Rate Us
</Text>
<Image
source={{ uri: BASE_PATH + 'star_filled.png' }}
style={styles.iconStyle}
/>
</View> */}
<TouchableOpacity onPress={logout}>
<Text style={{ fontSize: 16, fontWeight: 'bold', textAlign: 'left', color: 'blue', marginLeft: 20, }}>
Logout
</Text>
</TouchableOpacity>
</DrawerContentScrollView>
<Text style={{ fontSize: 16, textAlign: 'center', color: 'blue' }}>
https://www.glocoach.com/
</Text>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
sideMenuProfileIcon: {
// resizeMode: 'cover',
width: "70%",
height: 70,
marginTop: 20,
marginBottom: -40,
marginLeft: -50,
// borderRadius: 100 / 2,
alignSelf: 'center',
},
iconStyle: {
width: 15,
height: 15,
marginHorizontal: 5,
},
customItem: {
padding: 16,
flexDirection: 'row',
alignItems: 'center',
},
});
export default CustomSidebarMenu;

Normally what I would do in this situation is have two navigators. One for the logged-out screens and one for the logged-in screens. Then I would bind this to a check-in JSX like:
<NavigationContainer>
{!isLoggedIn ? (<LoggedOutNavigator />) : (<LoggedInNavigator />)}
</NavigationContainer>
After that, all you have to do when the button is pressed is to change the isLoggedIn value. you can save isloggedIn in redux and then just dispatch an action to handle the change.
if you only have one navigator and really don't want to change it, then you can add a useEffect hook to navigate to the log in screen once isLoggedIn is set to false.

Related

React Native How to show an element above bottom tab navigator

I am trying to show a media player above the bottom tab navigator just like in spotify app.
It should stay there in same state across all the screens (bottom tabs).
Any suggestions or approaches to implement this in React native ?
You just need to calculate the height of Bottom Navbar and make a View with Position:'absolute' and to keep it above Bottom Navbar assign the height of Navbar to 'bottom' of this View.
<View>
<View
style={{
position: "absolute",
backgroundColor: "#4470AE",
bottom: 75,
flexDirection: "row",
width: "90%",
height: 60,
paddingVertical: "3%",
alignSelf: "center",
borderRadius: 12,
margin: "3%",
}}
></View>
<View
style={{
position: "absolute",
backgroundColor: "orange",
bottom: 0,
height: 75,
flexDirection: "row",
width: "100%",
justifyContent: "space-around",
paddingVertical: "3%",
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
}}
>
</View>
</View>
I would suggest to use an React.Context as you wanna show the same object (music control panel) on each screen with same state and not an replica on each screen.
For positioning I suggest using an absolute position. This works together with "react-navigation" because header and bottom areas are changed.
This means bottom:0 is no longer the screens bottom within a tab navigator it's right above the TabBar.
Here is an example:
import * as React from 'react';
import { Text, View } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import { MusicControlPanelContext, MusicControlPanelConsumer } from './components/MusicControlContext';
import {MusicControlPanel} from './components/MusicContorlPanel'
function HomeScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Home!</Text>
<MusicControlPanelConsumer/>
</View>
);
}
function SettingsScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Settings!</Text>
<MusicControlPanelConsumer/>
</View>
);
}
const Tab = createBottomTabNavigator();
export default function App() {
return (
<MusicControlPanelContext.Provider value={MusicControlPanel}>
<>
<NavigationContainer>
<Tab.Navigator
tabBarOptions={{
activeTintColor: '#000000',
inactiveTintColor: 'gray',
activeBackgroundColor: '#ff0000',
inactiveBackgroundColor: '#ff0000',
style: {
backgroundColor: '#ffffff',
},
}}>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
</NavigationContainer>
</>
</MusicControlPanelContext.Provider>
);
}
import * as React from 'react';
import { MusicControlPanelContext } from './MusicControlPanelContext';
import { View } from 'react-native';
function MusicControlPanelConsumer() {
return (
<MusicControlPanelContext.Consumer>
{(Component) => <Component/>}
</MusicControlPanelContext.Consumer>
);
}
export { MusicControlPanelConsumer };
import * as React from 'react';
import {MusicControlPanel} from '../MusicContorlPanel'
export const MusicControlPanelContext = React.createContext<React.FC>(MusicControlPanel);
import * as React from 'react';
import { View, Text, Pressable } from 'react-native';
export const MusicControlPanel: React.FC = () => {
const [startStop, setStartStop] = React.useState(false);
return (
<View
style={{
position: 'absolute',
width: '90%',
height: 100,
backgroundColor: '#ff00ff',
bottom: 10,
justifyContent: 'center',
alignItems: 'center'
}}>
<Pressable
onPress={() =>
setStartStop((val) => {
return !val;
})
}>
<Text>{startStop ? 'Start' : 'Stop'}</Text>
</Pressable>
</View>
);
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
I just solved this problem
import BottomTabBar
call tabBar props in tab navigator
wrap it with empty tag
import and insert your component above the BottomTabBar
import { BottomTabBar} from '#react-navigation/bottom-tabs';
import SmallVideoPlay from 'YOUR_PATH_OF_THE_COMPONENT';
<Tab.Navigator
tabBar={(props) => (
<>
< SmallVideoPlay />
<BottomTabBar {...props} />
</>
)}
>
<Tab.Screen name="HomeStack" component={Home}/>
....
</Tab.Navigator/>

Add openDrawer() to hamburger menu on a header in React Native -gives error undefined

This is my first React Native app. I want to get the header hamburger icon to open the side bar (drawer) but it only read it as undefined. So I read that it´s not possible to implement openDrawer() on a header as it is not read as a "screen". I have not been able to understand how to change my code to make it work. Help appreciated.
My code:
//Header
import React from "react";
import { StyleSheet, View, Text, TouchableOpacity } from "react-native";
import { Ionicons } from "#expo/vector-icons";
export const Header = ({ navigation, title }) => {
const openMenu = () => {
navigation.openDrawer();
};
return (
<View style={styles.header}>
<TouchableOpacity onPress={openMenu} style={styles.icons}>
<Ionicons name="md-menu" size={28} color="white" />
</TouchableOpacity>
<View style={styles.headerTitle}>
<Text style={styles.headerText}>{title}Title for header</Text>
</View>
</View>
);
};
//Navigation screen
import React from "react";
import { NavigationContainer } from "#react-navigation/native";
import { createDrawerNavigator } from "#react-navigation/drawer";
import { Notifications } from "./screens/Notifications";
import { Profile } from "./screens/Profile";
import { Header } from "./screens/Header";
const Drawer = createDrawerNavigator();
export const Navigation = () => {
return (
<>
<Header />
<NavigationContainer>
<Drawer.Navigator>
<Drawer.Screen name="Login" component={Login} />
<Drawer.Screen name="Profile" component={Profile} />
<Drawer.Screen name="Notifications" component={Notifications} />
</Drawer.Navigator>
</NavigationContainer>
</>
);
};
Firstly, create a folder called navigation where your App.js is located
Inside navigation folder create a file called AppNavigator.js
Then paste this inside AppNavigator.js
import React from "react";
import { createDrawerNavigator } from "#react-navigation/drawer";
import { Notifications } from "./screens/Notifications";
import { Profile } from "./screens/Profile";
const Drawer = createDrawerNavigator();
function AppNavigator() {
return (
<Drawer.Navigator screenOptions={{ headerShown: true }}>
<Drawer.Screen name="Profile" component={Profile} />
<Drawer.Screen name="Notifications" component={Notifications} />
</Drawer.Navigator>
);
}
export default AppNavigator;
In your App.js paste this code
import React from "react";
import { NavigationContainer } from "#react-navigation/native";
import AppNavigator from "./navigation/AppNavigator"
const App = () => {
return (
<NavigationContainer>
<AppNavigator />
</NavigationContainer>
);
};
export default App;
Your Login.js would look like this
import React, { useState } from "react";
import {
TouchableOpacity,
TextInput,
Text,
View,
StyleSheet,
} from "react-native";
export const Login = ({ navigation }) => {
const [userName, setUserName] = useState("");
const [password, setPassword] = useState("");
return (
<View style={styles.container}>
<Text style={styles.welcomeText}>Welcome to your App</Text>
<View style={styles.inputView}>
<TextInput
// required
style={styles.inputText}
placeholder="Email"
placeholderTextColor="#fff"
onChangeText={(value) => setUserName(value)}
defaultValue={userName}
/>
</View>
<View style={styles.inputView}>
<TextInput
// required
style={styles.inputText}
placeholder="Password"
placeholderTextColor="#fff"
onChangeText={(value) => setPassword(value)}
defaultValue={password}
/>
</View>
<TouchableOpacity>
<Text style={styles.forgot}>Forgot Password?</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.loginButton}
title="Login"
onPress={() => navigation.navigate("NavigationTest", { userName })}
>
<Text style={styles.loginText}>LOGIN</Text>
</TouchableOpacity>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "center",
justifyContent: "center",
},
welcomeText: {
color: "#fb5b5a",
fontWeight: "bold",
fontSize: 50,
textAlign: "center",
margin: 40,
},
inputView: {
width: "80%",
backgroundColor: "#465880",
borderRadius: 25,
height: 50,
marginBottom: 20,
justifyContent: "center",
padding: 20,
},
inputText: {
height: 50,
color: "white",
},
loginButton: {
width: "80%",
backgroundColor: "#fb5b5a",
borderRadius: 25,
height: 50,
alignItems: "center",
justifyContent: "center",
marginTop: 40,
marginBottom: 10,
},
forgot: {
color: "grey",
},
loginText: {
color: "#ffff",
fontWeight: "bold",
},
});

getting white space at top when using react-native navigation

I am using react navigation to navigate between different screens.
below is my code:
import React from 'react';
import { StyleSheet, Text, View, Button, TouchableOpacity } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import Home from "./screen/Home";
function Main({ navigation }) {
return (
<View style={styles.container}>
<View style={{flex: 0}}>
<Text>Welcome</Text>
</View>
<View style={{flex: 0}}>
<TouchableOpacity style={styles.btn} onPress={() => navigation.navigate('Home')}>
<Text>Goto Home</Text>
</TouchableOpacity>
</View>
</View>
);
}
const MainNavigator = createStackNavigator();
export default class App extends React.Component {
render() {
return (
<NavigationContainer>
<MainNavigator.Navigator >
<MainNavigator.Screen name="Main" component={Main} />
<MainNavigator.Screen name="Home" component={Home} />
</MainNavigator.Navigator>
</NavigationContainer>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1, backgroundColor: '#44210D', alignItems: 'center', justifyContent: 'center',
},
text: {
color: "black", borderWidth: 2, borderColor: "green"
},
btn: {
alignItems: "center", backgroundColor: "#DDDDDD", padding: 10,margin: 10
},
});
You can see in the image that there is a white space at the top. I want to know how can I change the color of that space.

How to fix react navigation displacing my component from top of screen?

I am working on a react native application and am trying to understand how to deal with react navigation as it affects my styling. Essentially when I navigate to a page, react navigation's top arrow with header is displacing my components (I'd like to move my black header bar up and use react navigation's arrow ideally):
I have react navigation set up in the following manner:
App.js
const ProfileNavigator = createStackNavigator({
//Profile: { screen: Profile},
QR: { screen: GenerateQR },
EditAccount: { screen: EditAccount }
});
const AppNavigator = createSwitchNavigator({
tabs: bottomTabNavigator,
profile: ProfileNavigator
})
const AppContainer = createAppContainer(AppNavigator);
I have a header component I put together for styling that I use on top of each page:
pageTemplate
import React, {Component} from 'react';
import {Text,View, StyleSheet} from 'react-native';
import { TouchableOpacity } from 'react-native-gesture-handler';
import { Ionicons } from '#expo/vector-icons';
class PageTemplate extends Component {
render() {
return (
<View
style={{
flexDirection: 'row',
height: 130,
alignSelf: 'stretch',
width: '100%'
}}>
<View style={{backgroundColor: 'black', alignSelf: 'stretch',width: '100%'}} />
<View style=
{{position:'absolute',
marginTop: '16%',
marginLeft: '3%',
display: 'flex',
flexDirection: 'row',
flex:1
}}>
<TouchableOpacity onPress={this.props.navigate}>
<Ionicons name="ios-arrow-dropleft" size={32} color="white" />
</TouchableOpacity>
</View>
<Text
style={{
position: 'absolute',
marginTop: '15%',
marginLeft: '12%',
color: 'white',
fontSize: 30}}
>
{this.props.title}
</Text>
</View>
);
}
}
export default PageTemplate;
I have a tab called profile which navigates through a list item to get to an account edits page:
Profile
import React from 'react';
import { StyleSheet, Text, View, Image, TouchableOpacity, TouchableHighlight } from 'react-native';
import { Ionicons } from '#expo/vector-icons';
import { List, ListItem } from 'react-native-elements'
import GenerateQR from './generateQR';
import PageTemplate from './smallComponents/pageTemplate';
import pic from '../assets/bigRate.png'
export default class Profile extends React.Component {
render() {
const { navigate } = this.props.navigation;
navigateBack=()=>{
navigate('Queue')
}
return(
<React.Fragment>
<PageTemplate title={'Profile Settings'} navigate={navigateBack} />
{/*<Image source={pic} />*/}
{/** Frst Section */}
<View style={{
//backgroundColor:'blue'
}}>
<Text style={styles.section}>Account Information</Text>
</View>
<TouchableOpacity
onPress={()=>{navigate('EditAccount')}}
style={{position: 'absolute',
marginTop:'32%',
flex:1,
flexDirection: 'row',
flexWrap: 'wrap'}}>
<View style={{
marginLeft:'5%',
flex:1,
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'flex-start',
//backgroundColor:'yellow',
alignItems: 'center',
//borderRadius:50,
//height:'60%'
}} >
<Ionicons style={{marginLeft:'20%'}} name="ios-person" size={72} />
</View>
<View style={{paddingTop:50,
marginRight:'40%',
flex:2,
flexDirection: 'row',
flexWrap: 'wrap',
//backgroundColor: 'red'
}}
>
<Text>Sylvester Stallone</Text>
<Text>+1 646-897-0098</Text>
<Text>SlyLone#gmail.com</Text>
</View>
</TouchableOpacity>
{/**add line section */}
</React.Fragment>
);
}
}
const styles = StyleSheet.create({
option : {
//position: 'absolute',
marginLeft:'7%',
alignSelf: 'stretch',
width: '100%',
height: '15%',
//flexWrap: 'wrap',
justifyContent:'space-between',
//padding:20
},
section : {
fontSize:20,
marginLeft:'5%'
}
})
/**
*
*
*
<View style={styles.option}>
<Ionicons name="ios-gift" size={32} />
<TouchableHighlight>
<Text>Rewards</Text>
</TouchableHighlight>
</View>
*
*/
Ideally it be nice to drop the arrow icon and move the header up keeping react-navigations arrow.
If you want to get rid of the arrows, you can create your own headers.
Example
class LogoTitle extends React.Component {
render() {
return (
<Image
source={require('#expo/snack-static/react-native-logo.png')}
style={{ width: 30, height: 30, alignSelf:"center" }}
/>
);
}
}
class HomeScreen extends React.Component {
static navigationOptions = {
// headerTitle instead of title
headerTitle: () => <LogoTitle />,
headerLeft: () => (
<Button
onPress={() => alert('This is a button!')}
title="back"
color="#fff"
/>
),
};

navigate.dispatch(DrawerActions.closeDrawer()) not working in React Native

On click of a cross button the drawer should be closed, that is the
thing I am trying. I have passed down the props inside component but
giving error that navigate.dispatch(DrawerActions.closeDrawer()) is
undefined.
I am providing My code
SideMenu.js which the layout of drawer menu. From here I am passing
props to drawerheader.
import React, {Component} from 'react';
import { View, StyleSheet} from 'react-native';
import DrawerHeader from './DrawerHeader';
import DrawerMenu from './DrawerMenu';
import { StackNavigator } from 'react-navigation';
class SideMenuLayout extends Component {
state = {
menuNames:[{
id:'0',
name:'My Profile',
link:''
},{
id:'1',
name:'Place Order',
link:''
},{
id:'2',
name:'Order History',
link:'OrderHistory'
},{
id:'3',
name:'Payment',
link:''
},{
id:'4',
name:'Recharge',
link:''
},{
id:'5',
name:'Help',
link:''
},{
id:'6',
name:'Logout',
link:''
}]
}
render () {
return (
<View style={styles.container} >
<DrawerHeader navigation={this.props.navigation}/>
<DrawerMenu
navigation={this.props.navigation}
menuItems={this.state}
style={{ marginTop: 106/3}}
/>
</View>
);
}
}
export default SideMenuLayout;
const styles = StyleSheet.create({
container:{
flex:1,
backgroundColor: "#ffffff",
}
});
Drawer Header code goes here. Here I am trying to close the navigation drawer.
import React, {Component} from 'react';
import {Text, View, StyleSheet,Image,TouchableOpacity} from 'react-native';
import { FontAwesome } from '#expo/vector-icons';
import { DrawerActions, StackNavigator } from 'react-navigation';
const DrawerHeader = (props)=> {
const { navigate } = props.navigation;
return (
<View style={{backgroundColor: '#d61822',width:DRAWER_CONTAINER_WIDTH/3,height:DRAWER_CONTAINER_HEIGHT/3 }}>
<View style={styles.titleContainer}>
<View style={{ marginLeft:20, backgroundColor:'#d61822',height:40 }}>
<Text style={{fontSize:28,fontStyle:'italic',color:'#ffff',fontWeight:'bold'}}>
Prabhuji Online
</Text>
</View>
<View style={{ marginLeft:35,backgroundColor:'#d61822',width: 50, height: 40,paddingRight:10,alignItems:'center',justifyContent:'center' }}>
<TouchableOpacity onPress={()=>navigate.dispatch(DrawerActions.closeDrawer())}>
<Text style={{fontSize:20,color:'#ffff',}}>
<FontAwesome
style={{ alignSelf: 'flex-end'}}
name="times"
size={18}
color="#ffffff"
/>
</Text>
</TouchableOpacity>
</View>
</View>
<View style={styles.fakeContainer}>
</View>
<View style={{
position:'absolute',
top: 170/3,
marginLeft:20,
width:220/3,
height:220/3,
backgroundColor:'#fffcf9',
borderRadius:(220/3)/2,
justifyContent:'center',
alignContent:'center',
alignItems:'center',
shadowColor: "#000",
shadowOffset: {
width: 0,
height: 5,
},
shadowOpacity: 0.25,
shadowRadius: 6.27,
elevation: 7,
}}>
<Image
tintColor='red'
style={{
width: 111/3,
height: 111/3,
}}
source={require('../../../assets/place_order.png')}/>
</View>
</View>
);
}
export default DrawerHeader;
const styles = StyleSheet.create({
titleContainer:{
backgroundColor: '#d61822',
flexDirection: 'row',
height:TITLE_CONTAINER_HEIGHT/3,
marginTop: 50/3,
},
fakeContainer:{
position:'relative',
height:FAKE_CONTAINER_HEIGHT/3,
backgroundColor: '#ffffff',
//backgroundColor: 'yellow',
}
});
Can any one please tell me what is going wrong here?
I have also tried navigate.closeDrawer(). But same error is giving.
Instead of using the navigate call, you need to dispatch the action like this: this.props.navigation.dispatch(*your action here*), as described in the docs: https://reactnavigation.org/docs/en/navigation-prop.html#dispatch-send-an-action-to-the-router