React Native Firebase App: Change Stack.Screen onAuthStateChange - ios

I have a React-Native (sdk 46.0) Firebase app. I want to make it so that when the user is signed in, he moves from the LoginScreen to to the HomeScreen. Code is shown below.
// screens/LoginScreen.js >>
...
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const navigation = useNavigation();
const handleLogin = () => {
auth
.signInWithEmailAndPassword(email, password)
.then((userCredentials) => {
const user = userCredentials.user;
console.log("Logged in with:", user.email);
})
.catch((error) => alert(error.message));
};
...
<View style={styles.inputContainer}>
<Input
style={styles.input}
blurOnSubmit
autoCorrect={false}
placeholder="jdoe#ernestkoliqi.com"
placeholderTextColor="#666"
value={email}
onChangeText={(text) => setEmail(text)}
selectTextOnFocus
keyboardType="email-address"
/>
<Input
style={styles.input}
blurOnSubmit
autoCorrect={false}
placeholder="Password"
placeholderTextColor="#666"
bool={true}
value={password}
onChangeText={(text) => setPassword(text)}
selectTextOnFocus
/>
</View>
<View style={styles.buttonContainerModal}>
<TouchableOpacity onPress={handleLogin}>
<View style={styles.ctaBtnModal}>
<Text style={styles.loginBtn}>Log In</Text>
</View>
</TouchableOpacity>
...
// App.js
...
function Home() {
return <HomeScreen />;
}
function News() {
return <NewsScreen />;
}
function Calendar() {
return <CalendarScreen />;
}
function Login() {
return <LoginScreen />;
}
function Feed() {
return (
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color, size }) => {
let iconName;
if (route.name === "Home") {
iconName = focused ? "home" : "home-outline";
} else if (route.name === "News") {
iconName = focused ? "newspaper" : "newspaper-outline";
} else if (route.name === "Calendar") {
iconName = focused ? "calendar" : "calendar-outline";
}
return <Ionicons name={iconName} size={size} color={color} />;
},
activeTintColor: Colors.primary,
inactiveTintColor: "gray",
showLabel: true,
showIcon: true,
style: {
paddingBottom: 4.25,
paddingTop: 4.25,
},
})}
>
<Tab.Screen
name="Home"
component={Home}
options={{ headerShown: false }}
/>
<Tab.Screen
name="Calendar"
component={Calendar}
options={{ headerShown: false }}
/>
<Tab.Screen
name="News"
component={News}
options={{ headerShown: false }}
/>
</Tab.Navigator>
);
}
const Tab = createBottomTabNavigator();
const Stack = createNativeStackNavigator();
export default function App() {
return (
<SafeAreaView style={styles.screen}>
<StatusBar barStyle="light-content" translucent={true} />
<NavigationContainer theme={appTheme}>
<Stack.Navigator>
<Stack.Screen component={Login} options={{ headerShown: false }} name="Login" />
<Stack.Screen component={Feed} name="Feed" />
</Stack.Navigator>
<LoginScreen />
</NavigationContainer>
</SafeAreaView>
);
}
...
The code above shows the file structure and the code contained in the files relative to the topic. How can I manage to change Stack.Screen when user==True?

You need a state that can be changed in the Login component. You could use a Context for this purpose.
export const AppContext = React.createContext({});
export default function App() {
const [isSignedIn, setIsSignedIn] = React.useState(false);
const contextValue = React.useMemo(() => ({
isSignedIn,
setIsSignedIn
}), [isSignedIn])
return (
<SafeAreaView style={styles.screen}>
<StatusBar barStyle="light-content" translucent={true} />
<AppContext.Provider value={contextValue}>
<NavigationContainer theme={appTheme}>
<Stack.Navigator>
{
!isSignedIn ? (
<Stack.Screen component={Login} options={{ headerShown: false }} name="Login" />
) : (
<Stack.Screen component={Feed} name="Feed" />
)
</Stack.Navigator>
</NavigationContainer>
</AppContext.Provider>
</SafeAreaView>
);
}
The Login screen can access the context and change it if the user logs in successfully.
const Login = (props) => {
const { setIsSignedIn } = useContext(AppContext);
const handleLogin = () => {
auth
.signInWithEmailAndPassword(email, password)
.then((userCredentials) => {
const user = userCredentials.user;
console.log("Logged in with:", user.email);
// success ?
setIsSignedIn(true);
})
.catch((error) => alert(error.message));
};
...
}

Related

in DropDownPicker onChangeValue is not triggering

I'm using DropDownPicker in react native but onChangeValue event is not triggering.
I have used onChange and onChangeItem already. Trying to follow this https://hossein-zare.github.io/react-native-dropdown-picker-website/docs/usage#onchangevalue but its not working. Please help me out.
Below is the code:
import React, { useEffect, useState } from 'react';
import {View, Text, Button, TextInput, FlatList, ActivityIndicator, StyleSheet, Image} from 'react-native';
import filter from 'lodash.filter';
import DropDownPicker from 'react-native-dropdown-picker';
const CarList = () => {
const [isLoading, setIsLoading] = useState(false);
const [data, setData] = useState([]);
const [error, setError] = useState(null);
const [query, setQuery] = useState('');
const [fullData, setFullData] = useState([]);
const [selected, setSelected] = useState("");
const [open, setOpen] = useState(false);
const [childOpen, setChildOpen] = useState(false);
const [filterOption, setfilteroption] = useState([
{label: 'Color', value: 'Color'},
{label: 'Model', value: 'Model'},
{label: 'Year', value: 'Year'}
]);
const [value, setValue] = useState(null);
const [childvalue, setChildValue] = useState([]);
useEffect(() => {
setIsLoading(true);
fetch(`https://myfakeapi.com/api/cars/?seed=1&page=1&results=20`)
.then(response => response.json())
.then(response => {
setData(response.cars);
setFullData(response.cars);
setIsLoading(false);
})
.catch(err => {
setIsLoading(false);
setError(err);
});
}, []);
if (isLoading) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<ActivityIndicator size="large" color="#5500dc" />
</View>
);
}
if (error) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text style={{ fontSize: 18}}>
Error fetching data... Check your network connection!
</Text>
</View>
);
}
const handleSearch = text => {
const formattedQuery = text.toLowerCase();
const filteredData = filter(fullData, user => {
return contains(user, formattedQuery);
});
setData(filteredData);
setQuery(text);
};
const contains = ({ car, car_model,car_color }, query) => {
if (car.toLowerCase().includes(query) || car_model.toLowerCase().includes(query) || car_color.toLowerCase().includes(query)) {
return true;
}
return false;
};
const color = [...new Set(data.map((item) => item.car_color))];
const model = [...new Set(data.map((item) => item.car_model))];
const year = [...new Set(data.map((item) => item.car_model_year))];
//this is not triggering
const changeSelectOptionHandler = (value) => {
console.log("hi")
setSelected(value);
};
if (selected === "Color") {
setChildValue(color)
} else if (selected === "Model") {
setChildValue(model)
} else if (selected === "Year") {
setChildValue(year)
}
function renderHeader() {
return (
<View
style={{
backgroundColor: '#fff',
padding: 10,
marginVertical: 10,
borderRadius: 20
}}
>
<TextInput
autoCapitalize="none"
autoCorrect={false}
clearButtonMode="always"
value={query}
onChangeText={queryText => handleSearch(queryText)}
placeholder="Search"
style={{ backgroundColor: '#fff', paddingHorizontal: 20 }}
/>
<DropDownPicker onChangeItem={changeSelectOptionHandler}
open={open}
value={value}
items={filterOption}
setOpen={setOpen}
setValue={setValue}
setItems={setfilteroption}
dropDownDirection="TOP"
style={{
padding: 5,
margin: 5,
width: 200,
flexDirection: 'row'
// borderRadius: 20
}}
/>
<DropDownPicker
open={childOpen}
items={childvalue}
setOpen={setChildOpen}
setItems={setChildValue}
dropDownDirection="TOP"
/>
</View>
);
}
return (
<View style={styles.container}>
<Text style={styles.text}>Favorite Contacts</Text>
<FlatList
keyboardShouldPersistTaps="always"
ListHeaderComponent={renderHeader}
data={data}
keyExtractor={({ id }) => id}
renderItem={({ item }) => (
<View style={styles.listItem}>
<Image
source={{
uri: 'https://picsum.photos/200',
}}
style={styles.coverImage}
/>
<View style={styles.metaInfo}>
<Text style={styles.title}>{`${item.car} ${
item.car_model
}`}</Text>
<Text>Color: {`${item.car_color}`}</Text>
<Text>Price: {`${item.price}`}</Text>
</View>
</View>
)}
/>
</View>
);
}
I needed to use onSelectItem instead of onChangeValue
The latest version of dropdownpicker
OnChangeValue is not supported.
use this :
onSelectItem={(item) => {console.log(item.value)}}
Note: I am using "react-native-dropdown-picker": "^5.4.2",

How do I render different Screens of an iOS app with React Native and Firebase/Firestore based on a user's role (provider or customer) after login?

I'm creating an app with React Native and Firebase/Firestore, and I need the app to show different screens based on the role of the user's account (Provider or Customer). After a user logs into their account, the app should check their role data from Firebase and render a different screen based on it. So the app will first evaluate the condition to see if they're logged in. Then it will evaluate the condition to see if they're a Provider or Customer and then render the proper screen (either the Login, ProviderHomeScreen, or CustomerHomeScreen).
I've tried to use the condition:
const user = firebase.auth().currentUser;
var role;
if (user != null) {
role = user.role;
console.log(role);
}
if (isLoggedIn) {
if (user.role === 'provider') {
return (
<NavigationContainer>
<ProviderStack.Navigator>
<Stack.Navigator>
<Stack.Screen
name={'Provider Home'}
component={ProviderHomeTabNavigator}
options={{
headerShown: false,
}}
/>
</Stack.Navigator>
</ProviderStack.Navigator>
</NavigationContainer>
);
} else {
return (
<NavigationContainer>
<CustomerStack.Navigator>
<Stack.Screen
name={'Customer Home'}
component={CustomerHomeTabNavigator}
options={{
headerShown: false,
}}
/>
<Stack.Screen
name={'Search'}
component={SearchScreen}
options={{
title: 'Search Availa Providers',
}}
/>
</CustomerStack.Navigator>
</NavigationContainer>
);
}
}
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Login" component={LoginScreen} />
<Stack.Screen
name="Customer Sign-up"
component={CustomerRegistrationScreen}
/>
<Stack.Screen
name="Provider Sign-up"
component={ProviderRegistrationScreen}
/>
</Stack.Navigator>
</NavigationContainer>
but when I console.log the user.role, it says undefined in the console, and the app just renders the CustomerHomeScreen with the CustomerHomeTabNavigator.
Please help me successfully access the role data of the currently signed-in user from Firestore and create conditions to render the proper screens for the proper role of the users.
Right now, this is what my code looks like for App.js:
import 'react-native-gesture-handler';
import React, {useEffect, useState} from 'react';
import {View, Text} from 'react-native';
import {NavigationContainer} from '#react-navigation/native';
import {createNativeStackNavigator} from '#react-navigation/native-stack';
import {createStackNavigator} from '#react-navigation/stack';
import {createBottomTabNavigator} from '#react-navigation/bottom-tabs';
import CustomerHomeScreen from '../Availa/src/Customer/screens/Home/index';
import Fontisto from 'react-native-vector-icons/Fontisto';
import FontAwesome from 'react-native-vector-icons/FontAwesome';
import FontAwesome5 from 'react-native-vector-icons/FontAwesome5';
import Feather from 'react-native-vector-icons/Feather';
import AntDesign from 'react-native-vector-icons/AntDesign';
import Ionicons from 'react-native-vector-icons/Ionicons';
import {firebase} from '../Availa/src/firebase/config';
import 'firebase/auth';
import firestore from '#react-native-firebase/firestore';
import 'firebase/firestore';
import 'react-native-gesture-handler';
Fontisto.loadFont();
FontAwesome.loadFont();
Feather.loadFont();
AntDesign.loadFont();
Ionicons.loadFont();
import SearchScreen from '../Availa/src/Customer/screens/SearchScreen/index';
import ProfileScreen from '../Availa/src/Customer/screens/ProfileScreen/index';
import {
LoginScreen,
CustomerRegistrationScreen,
ProviderRegistrationScreen,
} from './src/screens';
import 'firebase/auth';
import {decode, encode} from 'base-64';
if (!global.btoa) {
global.btoa = encode;
}
if (!global.atob) {
global.atob = decode;
}
const ProviderStack = createNativeStackNavigator();
const ProviderStackScreen = () => {
return (
<ProviderStack.Navigator>
<Stack.Navigator>
<Stack.Screen
name={'Home'}
component={ProviderHomeTabNavigator}
options={{
headerShown: false,
}}
/>
</Stack.Navigator>
</ProviderStack.Navigator>
);
};
const ProviderTab = createBottomTabNavigator();
const ProviderHomeTabNavigator = () => {
return (
<Tab.Navigator
tabBarOptions={{
activeTintColor: '#007FFF',
}}>
<Tab.Screen
name={'Provider'}
component={ProviderHomeScreen}
options={{
tabBarIcon: ({color}) => (
<Fontisto name="home" size={25} color={color} />
),
}}
/>
<Tab.Screen
name={'My List'}
component={ProviderHomeScreen}
options={{
tabBarIcon: ({color}) => (
<FontAwesome name="heart-o" size={25} color={color} />
),
}}
/>
<Tab.Screen
name={'Appointments'}
component={ProviderHomeScreen}
options={{
tabBarIcon: ({color}) => (
<AntDesign name="calendar" size={25} color={color} />
),
}}
/>
<Tab.Screen
name={'Messages'}
component={ProviderHomeScreen}
options={{
tabBarIcon: ({color}) => (
<Feather name="message-square" size={25} color={color} />
),
}}
/>
<Tab.Screen
name={'Profile'}
component={ProfileScreen}
options={{
tabBarIcon: ({color}) => (
<Ionicons name="person-circle-outline" size={25} color={color} />
),
}}
/>
</Tab.Navigator>
);
};
const CustomerStack = createNativeStackNavigator();
const CustomerStackScreen = () => {
return (
<CustomerStack.Navigator>
<Stack.Navigator>
<Stack.Screen
name={'Home'}
component={CustomerHomeTabNavigator}
options={{
headerShown: false,
}}
/>
</Stack.Navigator>
</CustomerStack.Navigator>
);
};
const Tab = createBottomTabNavigator();
const CustomerHomeTabNavigator = () => {
return (
<Tab.Navigator
tabBarOptions={{
activeTintColor: '#1cd478',
}}>
<Tab.Screen
name={'Home'}
component={CustomerHomeScreen}
options={{
tabBarIcon: ({color}) => (
<Fontisto name="home" size={25} color={color} />
),
}}
/>
<Tab.Screen
name={'My List'}
component={CustomerHomeScreen}
options={{
tabBarIcon: ({color}) => (
<FontAwesome name="heart-o" size={25} color={color} />
),
}}
/>
<Tab.Screen
name={'Appointments'}
component={CustomerHomeScreen}
options={{
tabBarIcon: ({color}) => (
<AntDesign name="calendar" size={25} color={color} />
),
}}
/>
<Tab.Screen
name={'Messages'}
component={CustomerHomeScreen}
options={{
tabBarIcon: ({color}) => (
<Feather name="message-square" size={25} color={color} />
),
}}
/>
<Tab.Screen
name={'Profile'}
component={ProfileScreen}
options={{
tabBarIcon: ({color}) => (
<Ionicons name="person-circle-outline" size={25} color={color} />
),
}}
/>
</Tab.Navigator>
);
};
const chooseScreen = user => {
if (user?.role === 'provider') {
ProviderStackScreen();
}
CustomerStackScreen();
};
const Stack = createStackNavigator();
export default function App() {
const [isLoggedIn, setIsLoggedIn] = useState(false);
const [loading, setLoading] = useState(true);
const firestore = firebase.firestore;
const auth = firebase.auth;
const user = firebase.auth().currentUser;
// //to check if Firebase has been initialized
if (!firebase.apps.length) {
firebase.initializeApp(firebaseConfig);
} else {
firebase.app();
}
firebase.auth().onAuthStateChanged(user => {
if (user != null) {
setIsLoggedIn(true);
} else {
setIsLoggedIn(false);
}
});
var role;
if (user != null) {
role = user.role;
console.log(role);
}
if (isLoggedIn) {
if (user.role === 'provider') {
return (
<NavigationContainer>
<ProviderStack.Navigator>
<Stack.Navigator>
<Stack.Screen
name={'Provider Home'}
component={ProviderHomeTabNavigator}
options={{
headerShown: false,
}}
/>
</Stack.Navigator>
</ProviderStack.Navigator>
</NavigationContainer>
);
} else {
return (
<NavigationContainer>
<CustomerStack.Navigator>
<Stack.Screen
name={'Customer Home'}
component={CustomerHomeTabNavigator}
options={{
headerShown: false,
}}
/>
<Stack.Screen
name={'Search'}
component={SearchScreen}
options={{
title: 'Search Availa Providers',
}}
/>
</CustomerStack.Navigator>
</NavigationContainer>
);
}
}
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Login" component={LoginScreen} />
<Stack.Screen
name="Customer Sign-up"
component={CustomerRegistrationScreen}
/>
<Stack.Screen
name="Provider Sign-up"
component={ProviderRegistrationScreen}
/>
</Stack.Navigator>
</NavigationContainer>
);
Also, this is what my LoginScreen.js looks like:
import React, {useState} from 'react';
import {Image, Text, TextInput, TouchableOpacity, View} from 'react-native';
import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view';
import styles from './styles';
import {firebase} from '../../firebase/config';
export default function LoginScreen({navigation}) {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const onLoginPress = () => {
firebase
.auth()
.signInWithEmailAndPassword(email, password)
.then(response => {
const uid = response.user.uid;
const usersRef = firebase.firestore().collection('users');
usersRef
.doc(uid)
.get()
.then(firestoreDocument => {
if (!firestoreDocument.exists) {
alert('User does not exist');
return;
}
const user = firestoreDocument.data();
if (user.role === 'provider') {
navigation.navigate('Provider Home', {user});
} else {
navigation.navigate('Customer Home', {user});
}
})
.catch(error => {
alert(error);
});
})
.catch(error => {
alert(error);
});
};
return (
<View style={styles.container}>
<KeyboardAwareScrollView
style={{flex: 1, width: '100%'}}
keyboardShouldPersistTaps="always">
<Image
style={styles.logo}
source={require('../../../assets/availalogo.png')}
/>
<TextInput
style={styles.input}
placeholder="Email"
placeholderTextColor="#aaaaaa"
onChangeText={text => setEmail(text)}
value={email}
underlineColorAndroid="transparent"
autoCapitalize="none"
/>
<TextInput
style={styles.input}
placeholderTextColor="#aaaaaa"
secureTextEntry
placeholder="Password"
onChangeText={text => setPassword(text)}
value={password}
underlineColorAndroid="transparent"
autoCapitalize="none"
/>
<TouchableOpacity style={styles.button} onPress={() => onLoginPress()}>
<Text style={styles.buttonTitle}>Log in</Text>
</TouchableOpacity>
<Text style={styles.footerText}>Don't have an account?</Text>
<TouchableOpacity
style={{
backgroundColor: '#ED2939', //#118C4F?
marginLeft: 30,
marginRight: 30,
marginTop: 20,
height: 48,
borderRadius: 5,
alignItems: 'center',
justifyContent: 'center',
}}
onPress={() => navigation.navigate('Provider Sign-up')}>
<Text style={{color: 'white', fontSize: 16, fontWeight: 'bold'}}>
Sign Up as Availa Provider
</Text>
</TouchableOpacity>
<TouchableOpacity
style={{
backgroundColor: '#007FFF',
marginLeft: 30,
marginRight: 30,
marginTop: 20,
height: 48,
borderRadius: 5,
alignItems: 'center',
justifyContent: 'center',
}}
onPress={() => navigation.navigate('Customer Sign-up')}>
<Text style={{color: 'white', fontSize: 16, fontWeight: 'bold'}}>
Sign Up as Customer
</Text>
</TouchableOpacity>
</KeyboardAwareScrollView>
</View>
);
}
Are you adding the role in custom claims?
if so you need to get the the claims from getIdTokenResult
firebase.auth().currentUser.getIdTokenResult()
.then((idTokenResult) => {
const role = idTokenResult.claims.role;
})
.catch((error) => {
console.log(error);
});
Also I personally keep the firebase initialization outside of the component and
firebase.auth().onAuthStateChanged(user => {
if (user != null) {
setIsLoggedIn(true);
} else {
setIsLoggedIn(false);
}
});
inside useEffect, so instead of setIsLoggedIn would do setUser and in your case after you get the role you can set it in a different state.

How to redirect or load a view depending upon condition in react-native-iap purchase

What I want to achieve is to redirect or show a view upon successful purchase. Purchase is successful but the state variable is not updating inside validateReceiptIos handler.
I checked the validation of the receipt but after that not even able to redirect to another page or load a view on the condition. I am attaching a code snippet below.
const productIds = ['xxx_xx_xx'];
const InAppPurchase = ({ navigation }) => {
const [products, setProducts] = useState([]);
const [purchased, setPurchased] = useState(false);
const [email, setEmail] = useState({
emailText: '',
emailValidity: false,
emailErrorText: null,
});
const [name, setName] = useState({
nameText: '',
nameValidity: false,
nameErrorText: null,
});
const validateUserName = (text) => {
if (text.length < 1) {
setName({ nameText: text, nameValidity: false, nameErrorText: 'Name cannot be empty' });
}
else { setName({ nameText: text, nameValidity: true, nameErrorText: '' }); }
};
const validateEmail = (text) => {
let reg = /^\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{2,3})+$/;
if (reg.test(text) === false && text.length > 0) {
setEmail({ emailText: text, emailValidity: false, emailErrorText: 'Invalid email' });
} else if (text.length < 1) {
setEmail({ emailText: text, emailValidity: false, emailErrorText: 'Email cannot be empty' });
}
else { setEmail({ emailText: text, emailValidity: true, emailErrorText: '' }); }
};
const validate = async (receipt, purchase) => {
const receiptBody = {
"receipt-data": receipt,
"password": "xxxxxxxxxxxxxxxxxxxxxx"
}
const result = await IAP.validateReceiptIos(receiptBody, true).catch(() => {
}).then((receipt) => {
try {
const renewalHistory = receipt.latest_receipt_info;
const expiration = renewalHistory[renewalHistory.length - 1].expires_date_ms;
// const expiration = renewalHistory[0].expires_date_ms;
let expired = Date.now() > expiration;
if (!expired) {
IAP.finishTransaction(purchase);
setPurchased(true); //***Not updating the state variable***
//navigation.navigate('Success') //***Not even navigate to another page***
} else {
Alert.alert("Purchase expired", "Your subscription has been expired, please resubscribe to continue using the app")
}
} catch (error) {
console.log(error)
}
})
}
useEffect(() => {
IAP.getProducts(productIds).then(res => {
setProducts(res);
})
const purchaseUpdateSubscription = IAP.purchaseUpdatedListener(purchase => {
const receipt = purchase.transactionReceipt;
if (receipt) {
validate(receipt, purchase)
}
})
return () => {
purchaseUpdateSubscription.remove();
}
}, []);
if (purchased) {
return (
<SafeAreaView style={styles.container}>
<View style={styles.containerInner}>
<View style={{ flex: 1, flexDirection: "column" }}>
<View style={styles.logoSuccessSection}>
<Image style={styles.successLogo} source={require('../images/success.png')} />
</View>
<View style={{ flex: 1 }}>
<TouchableOpacity style={styles.button} onPress={() => navigation.navigate('Login')}>
<Text style={styles.signText}>CONTINUE</Text>
</TouchableOpacity>
</View>
</View>
</View>
</SafeAreaView>
)
} else {
return (
<SafeAreaView style={styles.container}>
<View style={styles.containerInner}>
<View style={styles.logoSection}>
<Image style={styles.logo} source={require('../images/logo.jpg')} />
</View>
<View style={styles.headerContainer}>
<Text style={styles.headerText}>PREMIUM ACCESS</Text>
</View>
<View style={styles.featureContainer}>
<ScrollView style={{ flexDirection: 'column', paddingVertical: 20 }}>
<TextInput blurOnSubmit={true} autoCapitalize='none' placeholderTextColor="#736c6c"
style={{ height: 40, borderColor: '#d6d8e1', borderWidth: 1, paddingHorizontal: 10 }} placeholder="Email" onChangeText={(text) => validateEmail(text)} onSubmitEditing={(event) => setEmail({ emailText: event.nativeEvent.text })}
/>
{email.emailValidity === false ? <Text style={styles.errorTextStyle}>{email.emailErrorText}</Text> : null}
<TextInput blurOnSubmit={true} autoCapitalize='none' placeholderTextColor="#736c6c"
style={{ height: 40, borderColor: '#d6d8e1', borderWidth: 1, paddingHorizontal: 10, marginVertical: 5 }} placeholder="Name" onChangeText={(text) => validateUserName(text)} onSubmitEditing={(event) => setName({ nameText: event.nativeEvent.text })}
/>
{name.nameValidity === false ? <Text style={styles.errorTextStyle}>{name.nameErrorText}</Text> : null}
</ScrollView>
</View>
<View>
{products.map((product, i) =>
<TouchableOpacity key={i} style={styles.button} onPress={() => {
if (email.emailValidity === false || name.nameValidity === false) {
Alert.alert(
"Email & Name fields cannot be empty.",
"",
[
{ text: "OK", onPress: () => console.log("OK Pressed") }
],
{ cancelable: false }
);
} else {
IAP.requestSubscription(product.productId);
}
}}>
<Text style={styles.signText}>SUBSCRIBE - $9.99/Month</Text>
</TouchableOpacity>
)}
</View>
</View>
</SafeAreaView>
)
}
}

React Native + Firebase - How to navigate to login screen after log-out?

I want to set up authentication in my app, so I'm using firebase (I'm new to Firebase and authentication in react native in general).
When I open the app, for some reason it is already logged in, and displays AppStack, instead of AuthStack which is supposed to be the LoginScreen. When I run this code inside my AppStack on a component:
onPress={() => {firebase.auth().signOut().then(function() {
console.log('Signed Out');
}, function(error) {
console.error('Sign Out Error', error);
});}}>
it successfully logs 'Signed Out', but it doesn't switch screens.
I know the problem lies in my state variable, isLoggedIn, but I don't know how to fix it.
So this is my app.js, would really appreciate any feedback on how to make this work.
import * as React from "react";
...
import * as firebase from 'firebase';
var firebaseConfig = {
...
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
const Stack = createStackNavigator();
const Tab = createBottomTabNavigator();
function AuthStack() {
return(
<Stack.Navigator>
<Stack.Screen name="Login" component={LoginScreen} options={{ headerShown: false }} />
</Stack.Navigator>)}
function AppStack() {
return (
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color, size }) => {
if (route.name === 'Order') {
return (
<IconWithBadge
name={focused ? 'ios-book' : 'ios-book'}
size={size}
color={color}
/>
);
} else if (route.name === 'Map') {
return (
<Ionicons
name={focused ? 'md-globe' : 'md-globe'}
size={size}
color={color}
/>
);
} else if (route.name === 'Profile') {
return (
<Ionicons
name={focused ? 'md-contact' : 'md-contact'}
size={size}
color={color}
/>
)
} else if (route.name === 'Notifications') {
return (
<Ionicons
name={focused ? 'ios-notifications-outline' : 'ios-notifications-outline'}
size={size}
color={color}
/>
)
}
},
})}
tabBarOptions={{
activeTintColor: 'orange',
inactiveTintColor: 'gray',
}}>
<Tab.Screen name="Order" component={OrderScreen} />
<Tab.Screen name="Map" component={MapScreen} />
<Tab.Screen name="Profile" component={ProfileScreen} />
<Tab.Screen name="Notifications" component={Notifications} />
</Tab.Navigator>)}
export default class App extends React.Component {
state = {
isLoggedIn: firebase.auth().onAuthStateChanged(user => { return user}),
}
render() {
return(
<NavigationContainer>
{ this.state.isLoggedIn ? (<AppStack />) : (<AuthStack />) }
</NavigationContainer>
)}
}
function Notifications() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Notifications</Text>
</View>
);
}
One thing you can do is :
export default class App extends React.Component {
state = {
isLoggedIn: false,
}
componentDidMount(){
firebase.auth().onAuthStateChanged(user => {
if(user) {
this.setState({ isLoggedIn: true })
} else {
this.setState({ isLoggedIn: false })
}
})
}
render() {
return(
<NavigationContainer>
{ this.state.isLoggedIn ? (<AppStack />) : (<AuthStack />) }
</NavigationContainer>
)}
}

React-Native. TouchableOpacity works only when tap with 2 fingers

I'm running my app via React-Native and native-base and I got some problems with component TouchableOpacity.
When I'm writing my component like
<TouchableOpacity onPress={() => {this.onPress()}}>
<Text>Some text</Text>
</TouchableOpacity
It works perfect, when I tap with 1 finger
But when I'm running like this - My Code:
renderList () {
return (
<List>
{this.state.data.map( ( restaurant, index ) => {
return (
<TouchableOpacity onPress={() => {
this.onPress();
}} key={index}>
<View style={styles.example}>
<ListItem>
<Thumbnail square size={80} source={{ uri: 'Image URL' }}/>
<Body>
<Text>{restaurant.title}</Text>
<Text note>{restaurant.shortDescription}</Text>
</Body>
</ListItem>
</View>
</TouchableOpacity>
);
} )}
</List>
);
}
It is ignoring 1 tap, twice tap etc, it is only working when I tap with 2 fingers. Didn't find any info about this problem. May be some one know how to solve this?
Thanks
Added FullCode:
import React, { Component } from 'react';
import {
Container,
Button,
Header,
Left,
Icon,
Body,
Right,
Text,
Content,
List,
ListItem,
Thumbnail
} from 'native-base';
import { StyleSheet, TouchableOpacity, View } from 'react-native';
export default class Restaurants extends Component {
constructor ( props ) {
super( props );
this.state = {
data: this.props.data
};
}
onPress () {
console.log( 'Hello' );
}
renderList () {
return (
<List>
{this.state.data.map( ( restaurant, index ) => {
return (
<TouchableOpacity onPress={() => {
this.onPress();
}} key={index}>
<View style={styles.example}>
<ListItem>
<Thumbnail square size={80} source={{ uri: 'Image URL' }}/>
<Body>
<Text>{restaurant.title}</Text>
<Text note>{restaurant.shortDescription}</Text>
</Body>
</ListItem>
</View>
</TouchableOpacity>
);
} )}
</List>
);
}
render () {
return (
<Container>
<Header style={styles.header}>
<Left>
<Button transparent>
<Icon style={styles.header_icon} name="arrow-back"/>
</Button>
</Left>
<Body>
<Text>Ресторанны</Text>
</Body>
<Right>
<Button transparent>
<Icon style={styles.header_icon} name="restaurant"/>
</Button>
</Right>
</Header>
<Content>
{this.renderList()}
</Content>
</Container>
);
}
}
const styles = StyleSheet.create( {
header: {
backgroundColor: '#606dff'
},
header_icon: {
color: 'black'
},
example: {
backgroundColor: 'red'
}
} );
As we spoken, I'll post it here so it's better to read and copy the code.
Try this:
renderList() {
return (
<List>
{
this.state.data.map( ( restaurant, index ) => {
return (
<ListItem>
<TouchableOpacity
onPress={() => {
this.onPress();
}}
key={index}
>
<View style={styles.example}>
<Thumbnail square size={80} source={{ uri: 'Image URL' }}/>
<Body>
<Text>{restaurant.title}</Text>
<Text note>{restaurant.shortDescription}</Text>
</Body>
</View>
</TouchableOpacity>
</ListItem>
);
});
}
</List>
);
}
I swapped <ListItem> and <TouchableOpacity>
There might be any conflict the way you wrote.
Let me know if it worked.

Resources