Two column layout in react native using reactnavigation - react-navigation-v5

I am trying to achieve two column layout if i click something inside tab (for example list of Chats) chat should show in right, now its appears inside left column
can you point me to correct way?

if someone needs this is how I make this
/* eslint-disable react-native/no-inline-styles */
import * as React from 'react';
import {Button, Text, View} from 'react-native';
import {NavigationContainer} from '#react-navigation/native';
import {createStackNavigator} from '#react-navigation/stack';
import {createBottomTabNavigator} from '#react-navigation/bottom-tabs';
function ContactScreen({route}) {
const {contactId} = route.params;
return (
<View style={{flexDirection: 'row', flex: 1}}>
<Tab.Navigator
initialRouteName="Contacts"
style={{flex: 1}}>
<Tab.Screen name="Chats" component={ChatsTab} />
<Tab.Screen name="Contacts" component={ContactsTab} />
</Tab.Navigator>
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<Text>Contact {contactId}</Text>
</View>
</View>
);
}
function ChatScreen({route}) {
const {chatId} = route.params;
return (
<View style={{flexDirection: 'row', flex: 1}}>
<Tab.Navigator
initialRouteName="Chats"
style={{flex: 1}}>
<Tab.Screen name="Chats" component={ChatsTab} />
<Tab.Screen name="Contacts" component={ContactsTab} />
</Tab.Navigator>
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<Text>Chat {chatId}</Text>
</View>
</View>
);
}
function ChatsTab({navigation}) {
return (
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<Text>chats tab</Text>
<Button
title="open chat 1"
onPress={() =>
navigation.navigate('Chat', {
screen: 'Chats',
chatId: 1,
})
}
/>
<Button
title="open chat 2"
onPress={() =>
navigation.navigate('Chat', {
screen: 'Chats',
chatId: 2,
})
}
/>
<Button
title="open chat 5"
onPress={() =>
navigation.navigate('Chat', {
screen: 'Chats',
chatId: 5,
})
}
/>
</View>
);
}
function ContactsTab({navigation}) {
return (
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<Text>contacts tab</Text>
<Button
title="open contact 4"
onPress={() =>
navigation.navigate('Contact', {
screen: 'Contacts',
contactId: 4,
})
}
/>
<Button
title="open contact 3"
onPress={() =>
navigation.navigate('Contact', {
screen: 'Contacts',
contactId: 3,
})
}
/>
</View>
);
}
const HomeStack = createStackNavigator();
const Tab = createBottomTabNavigator();
export default function App() {
return (
<NavigationContainer>
<HomeStack.Navigator screenOptions={{headerShown: false}}>
<HomeStack.Screen
initialParams={{chatId: 0}}
name="Chat"
options={{animationEnabled: false}}
component={ChatScreen}
/>
<HomeStack.Screen
initialParams={{contactId: 0}}
options={{animationEnabled: false}}
name="Contact"
component={ContactScreen}
/>
</HomeStack.Navigator>
</NavigationContainer>
);
}

Related

fontFamily "FontAwesome5Free-Regular" is not a system font and has not been loaded through Font.loadAsync

I'm working on a dental app in which there are icons in almost every screens. But, suddenly all the icons are not visible and just show a box with a question mark. The icon groups keep throwing errors. I changed the way the icons were imported according to expo icons document but it still wasn't working. This is the error I'm getting:
Code of one of the screens in which I am using the icons:
import React, { Component } from "react";
import * as db from '../Config/Firebase';
import {
View,
Text,
StatusBar,
TouchableOpacity,
FlatList,
} from "react-native";
import AntDesign from '#expo/vector-icons/AntDesign'
import Ionicons from '#expo/vector-icons/Ionicons'
import { ListItem, Avatar, Badge } from "react-native-elements";
import firebase from 'firebase/compat/app';
import 'firebase/compat/firestore'
import 'firebase/compat/auth'
import theme from "../Props/theme";
import Constants from "expo-constants";
export default class Pending extends Component {
constructor() {
super();
this.state = {
patients: [],
};
this.patient = null;
}
componentDidMount = async () => {
this.patient = await firebase
.firestore()
.collection(firebase.auth().currentUser.email)
.where("doctorEmail", "==", auth.currentUser.email)
.where("allVisitsCompleted", "==", false)
.onSnapshot((snapshot) => {
var docData = snapshot.docs.map((document) => document.data());
this.setState({
patients: docData,
});
});
};
render() {
return (
<View style={{ flex: 1, backgroundColor: "#FFF" }}>
<StatusBar hidden />
{this.state.patients.length !== 0 ? (
<View>
<FlatList
data={this.state.patients}
style={{ marginTop: 20 }}
renderItem={({ item }) => (
<ListItem>
<ListItem.Content
style={{
backgroundColor: "#f0f0f0",
padding: 20,
borderRadius: 20,
}}
>
<View style={{ flexDirection: "row" }}>
<View>
<Avatar
rounded
icon={{ name: "user", type: "font-awesome" }}
activeOpacity={0.7}
source={{
uri: "https://s3.amazonaws.com/uifaces/faces/twitter/adhamdannaway/128.jpg",
}}
/>
<Badge
containerStyle={{
position: "absolute",
top: -1,
right: -3,
}}
badgeStyle={{
width: 15,
height: 15,
borderRadius: 7.5,
backgroundColor: theme.darkPink,
}}
/>
</View>
<View style={{ flexDirection: "column", marginLeft: 20 }}>
<ListItem.Title>{item.patientName}</ListItem.Title>
<ListItem.Subtitle>{item.patientId}</ListItem.Subtitle>
</View>
</View>
</ListItem.Content>
</ListItem>
)}
keyExtractor={(item, index) => index.toString()}
/>
</View>
) : (
<View>
<Text
style={{
marginTop: Constants.statusBarHeight + 250,
fontSize: 35,
fontWeight: "200",
alignSelf: "center",
}}
>
No patients found
</Text>
<View style={{ marginVertical: 48, alignItems: "center" }}>
<TouchableOpacity
style={{
borderWidth: 2,
borderColor: theme.blue,
borderRadius: 4,
padding: 15,
alignItems: "center",
justifyContent: "center",
}}
onPress={() => this.props.navigation.navigate("Add")}
>
<AntDesign name="plus" size={16} color={theme.darkBlue} />
</TouchableOpacity>
<Text
style={{
color: theme.darkBlue,
fontWeight: "600",
fontSize: 14,
marginTop: 8,
}}
>
Add patient
</Text>
</View>
</View>
)}
</View>
);
}
}
Any ideas on how to solve this? Thanks in advance!
This is related to Expo, it's a known issue.
You will either have to load the font manually, see this.
Or use a library for your icons, VectorIcons has all fontawesome icons.

aws graphql content update shopping cart

I can increase and decrease item quantity from the app in sync with the graphql without any issue. the problem here is when i add a new item it appears in the graphql but it doesn't show up on the app unless i press save ctrl + s, and the same happens when i delete item it gets deleted on the graphql but it disappears from the app only when i press save or ctrl + s.
this is the product details screen and how i add items to cart, and it works fine without any issue and items get added to graphql when i call onAddToCart function
import React, {useState, useEffect} from "react";
import { View, Text, Image, StyleSheet, FlatList, TouchableOpacity, Alert} from 'react-native';
import Icon from 'react-native-vector-icons/AntDesign';
import Colors from "../../constants/Colors";
import { Auth , Hub} from "aws-amplify";
import { API, graphqlOperation } from 'aws-amplify';
import {getProduct } from '../graphql/queries';
import Card from "../../component/Card";
import {createCartItems} from '../graphql/mutations';
const [getProducts, setGetProducts] = useState([])
const [user, setUser] = useState(undefined)
const prodId = route.params;
const [quantity, setQuantity] = useState(1);
useEffect(()=>{
fetchProducts();
},[])
const fetchProducts = async ()=>{
const productsData = await API.graphql(graphqlOperation(getProduct, {id: prodId.productId}))
setGetProducts(productsData.data.getProduct)const checkUser = async ()=>{
try {
const authUser = await Auth.currentAuthenticatedUser({bypassCache: true})
// console.log(authUser)
setUser(authUser)
} catch (error) {
setUser(null)
}
}
useEffect(()=>{
checkUser();
},[])
useEffect(() => {
const listener = data => {
if (data.payload.event === 'signIn' || data.payload.event === 'signOut') {
checkUser();
}
};
Hub.listen('auth', listener);
return () => Hub.remove('auth', listener);
}, []);
const onAddToCart = async ()=>{
const userData = await Auth.currentAuthenticatedUser();
const newCartItem = {
userId: userData.attributes.sub,
productId: getProducts.id,
productPrice: getProducts.price,
productTitle: getProducts.title,
productImage: getProducts.image,
quantity: quantity,
}
API.graphql(graphqlOperation(createCartItems, {input: newCartItem}))
if(user === undefined || !user){
Alert.alert(
'خطأ تسجيل الدخول',
'لابد من تسجيل الدخول للأستمرار',
[
{
text : 'سجل الدخول',
onPress: ()=> navigation.navigate('SignIn')
},
{
text: 'اغلاق'
}
]
)
}else{
navigation.navigate('CartItem')
}
}
useEffect(() => {
const unsubscribe = navigation.addListener('focus', () => {
setQuantity(1);
});
return unsubscribe;
}, [navigation]);
return(
<View style={styles.container}>
<View style={styles.headerImageView}>
<Card image={{uri: getProducts.image}} promotion={getProducts.promotionRate} />
</View>
<View style={styles.descriptionPriceView}>
<Text style={styles.price}>{getProducts.price} ج.م </Text>
<Text style={styles.descriptionText}>{getProducts.description}</Text>
</View>
<View style={styles.quantity}>
<Text style={styles.quantityText}>الكمية</Text>
<Text style={styles.quantityText}>{quantity}</Text>
</View>
<View style={styles.share}>
<TouchableOpacity>
<Image style={{width: 30, height: 30, margin: 10}} source={{uri: 'https://firebasestorage.googleapis.com/v0/b/test-5c03d.appspot.com/o/NakoA%2FLogos%2Ffacebook.png?alt=media&token=6ba4cb45-4f42-42f5-b5c7-2063eeffd1a8'}}/>
</TouchableOpacity>
<TouchableOpacity>
<Image style={{width: 30, height: 30, margin: 10}} source={{uri: 'https://firebasestorage.googleapis.com/v0/b/test-5c03d.appspot.com/o/NakoA%2FLogos%2Finstagram.png?alt=media&token=f06f3b53-f026-43f0-a855-8ace6ed7b1b8'}}/>
</TouchableOpacity>
<TouchableOpacity>
<Icon name="sharealt" size={30} color="black" />
</TouchableOpacity>
</View>
<View style={styles.bottomAddToCartView}>
<View>
<TouchableOpacity onPress={onAddToCart}>
<Text style={styles.bottomAddToCartText}>أضف للسلة</Text>
</TouchableOpacity>
</View>
<View style={styles.addQuantity}>
<TouchableOpacity onPress={()=>{
setQuantity(Math.max(quantity - 1, 1))
}}>
<Text style={styles.minProd}>-</Text>
</TouchableOpacity>
<Text style={styles.numProd}>{quantity}</Text>
<TouchableOpacity onPress={()=>{
setQuantity(Math.min(quantity + 1, 100))
}}>
<Text style={styles.plusProd}>+</Text>
</TouchableOpacity>
</View>
</View>
</View>
)};
this is the CartItem screen
import React, {useEffect, useState} from "react";
import { View, Text, Image, StyleSheet, FlatList } from 'react-native';
import { Auth } from "aws-amplify";
import Colors from "../../constants/Colors";
import { DataStore} from "aws-amplify";
import ItemQuantity from '../../component/ItemQuantity';
import {CartItems} from '../models'
const CartItem = ()=>{
const [cartItem, setCartItem] = useState([]);
const [user, setUser] = useState('');
useEffect(()=>{
fetchCartItem();
userData();
},[])
const fetchCartItem = async ()=>{
try {
const cartitemsData = await DataStore.query(
CartItems, c=>c.userId("eq", user).quantity("gt", 0)
)
setCartItem(cartitemsData)
} catch (error) {
console.log(error)}}
return(
<View style={styles.screen}>
<FlatList data={cartItem} renderItem={({item})=>{
return(
<View style={styles.container}>
<View style={styles.cardView}>
<View style={styles.imageView}>
<Image style={styles.image} source={{uri: item.productImage}} />
</View>
<View style={styles.detailsView}>
<Text style={styles.titl}>{item.productTitle}</Text>
<Text style={styles.price}>{item.productPrice} ج.م </Text>
</View>
</View>
<ItemQuantity quantityItem={item.quantity}
updatedItemId={item.id}
userId={item.userId}
productID={item.productID}
productPrice={item.productPrice}
productTitle={item.productTitle}
productImage={item.productImage}
/>
</View>)}}/>
</View>)};
this is itemQuantity componenet
import React, {useState, useEffect} from "react";
import {View, Text, TouchableOpacity, StyleSheet} from 'react-native'
import { AntDesign } from '#expo/vector-icons';
import { DataStore } from "aws-amplify";
import { CartItems } from "../src/models";
const ItemQuantity = ({quantityItem, updatedItemId})=>{
const [quantity, setQuantity] = useState(quantityItem);
const onMinusPressed = ()=>{
setQuantity(Math.max(1, quantity - 1))
};
useEffect(()=>{fetchUpdatedCartItemPlus();},[quantity])
const fetchUpdatedCartItemPlus= async()=>{
const original = await DataStore.query(CartItems, updatedItemId)
await DataStore.save(CartItems.copyOf(original, updated=>{
updated.quantity = quantity
}))};
return(
<View style={styles.quantity}>
<TouchableOpacity onPress={onMinusPressed}>
<AntDesign name={'minuscircleo'} size={24} color="black" />
</TouchableOpacity>
<TouchableOpacity onPress={cartitemDelete}>
<AntDesign name={'delete'} size={24} color="black" />
</TouchableOpacity>
<Text style={styles.itemQuantity}>{quantity}</Text>
<TouchableOpacity onPress={onPlusPressed}>
<AntDesign name="pluscircleo" size={24} color="black" />
</TouchableOpacity>
</View>
)};

Auth.changePassword throws 'incorrect username or password'

I am using react native and AWS for my backend. I am trying to add a feature that allows users to be able to change their password after they have logged into the app. I believe I should be able to do this using the Auth.changePassword function (AWS doc). For some reason, I am getting an error that the username or password is incorrect.
When testing, the user returns a CognitoUser, the oldPassword is definitely correct, and the newPassword throws errors if it does not meet the character settings. I am lost as to what the issue could be. Should I also be using completeChangePassword in conjunction?
import React from 'react';
import {Auth} from '#aws-amplify/auth';
export default class ChangePassword extends React.Component {
constructor(props) {
super(props);
this.state = {
oldPassword: '',
newPassword: '',
};
}
handleChangePassword = async () => {
const { oldPassword, newPassword } = this.state;
await Auth.currentAuthenticatedUser()
.then(user => {
return Auth.changePassword(user, oldPassword, newPassword)
})
.then(data => console.log(data))
.then(user => this.props.navigation.navigate('Home'))
.catch(err => console.log(err))
}
render() {
return (
<View style={styles.container}>
<View style={styles.header}>
<Text style={styles.text_header}>Change Password</Text>
</View>
<Animatable.View
animation='bounceInUp'
style={styles.footer}
>
<View style={styles.footer}>
<Text style={styles.text_footer}>Old Password</Text>
<View style={styles.action}>
<Feather
name='lock'
color='#05375a'
size={20}
/>
<TextInput
placeholder='Enter old password'
style={styles.textInput}
autoCapitalize='none'
onChangeText={(val) => this.setState({ oldPassword: val })}
/>
</View>
<Text style={styles.text_footer}>New Password</Text>
<View style={styles.action}>
<Feather
name='lock'
color='#05375a'
size={20}
/>
<TextInput
placeholder='Enter new password'
style={styles.textInput}
autoCapitalize='none'
onChangeText={(val) => this.setState({ newPassword: val })}
/>
</View>
<View style={styles.button}>
<TouchableOpacity
style={styles.signIn}
onPress={this.handleChangePassword}
>
<LinearGradient
colors={['#55B142', '#155843']}
style={styles.signIn}
>
<Text style={[ styles.textSign, { color: '#fff' }]}>Submit</Text>
</LinearGradient>
</TouchableOpacity>
</View>
<View style={{ alignItems: 'center'}}>
<View style={{flexDirection: 'row', alignItems: 'center', paddingTop: 5 }}>
<TouchableOpacity
onPress={() => this.props.navigation.navigate('EditProfile')}
style={[styles.signUp, {
//borderColor: '#155843',
//borderWidth: 1,
marginTop: 15,
}]}
>
<Text style={[styles.textSign, {
color: '#155843'
}]}>Go Back</Text>
</TouchableOpacity>
</View>
</View>
</View>
</Animatable.View>
</View>
);
}}
Turns out the problem was that the account that was logged in wasn't verified which is why it would reject the email address.

react navigation screen jumping with when switching screen with BottomTabNavigator

I use BottomTabNavigator from reactnavigation v5. The problem is when switching the pages from bottom tab navigator to the page that is heavier than other pages in terms of rendering elements the screen jumps/flitters for a second to resize. I have noticed it does appear on both platforms but it is more noticeable in android. I have recorded the screen to demonstrate the issue. Any ideas on how to solve the bug would be great.
https://www.youtube.com/watch?v=U6OfVeNafMI
(Check it out when switching to the home screen)
This is how I am using bottomTabNavigator:
const AppNavigator = (props) => {
const { language } = props;
return (
<Tab.Navigator
tabBarOptions={{
activeBackgroundColor: data.colors.superdark_blue,
inactiveBackgroundColor: data.colors.dark_blue,
activeTintColor: data.colors.nice_orange,
inactiveTintColor: "#c9c9c9",
tabStyle: {
zIndex: 100,
},
labelPosition: "below-icon",
tabStyle: {
justifyContent: "center",
paddingTop: 5,
paddingBottom: 5,
borderTopWidth: 1,
borderTopColor: data.colors.dark_blue,
alignItems: "center",
},
labelStyle: {
textAlign: "center",
alignItems: "center",
fontSize: language === "FA" ? 12 : 11,
fontFamily: language === "FA" ? "Yekan" : "Heebo",
},
style: {
backgroundColor: data.colors.dark_blue,
}
}}
screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color, size }) => {
if (route.name === "HOME") {
return (
<Feather name={"home"} size={17} color={color} />
);
} else if (route.name === "OFFERS") {
return (
<AntDesign
name={"notification"}
size={17}
color={color}
/>
);
} else if (route.name === "SAVED") {
return (
<Feather
name={"bookmark"}
size={17}
color={color}
/>
);
} else if (route.name === "CONTACT") {
return (
<Feather
name={"settings"}
size={17}
color={color}
/>
);
}
},
})}
>
<Tab.Screen
name="HOME"
component={HomeStack}
options={{
tabBarLabel: data.bottomNavigatorHeader[language].home,
}}
/>
<Tab.Screen
name="SAVED"
component={FavoritesStack}
options={{
tabBarLabel: data.bottomNavigatorHeader[language].bookmarks,
}}
/>
<Tab.Screen
name="OFFERS"
component={MagazineStack}
options={{
tabBarLabel: data.bottomNavigatorHeader[language].offers,
}}
/>
<Tab.Screen
name="CONTACT"
component={ContactStack}
options={{
tabBarLabel: data.bottomNavigatorHeader[language].contact,
}}
/>
</Tab.Navigator>
);
};
Every tabscreen component as you might guess from their names is also a stackNavigator with a few pages and AppNavigator is wrapped in NavigationContainer in App.js

Displaying data next to each other in react native

In my react-native app I'm returning data from an api, everything is working except for my layout it got messed up, i have an albums list and i need to display each 2 albums next to each other, but all of them are getting displayed under each other, here is my code:
Album detail:
const AlbumDetails= (props) => {
return(
<Album>
<Image source={{ uri: props.album.thumbnail_image }}/>
<Text>{props.album.title}</Text>
</Album>
);
};
export default AlbumDetails;
Album:
const Album= (props) => {
return(
<View style={{flex: 1}}>
<View style={{display: "flex", flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
<View style={styles.albumContainer}>
<View>{props.children}</View>
</View>
</View>
</View>
);
};
const styles = StyleSheet.create({
albumContainer: {
backgroundColor: 'red',
width: '50%',
height: 180,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
marginBottom: 20,
flexDirection: 'column'
},
});
export default Album;
I suggest to use FlatList component with numColumns param equal 2. Check Expo Snack or code below.
export default class App extends React.Component {
render() {
return (
<View style={styles.container}>
<FlatList
style={{ margin: 5 }}
data={data}
numColumns={2}
keyExtractor={(item, index) => item.id}
renderItem={dataItem => (
<AlbumDetails
album={{
title: dataItem.item.title,
thumbnail_image: dataItem.item.image,
}}
/>
)}
/>
</View>
);
}
}