I have a React Native project. My problem is that when login successfully from the Login screen, I navigate to the Home screen. Here I have a bottom navigator tab including Home and Profile. I want to show the user info in Profile but I don't know how to do it. Can anyone give me some ideas?
Here is my code
import React, {useState} from 'react';
import {
View,
StyleSheet,
Text,
Image,
ScrollView,
Dimensions,
TouchableOpacity,
TextInput,
Alert,
} from 'react-native';
import Icon from 'react-native-vector-icons/Ionicons';
import Account from '../component/Account';
const {width: WIDTH} = Dimensions.get('window');
const Login = (props) => {
let [email, setEmail] = useState('');
let [password, setPassword] = useState('');
let [isFocused, setIsFocused] = useState(0);
const _onPress = (index) => {
setIsFocused(index);
};
const dangnhap = (params) => {
if (email.length == 0 || password.length == 0) {
Alert.alert('Thông Báo', 'Hãy nhập đầy đủ email và mật khẩu');
return;
}
try {
fetch('http://192.168.1.10:8080/api/auth/signin', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json ; charset=utf-8',
},
body: JSON.stringify(params),
})
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
if (responseJson.status == 200) {
props.navigation.push('Home', email);
props.navigation.navigate('Home');
} else {
Alert.alert('Thông báo', 'Đăng nhập thất bại');
}
});
} catch (error) {
console.log(error);
}
};
return (
<ScrollView style={{backgroundColor: 'white'}}>
<View style={styles.container}>
<Image
source={require('../assets/images/login.png')}
resizeMode="center"
style={styles.image}
/>
<Text style={styles.textTitle}>Chào mừng trở lại</Text>
<Text style={styles.textBody}>Đăng nhập vào tài khoản sẵn có</Text>
<View style={{marginTop: 10}} />
<View style={styles.inputContainer}>
<Icon
name="mail"
size={25}
color="#59B7C9"
style={styles.inputIcon}
/>
<TextInput
onChangeText={(value) => setEmail(value)}
placeholder="Email"
style={[
styles.input,
{borderColor: isFocused == 1 ? '#59B7C9' : 'black'},
]}
onFocus={() => _onPress(1)}
/>
</View>
<View style={styles.inputContainer}>
<Icon
name="lock-closed"
size={25}
color="#59B7C9"
style={styles.inputIcon}
/>
<TextInput
placeholder={'Mật khẩu'}
pass={true}
onChangeText={(value) => setPassword(value)}
style={[
styles.input,
{borderColor: isFocused == 2 ? '#59B7C9' : 'black'},
]}
secureTextEntry={true}
onFocus={() => _onPress(2)}
/>
</View>
<View style={{width: '90%'}}>
<TouchableOpacity
onPress={() => props.navigation.navigate('Forgot')}
style={([styles.textBody], {alignSelf: 'flex-end'})}>
<Text style={[styles.textBody, {color: 'blue'}]}>
Quên mật khẩu?
</Text>
</TouchableOpacity>
</View>
<View style={styles.buttonContainer}>
<TouchableOpacity
style={styles.buttonLogin}
onPress={() => {
const newUser = {
Email: email,
Password: password,
};
dangnhap(newUser);
}}>
<Text style={styles.buttonText}>Đăng nhập</Text>
</TouchableOpacity>
</View>
<Text style={styles.textBody}>Hoặc kết nối với</Text>
<View style={{flexDirection: 'row'}}>
<Account color="#3b5c8f" icon="facebook" title="Facebook" />
<Account color="#ec482f" icon="google" title="Google" />
</View>
<View style={{flexDirection: 'row', marginVertical: 5}}>
<Text style={styles.textBody}>Chưa có tài khoản?</Text>
<Text
style={[styles.textBody, {color: 'blue'}]}
onPress={() => props.navigation.navigate('Signup')}>
Đăng ký
</Text>
</View>
</View>
</ScrollView>
);
};
This might help
import {AsyncStorage} from 'react-native';
if (responseJson.status == 200) {
AsyncStorage.setItem('email', 'email#email.com');
props.navigation.navigate('Home');
}
Profile.js
import { AsyncStorage } from 'react-native';
export default const Profile = props => {
const [email, setEmail] = useState('');
useEffect(() => {
retrieveData();
}, []);
const retrieveData = async () => {
const email = await AsyncStorage.getItem('email');
setEmail(email);
};
render(){
return {
<View>
<Text>{email}</Text>
</View>
}
}
}
Related
in react native, i am using react navigation ,and when using setOptions i am setting up headerright, and onPress of headerRight, i am updating a boolean state to true, to show up the popup, but it does not showup untill i click on the screen once.
this view Media component is passed to a Flatlist as a Renderitem. does it make any problem here.
import { AntDesign, Feather, Ionicons, Octicons } from "#expo/vector-icons";
import { useNavigation } from "#react-navigation/native";
import { Video } from "expo-av";
import { LinearGradient } from "expo-linear-gradient";
import React, { useContext, useEffect, useLayoutEffect, useRef, useState } from "react";
import {
Image,
ImageBackground,
LayoutAnimation,
Text,
TouchableOpacity,
TouchableWithoutFeedback,
View,
Alert
} from "react-native";
import Animated from "react-native-reanimated";
import { colors, radius } from "../../../../styles/variables";
import { AuthContext } from "../../../components/layout/layout";
import MemberModal from "../../../components/member-modal/member-modal";
import { DEFAULT_PROFILE, SUCCESS } from "../../../utils/constants/user-constants";
import { concatMediaData } from "../../../utils/helpers/concatQueryPages";
import { VIDEO } from "../../add-content/utils/constants";
import { useMediaListQuery } from "../../add-content/utils/hooks";
import { POST } from "../../report/utils/constants";
import DeletePostModal from "../deletePostModal";
import { likeKeyframe, styles } from "./style";
import {
downloadMediaSendRequest
} from "../utils/api";
import { LIKE, LIKED_BY, UNLIKE } from "../utils/constants";
import { useDeleteMediaQuery, useLikedListQuery, useLikeUnlikeMediaQuery } from "../utils/hooks";
import { updateImgixCDN } from "../../../utils/helpers/updateImgixCDN";
const ViewMedia = ({ media }) => {
const navigation = useNavigation()
const { authContext, state } = useContext(AuthContext);
const video = useRef(null);
const [mediaDetail, setMediaDetail] = useState(null)
const [mediaLoaded, setLoaded] = useState(false);
const [status, setStatus] = React.useState({});
const [showModal, setModal] = useState(false);
const [showDeleteModal, setDeleteModal] = useState(false);
const [showKebabModal, setKebabModal] = useState(false);
const [profileURI, setURI] = useState(null);
const [liked, setLiked] = useState(false);
const [totalLikes, setTotalLikes] = useState(0);
const [totalComments, setTotalComments] = useState(null);
const [likedBy, setLikedBy] = useState([]);
const [showMediaText, setMediaText] = useState(true);
const [showPlayPause, setPlayPauseIcon] = useState(null);
const [doubleTapCount, setDoubleTapCount] = useState(0);
const [showDoubleTapIcon, setDoubleTapIcon] = useState(false);
const {
data: likedListData,
isLoading: isLikesLoading,
status: likedStatus,
fetchStatus: likedFetchStatus,
} = useLikedListQuery({
mediaId: media?._id,
circleId: media.circleId._id,
pageParam: 1,
feature: LIKED_BY,
authToken: state.authToken,
});
// console.log(media.s3BucketObject)
const { mutateAsync: mutateDeleteMedia } = useDeleteMediaQuery(mediaDetail)
const { mutateAsync: mutateLikeUnlikedMedia } = useLikeUnlikeMediaQuery(mediaDetail)
// useEffect(() => {
// if (!mediaLoaded) {
// authContext.loading(true);
// }
// return () => {
// authContext.loading(false);
// };
// }, [mediaLoaded]);
useEffect(() => {
// setMediaDetail(state?.selectedMediaData)
setMediaDetail(media)
setTotalLikes(media.likes);
setTotalComments(media.comments);
setURI({ uri: updateImgixCDN(media?.uploadedBy?.profile, 'w=200&h=200') });
}, [state])
useEffect(() => {
navigation.setOptions({
headerLeft: () => (
<Ionicons
name="ellipsis-vertical"
size={26}
color={colors.color_white}
onPress={() => {
setKebabModal(!showKebabModal)
console.log(showKebabModal);
}}
/>
),
headerShown: showMediaText,
});
});
useEffect(() => {
if (likedStatus == SUCCESS && likedListData && likedListData.pages.length)
setLiked(!!likedListData?.pages[0]?.isLikedByUser);
}, [isLikesLoading, media]);
useEffect(() => {
if (mediaDetail) setPlayPause();
}, [status.isPlaying]);
const setPlayPause = () => {
if (mediaDetail?.mediaType == VIDEO) {
if (status.isPlaying) {
setPlayPauseIcon(
<Ionicons name="play" size={60} color={colors.color_white} />
);
setTimeout(() => setPlayPauseIcon(null), 1500);
} else {
setPlayPauseIcon(
<AntDesign name="pause" size={60} color={colors.color_white} />
);
}
}
};
const toggle = () => {
setModal(!showModal);
};
const toggleDeleteModal = () => {
setDeleteModal(!showDeleteModal);
setKebabModal(false);
};
const setLikes = async (likeFlag) => {
setLiked(likeFlag);
const args = {
mediaId: mediaDetail._id,
circleId: mediaDetail?.circleId._id,
authToken: state.authToken,
};
if (likeFlag) {
authContext.setSelectedMediaData({ ...state?.selectedMediaData, likes: totalLikes + 1 })
setTotalLikes((prevState) => prevState + 1);
mutateLikeUnlikedMedia({ ...args, feature: LIKE })
} else {
setDoubleTapCount(0)
authContext.setSelectedMediaData({ ...state?.selectedMediaData, likes: totalLikes - 1 })
setTotalLikes((prevState) => prevState - 1);
mutateLikeUnlikedMedia({ ...args, feature: UNLIKE })
}
};
const deleteMedia = async () => {
const args = {
mediaId: mediaDetail._id,
circleId: mediaDetail?.circleId._id,
authToken: state.authToken,
};
authContext.loading(true);
Alert.alert('Deleting post');
await mutateDeleteMedia(args)
navigation.navigate("AddContent");
authContext.loading(false);
};
return (
<TouchableOpacity activeOpacity={1}
onLongPress={() => {
LayoutAnimation.configureNext(LayoutAnimation.Presets.linear);
setMediaText(false);
}}
onPressOut={() => setMediaText(true)}
onPress={() => {
if (showKebabModal) setKebabModal(!showKebabModal);
if (mediaDetail?.mediaType == VIDEO)
status.isPlaying
? video.current.pauseAsync()
: video.current.playAsync();
// Added Double Tap Like feature
let doubleTapTimer;
setDoubleTapCount((prevCount) => prevCount + 1)
if (doubleTapCount % 2 == 1 && !showDoubleTapIcon) {
setDoubleTapIcon(true)
if (doubleTapCount == 1 && !liked) setLikes(true)
clearTimeout(doubleTapTimer)
} else {
doubleTapTimer = setTimeout(() => {
(function () {
setDoubleTapCount(prevCount => prevCount + 1)
setDoubleTapIcon(false)
})()
}, 1000)
}
}} style={styles.media_screen}>
<>
<TouchableWithoutFeedback
>
<>
{mediaDetail?.mediaType == VIDEO ? (
<Video
ref={video}
style={styles.card}
source={{
uri: mediaDetail?.s3BucketObject,
}}
useNativeControls
isLooping
shouldPlay={true}
resizeMode={"contain"}
onReadyForDisplay={() => setLoaded(true)}
onPlaybackStatusUpdate={(status) => setStatus(() => status)}
/>
) : (
<Image
source={{ uri: updateImgixCDN(mediaDetail?.s3BucketObject, '?auto=compress&w=720') }}
borderRadius={radius.border_radius_ternary}
style={styles.card}
resizeMode={"contain"}
// resizeMode={FastImage.resizeMode.contain}
onLoadEnd={() => setLoaded(true)}
/>
)}
<TouchableOpacity
activeOpacity={0.7}
style={styles.play_pause}
onPress={() => {
mediaDetail?.mediaType == VIDEO &&
(status.isPlaying
? video.current.pauseAsync()
: video.current.playAsync());
}}
>
{showPlayPause}
</TouchableOpacity>
{showDoubleTapIcon ? <Animated.View
entering={likeKeyframe} style={[styles.play_pause, styles.center_like_icon]}>
<AntDesign
name="heart"
size={60}
color={colors.color_green}
/>
</Animated.View> : null}
<LinearGradient
colors={[
colors.color_modal_black_bg,
colors.color_transparent,
colors.color_transparent,
colors.color_modal_black_bg,
]}
style={[showMediaText && styles.linearGradient]}
/>
</>
</TouchableWithoutFeedback>
{showMediaText && (
<>
{showKebabModal && (
<View style={styles.kebab}>
<TouchableOpacity
activeOpacity={0.7}
style={styles.kebab_feature}
onPress={async () => {
authContext.loading(true);
setKebabModal(false);
await downloadMediaSendRequest(
updateImgixCDN(mediaDetail?.s3BucketObject, 'auto=compress'),
mediaDetail?.mediaType
);
authContext.loading(false);
}}
>
<Feather
name="download"
size={24}
color={colors.color_blue}
/>
<Text style={[styles.feature_text, styles.download]}>
Download
</Text>
</TouchableOpacity>
{mediaDetail?.uploadedBy?._id == state?.userData?._id ? (
<>
<TouchableOpacity
activeOpacity={0.7}
style={styles.kebab_feature}
onPress={toggleDeleteModal}
>
<AntDesign
name="delete"
size={24}
color={colors.color_error}
/>
<Text style={[styles.feature_text, styles.delete]}>
Delete
</Text>
</TouchableOpacity>
</>
) : (
<TouchableOpacity
activeOpacity={0.7}
style={styles.kebab_feature}
onPress={() => {
navigation.navigate("Report", {
mediaId: mediaDetail?._id,
circleId: mediaDetail?.circleId?._id,
reportType: POST,
});
setKebabModal(false);
}}
>
<Octicons name="stop" size={24} color={colors.color_blue} />
<Text style={[styles.feature_text, styles.download]}>
Report post
</Text>
</TouchableOpacity>
)}
</View>
)}
<View style={styles.detail}>
<TouchableOpacity
activeOpacity={0.7}
style={styles.detail_top}
onPress={toggle}
>
<Image
source={profileURI || DEFAULT_PROFILE}
style={styles.profile}
/>
<Text style={styles.name}>
{mediaDetail?.uploadedBy?.name || "Earth Cups User"}
</Text>
</TouchableOpacity>
<View style={[styles.detail_bottom, styles.bottom]}>
<View style={styles.detail_bottom}>
<TouchableOpacity
activeOpacity={0.9}
style={styles.like_icon}
// taking current feature as a param after hitting the icon.
onPress={() => setLikes(!liked)}
>
{liked ? (
<Animated.View entering={likeKeyframe} exiting={likeKeyframe}>
<AntDesign
name="heart"
size={15}
color={colors.color_green}
/>
</Animated.View>
) : (
<Animated.View entering={likeKeyframe} exiting={likeKeyframe}>
<AntDesign
name="hearto"
size={15}
color={colors.color_black_500}
/>
</Animated.View>
)}
</TouchableOpacity>
<TouchableOpacity
activeOpacity={0.8}
onPress={() =>
navigation.navigate("MembersList", {
mediaDetail: mediaDetail,
circleId: mediaDetail?.circleId._id,
likePage: true,
})
}
>
<Text style={styles.name}>
{totalLikes} like{totalLikes > 1 && "s"}
</Text>
</TouchableOpacity>
</View>
<TouchableOpacity
activeOpacity={0.8}
style={[
styles.detail_bottom,
styles.bottom_right,
styles.like_icon,
]}
onPress={() =>
navigation.navigate("Comments", {
mediaDetail: media,
circleId: media?.circleId._id,
})
}
>
<Image
source={require("../../../../assets/icons/comment.png")}
/>
<Text style={[styles.name, styles.comments]}>
{totalComments}
</Text>
</TouchableOpacity>
</View>
</View>
</>
)}
<MemberModal
toggle={toggle}
showModal={showModal}
memberDetail={mediaDetail?.uploadedBy}
/>
<DeletePostModal
toggle={toggleDeleteModal}
showModal={showDeleteModal}
deleteMedia={() => deleteMedia()}
/>
</>
</TouchableOpacity>
);
};
export default React.memo(ViewMedia);
I am very new to React Native and this is the reason why I need your help now. I try to create an app with a normal Sidemenu (Burgermenu) which should apear on ech page. And I have a Bottom tab bar which should appear on 3 pages. The problem is, that on those 3 pages the Sidemenu is not displayed. What am I doing wrong?
This is the first called Page:
import * as React from 'react';
import DrawerNavigator from './DrawerNavigator'
function App() {
return (
<DrawerNavigator />
);
}
export default App;
This is the Sidemenu (DrawerNavigator.js):
import * as React from 'react'
import { createDrawerNavigator, DrawerContentScrollView, DrawerItemList, DrawerItem } from '#react-navigation/drawer'
import ProjekteStackNavigator from './side_menu/Projekte'
import DashboardStackNavigator from './side_menu/Desktop'
...
import { Text, View, StyleSheet} from 'react-native';
//##################### ICONS Importieren #####################
import AppLoading from 'expo-app-loading';
import { useFonts } from 'expo-font';
import { createIconSetFromIcoMoon } from '#expo/vector-icons';
const Icon = createIconSetFromIcoMoon(
require('../../assets/icomoon/selection.json'),
'IcoMoon',
'zepra_icons.ttf'
);
//#############################################################
const Drawer = createDrawerNavigator()
function myLogout(){
navigation.navigate("LoginScreen");
}
const DrawerNavigator = () => {
const [fontsLoaded] = useFonts({ IcoMoon: require('../../assets/icomoon/zepra_icons.ttf') });
if (!fontsLoaded) {
return <AppLoading />;
}
return (
<Drawer.Navigator initialRouteName="Home" drawerContent={props => {
return (
<DrawerContentScrollView {...props} scrollIndicatorInsets={{ right: 1 }}>
<DrawerItemList {...props} />
<DrawerItem label="Logout" labelStyle={{marginLeft:-18, fontSize: 15,}}
icon={({ focused, color, size }) => <Icon2 style={{marginLeft:8}} color={focused ? '#1585b5' : '#6cbabf'} size={26} name={focused ? 'log-out-outline' : 'log-out-outline'} /> }
onPress={() => props.navigation.navigate("StartScreen") } />
</DrawerContentScrollView>
)
}}>
<Drawer.Screen name="Dashboard" component={DashboardStackNavigator}
options={{
drawerLabel: 'Dashboard',
drawerLabelStyle:{ marginLeft:-20, fontSize: 15},
drawerIcon: ({focused, size}) => (
<Icon name='HAUS_3' size={35} color={focused ? '#1585b5' : '#6cbabf'} />
)}}/>
<Drawer.Screen name="Projekte" component={ProjekteStackNavigator}
options={{
drawerLabel: 'Projekte',
drawerLabelStyle:{marginLeft:-20, fontSize: 15},
drawerIcon: ({focused, size}) => (
<Icon name='PROJEKTE_ALLE' size={35} color={focused ? '#1585b5' : '#6cbabf'} />
)}}/>
</Drawer.Navigator>
)
}
export default DrawerNavigator
This is the Projects Page which calls the Pages with the Bottom Tab:
import React, { useState, useEffect } from 'react';
import {Alert, View, Text, Modal, StyleSheet, Pressable, ListView, FlatList, TouchableOpacity } from 'react-native'
import { createStackNavigator } from '#react-navigation/stack'
import { theme } from '../../core/theme';
import clientConfig from '../../../client-config';
import Icon2 from 'react-native-vector-icons/Ionicons';
import ProjektOverview from '../ProjektOverview'
//##################### ICONS Importieren #####################
import AppLoading from 'expo-app-loading';
import { useFonts } from 'expo-font';
import { createIconSetFromIcoMoon } from '#expo/vector-icons';
const Icon = createIconSetFromIcoMoon(
require('../../../assets/icomoon/selection.json'),
'IcoMoon',
'zepra_icons.ttf'
);
//#############################################################
const Stack = createStackNavigator()
const ModalComponent = ({ modalVisible, setModalVisible, children }) => {
return (
<Modal
animationType="slide"
transparent={true}
style={styles.centeredView}
visible={modalVisible}
onRequestClose={() => {
Alert.alert('Modal has been closed.');
setModalVisible(!modalVisible);
}}>
{children}
</Modal>
);
};
export default function ObjectsScreen({ navigation }){
const [modalVisible, setModalVisible] = useState(false);
const [modal2Visible, setModal2Visible] = useState(false);
const [data, setData] = React.useState(null);
const [fontsLoaded] = useFonts({ IcoMoon: require('../../../assets/icomoon/zepra_icons.ttf') });
const onClickHandler =(data)=>()=> {
navigation.navigate('ProjektOverview', {data});
};
const comp_id = localStorage.getItem('anwender_unternehmen');
if ( localStorage.getItem( 'token' )!=null ) {
React.useEffect(() => {
async function getData() {
try {
const siteUrl = clientConfig.siteUrl + '/wp-json/zep/v1/projekt-liste/' + comp_id;
const response = await fetch(siteUrl, {
method: 'GET',
headers: {
Authorization: 'Bearer '+localStorage.getItem( 'token' )
}
})
if (response.status === 200) {
let json = await response.json();
const array = json.data;
const error = array.error_code;
if(error == 0){
const projekte = array.data_values[0];
setData(projekte);
}else{
setData(1201);
}
}else {
if(response.status === 503) {
setModalVisible(true);
}
if(response.status === 403) {
setModal2Visible(true);
}
throw new Error(`failed due to status code ${response.status}`);
}
} catch (err) {
console.log(err);
}
}
getData();
}, []);
if(data != 1201){
return (
<FlatList
data={data}
keyExtractor={(item, index) => String(index) + item.value}
renderItem={({item, index})=>(
<TouchableOpacity onPress={ onClickHandler({item}) } >
<View style={{ textAlign: 'left', borderColor:'#6cbabf', borderBottomWidth: 1, padding:10, margin:0, flexDirection: "row", alignItems: "center"}}>
<Text style={{textAlign: 'left', marginLeft:15, fontSize: 16, fontWeight: '500',}}>
{item.projekt_name} {item.projekt_nummer}</Text>
<View style={{flex:1, alignItems: "center", flexDirection: "row", justifyContent: "flex-end", marginRight:30}}>
<Icon name='PROJEKTE_BEARBEITEN' size={40} color={'#6cbabf'} />
<Icon2 name='eye-outline' size={10} color={'#6cbabf'} style={{padding:-100, margin:-17, bottom:-7.5}} />
</View>
</View>
</TouchableOpacity>
)}/>
); // return
}else{
return (
<View style={{borderColor:'#6cbabf',borderWidth: 1,borderRadius:5, padding:15,margin:12,}}>
<View style={{justiftyContent:"center", alignItems:"center"}}>
<Icon name='PROJEKTE_ALLE' size={100} color={'#6cbabf'} />
</View>
<Text style={{textAlign: 'left', fontSize: 16, fontWeight: '700', paddingBottm:15,}}>Sie haben noch keine Projekte erstellt.</Text>
<Text style={{fontSize: 12}}> </Text>
<Text style={{textAlign: 'center', fontSize: 13}}>Projekte können nur in der Desktopanwendung verwalten werden.</Text>
</View>
); // return
}
}else{
navigation.navigate('Dashboard');
}
return (
<>
<ModalComponent
modalVisible={modalVisible}
setModalVisible={(val) => {
setModalVisible(val);
}}>
<View style={styles.centeredView}>
<View style={styles.modalView}>
<Text style={styles.modalText}>Fehler 503</Text>
<Text style={styles.modalText}>Ein unbekannter Fehler ist aufgetreten!.</Text>
<Pressable
style={[styles.button, styles.buttonClose]}
onPress={() => setModalVisible(!modalVisible)}>
<Text style={styles.textStyle}>Ok</Text>
</Pressable>
</View>
</View>
</ModalComponent>
<ModalComponent
modalVisible={modal2Visible}
setModalVisible={(val) => {
setModal2Visible(val);
}}>
<View style={styles.centeredView}>
<View style={styles.modalView}>
<Text style={styles.modalText}>Fehler 403</Text>
<Text style={styles.modalText}>Bitte loggen Sie sich erneut ein!</Text>
<Pressable
style={[styles.button, styles.buttonClose]}
onPress={() => setModal2Visible(!modal2Visible)}>
<Text style={styles.textStyle}>Ok</Text>
</Pressable>
</View>
</View>
</ModalComponent>
</>
);
}
This is the Bottom Navigator:
import * as React from 'react';
import { NavigationContainer } from '#react-navigation/native';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
//##################### ICONS Importieren #####################
import AppLoading from 'expo-app-loading';
import { useFonts } from 'expo-font';
import { createIconSetFromIcoMoon } from '#expo/vector-icons';
const Icon = createIconSetFromIcoMoon(
require('../../assets/icomoon/selection.json'),
'IcoMoon',
'zepra_icons.ttf'
);
//#############################################################
//##################### Seiten importieren #####################
import ProjectsScreen from './ProjectScreen';
import WaermeschutzScreen from './tabs/waermeschutz';
import BegehungenScreen from './tabs/begehungen';
//##############################################################
//##################### Menünamen für Buttontab ################
const projectsName = "Projekte";
const waermeschutzName = "Wärmeschutz";
const begehungenName = "Begehungen";
//##############################################################
//#################### BUTTON-TAB erstellen #####################
const Tab = createBottomTabNavigator();
function MainContainer() {
// Load the icon font before using it
const [fontsLoaded] = useFonts({ IcoMoon: require('../../assets/icomoon/zepra_icons.ttf') });
if (!fontsLoaded) {
return <AppLoading />;
}
return (
<Tab.Navigator
initialRouteName={projectsName}
screenOptions={({ route }) => ({
headerShown: false,
tabBarIcon: ({ focused, color, size }) => {
let iconName;
let rn = route.name;
if (rn === projectsName) {
iconName = focused ? 'PROJEKTE_ALLE' : 'PROJEKTE_ALLE';
} else if (rn === waermeschutzName) {
iconName = focused ? 'HAUS_3' : 'HAUS_3';
} else if (rn === begehungenName) {
iconName = focused ? 'NOTIZ_ERSTELLEN' : 'NOTIZ_ERSTELLEN';
}
// You can return any component that you like here!
return <Icon name={iconName} size={43} color={color} />;
},
'tabBarActiveTintColor': '#4283b1',
'tabBarInactiveTintColor': '#5db8bd',
'tabBarStyle':{ 'paddingTop':4, 'height':90 },
'tabBarLabelStyle':{ 'paddingTop':3, 'fontSize':13 }
})}>
<Tab.Screen name={projectsName} component={ProjectsScreen} />
<Tab.Screen name={waermeschutzName} component={WaermeschutzScreen} />
<Tab.Screen name={begehungenName} component={BegehungenScreen} />
</Tab.Navigator>
);
}
export default MainContainer;
And this is the page with the ProjectsScreen:
import React, { useState, useEffect } from 'react';
import {Alert, View, Text, Modal, StyleSheet, ImageBackground, ScrollView, FlatList , TouchableOpacity, Linking} from 'react-native';
import Background from '../components/Background_2';
import BackButton from '../components/BackButton';
import helpers from '../components/Data_funks';
import Icon2 from 'react-native-vector-icons/Ionicons';
import DrawerNavigator from './DrawerNavigator'
//##################### ICONS Importieren #####################
import AppLoading from 'expo-app-loading';
import { useFonts } from 'expo-font';
import { createIconSetFromIcoMoon } from '#expo/vector-icons';
const Icon = createIconSetFromIcoMoon( require('../../assets/icomoon/selection.json'), 'IcoMoon', 'zepra_icons.ttf');
const Bold = ({ children }) => <Text style={{ fontWeight: 'bold' }}>{children}</Text>
//#############################################################
//export default function ProjectsScreen({ route, navigation }) {
function ProjectsScreen({ route, navigation }) {
const data = route.params['data'];
const [projekte_data, setProjektdata] = useState([]);
const [bauherr, setBauherr] = useState([]);
const [bauleiter, setBauleiter] = useState([]);
const [projektleiter, setProjektleiter] = useState([]);
const [sachbearbeiter, setSachbearbeiter] = useState([]);
const [objekte, getObjekte] = useState([]);
// Projektdaten ########################################################################
useEffect(() => {
const init = async () => {
await helpers.get_projekt_data(data.item.projekt_id).then(result =>{
setProjektdata(result.p_data[0]);
setBauherr(result.bauherr[0]);
setBauleiter(result.bauleiter[0]);
setProjektleiter(result.projektleiter[0]);
setSachbearbeiter(result.sachbearbeiter[0]);
})
}
;
init();
},[]);
//###################################################################################
// Objektdaten ########################################################################
useEffect(() => {
const init2 = async () => {
await helpers.getObjekte(data.item.projekt_id).then(result2 =>{
getObjekte(result2[0]);
})
}
;
init2();
},[]);
//###################################################################################
const onClickHandler =(data)=>()=> {
navigation.navigate('ProjektOverview', {data});
};
console.log(objekte);
return(
<ScrollView scrollIndicatorInsets={{ right: 1 }} contentContainerStyle={{ flexGrow: 1 }}>
<Background>
<DrawerNavigator />
<View style={{paddingTop:50,}}>
<Icon name='KRAN' size={80} color={'#6cbabf'} style={{textAlign: 'center',}} />
</View>
<View style={{paddingTop:10,}}>
{ data.item.projekt_name !='Kein Titel'? <Text style={styles.HeadNameStyle}>{data.item.projekt_name}
<Text>{"\n"}</Text>
{data.item.projekt_nummer}</Text> : <Text style={styles.HeadNameStyle}>{data.item.projekt_nummer}</Text> }
</View>
<View style={styles.tabsStyle}>
<View style={styles.row}>
<TouchableOpacity onPress={() => Linking.openURL(`tel:${bauleiter['kontakte_mobil']}`) }>
<Icon2 style={styles.icon} name='call-outline' size={22} color={'#6cbabf'} />
</TouchableOpacity>
<View style={styles.inputWrap}>
<Text style={styles.tabsHeader}><Bold>Bauleiter:</Bold> {bauleiter['kontakte_vorname']} {bauleiter['kontakte_vorname']}</Text>
</View>
<View style={styles.inputWrap2}>
<TouchableOpacity onPress={() => Linking.openURL(`tel:${bauleiter['kontakte_mail']}`) }>
<Icon2 style={styles.icon} name='md-mail-outline' size={22} color={'#6cbabf'} />
</TouchableOpacity>
</View>
</View>
<View style={styles.row}>
<TouchableOpacity onPress={() => Linking.openURL(`tel:${bauherr['kontakte_mobil']}`) }>
<Icon2 style={styles.icon} name='call-outline' size={22} color={'#6cbabf'} />
</TouchableOpacity>
<View style={styles.inputWrap}>
<Text style={styles.tabsHeader}><Bold>Bauherr:</Bold> {bauherr['kontakte_vorname']} {bauherr['kontakte_nachname']}</Text>
</View>
<View style={styles.inputWrap2}>
<TouchableOpacity onPress={() => Linking.openURL(`tel:${bauherr['kontakte_mail']}`) }>
<Icon2 style={styles.icon} name='md-mail-outline' size={22} color={'#6cbabf'} />
</TouchableOpacity>
</View>
</View>
<View style={styles.row}>
<TouchableOpacity onPress={() => Linking.openURL(`tel:${projektleiter['anwender_mobil']}`) }>
<Icon2 style={styles.icon} name='call-outline' size={22} color={'#6cbabf'} />
</TouchableOpacity>
<View style={styles.inputWrap}>
<Text style={styles.tabsHeader}><Bold>Projektleiter:</Bold> {projektleiter['anwender_vorname']} {projektleiter['anwender_nachname']}</Text>
</View>
<View style={styles.inputWrap2}>
<TouchableOpacity onPress={() => Linking.openURL(`tel:${projektleiter['anwender_mail']}`) }>
<Icon2 style={styles.icon} name='md-mail-outline' size={22} color={'#6cbabf'} />
</TouchableOpacity>
</View>
</View>
<View style={styles.row}>
<TouchableOpacity onPress={() => Linking.openURL(`tel:${sachbearbeiter['anwender_mobil']}`) }>
<Icon2 style={styles.icon} name='call-outline' size={22} color={'#6cbabf'} />
</TouchableOpacity>
<View style={styles.inputWrap}>
<Text style={styles.tabsHeader}><Bold>Sachbearbeiter:</Bold> {sachbearbeiter['anwender_vorname']} {sachbearbeiter['anwender_nachname']}</Text>
</View>
<View style={styles.inputWrap2}>
<TouchableOpacity onPress={() => Linking.openURL(`tel:${sachbearbeiter['anwender_mail']}`) }>
<Icon2 style={styles.icon} name='md-mail-outline' size={22} color={'#6cbabf'} />
</TouchableOpacity>
</View>
</View>
</View>
<View style={styles.objectHeader}>
{ objekte !=''? <Text style={styles.HeadNameStyle}>Objekte</Text>: null}
</View>
<FlatList style={styles.FlatList}
data={objekte}
scrollEnabled={false}
keyExtractor={(item, index) => String(index) + item.value}
renderItem={({item, index})=>(
<View style={styles.Container}>
<View style={styles.navBar}>
<Icon name='HAUS_3' size={110} color={'#6cbabf'} />
<View style={styles.centerContainer}>
<Text style={styles.centerText}>{item.objekt_name} </Text>
<Text style={styles.centerText}>{item.objekt_nummer} </Text>
</View>
</View>
<Text>{<Bold>Adresse:</Bold>} {item.objekt_strasse}</Text>
<Text>{' '} {item.objekt_plz}, {item.objekt_ort}</Text>
<Text>{' '}</Text>
<Text>{<Bold>Nutzung:</Bold>} {item.objekt_typ}, {<Bold>Vorhaben:</Bold>} {item.objekt_sanierungs_art}</Text>
</View>
)}/>
<Text>{''}</Text>
</Background>
</ScrollView>
)
}
export default ProjectsScreen;
The setSearchTerm does not get updated and is stuck with empty string all the time when i hit "done" on the keyboard. Any suggestions?
// React Native Bottom Navigation
// https://aboutreact.com/react-native-bottom-navigation/
import React, { useState } from 'react';
import { View, Text, SafeAreaView, Dimensions, FlatList, TouchableOpacity, TextInput } from 'react-native';
import { WebView } from 'react-native-webview';
import
MaterialCommunityIcons
from 'react-native-vector-icons/MaterialCommunityIcons';
const windowWidth = Dimensions.get('window').width;
const windowHeight = Dimensions.get('window').height;
const SearchScreen = ({navigation}) => {
const [searchTerm, setSearchTerm] = useState('');
const [data, dataSet] = useState({})
const onSearchText = async() => {
alert(searchTerm);
dataSet({});
let txtSearch = searchTerm;
if(txtSearch.length > 0){
//alert(searchTerm);
let response = await fetch('https://xxxxxx',{
headers: {
'Accept': 'application/json, text/plain',
'Content-Type': 'application/json;charset=UTF-8'
},
method: 'POST',
body: JSON.stringify({ searchTerm: searchTerm }),
mode: 'no-cors',
})
response = await response.json();
alert(JSON.stringify(response.results));
//alert(JSON.stringify(response.results));
dataSet(response.results);
}else{
}
}
React.useLayoutEffect(() => {
navigation.setOptions({
headerRight: () =>
<View style={{flexDirection:'row'}}>
<TextInput
placeholder='Search Here'
onChangeText={term => setSearchTerm(term)}
onSubmitEditing={onSearchText} style={{backgroundColor:'#B2DFDB',marginRight:20,width:windowWidth - 125, padding:5, borderRadius:5,}}/>
</View>
,
});
}, [navigation, ]);
const renderItem = ({ item }) => (
<TouchableOpacity
onPress={() => navigation.navigate("Display", { url: item.url, youtube: item.youtube })}>
<View style={{flexDirection:'row', marginBottom:20,padding:10,backgroundColor:'#B2DFDB',borderRadius:10,}}>
<View pointerEvents="none" style={{}}>
<WebView style={{width:200, height:130, }} source={{ uri: item.url }} />
</View>
<View style={{ marginLeft:10, }}>
<Text style={{color:'#00796B', flexWrap: 'wrap',}}>{item.source}</Text>
<View style={{flexDirection:'row', flex:1,}}>
<Text style={{color:'#000000', fontWeight:'bold', flex:1, flexWrap: 'wrap'}}>{item.title}</Text>
</View>
<Text style={{color:'#00838F', }}>{item.category}</Text>
<Text style={{color:'#00838F', }}>{item.country}</Text>
</View>
</View>
</TouchableOpacity>
);
return (
<SafeAreaView style={{ flex: 1 }}>
<View style={{ flex: 1 , padding: 16, backgroundColor:'#E0F2F1',}}>
{
data.length > 0 ? (
<FlatList
style={{flex:1,}}
data={data}
renderItem={renderItem}
keyExtractor={item => item.id}
/>) : <View style={{flex:1,justifyContent:'center',alignItems:'center', }}><Text style={{color:'#80CBC4', fontSize:20, textAlign:'center'}}>Nothing found, please try and search again.</Text></View>
}
</View>
</SafeAreaView>
);
}
export default SearchScreen;
You don't currently have a value assigned to the textInput field. Adding a value of searchTerm should resolve it.
React.useLayoutEffect(() => {
navigation.setOptions({
headerRight: () =>
<View style={{flexDirection:'row'}}>
<TextInput
placeholder='Search Here'
onChangeText={term => setSearchTerm(term)}
value={searchTerm}
onSubmitEditing={onSearchText} style={{backgroundColor:'#B2DFDB',marginRight:20,width:windowWidth - 125, padding:5, borderRadius:5,}}/>
</View>
,
});
}, [navigation, ]);
I'm new to react-native. This component below should render comments posted by users, I would like to add an inputText component from react-native to allow users to post a comment, but don't know where I should place it within the code below.
import React, { useState, useEffect } from 'react';
import { useNavigation } from "#react-navigation/native";
import Icon from 'react-native-vector-icons/AntDesign';
import {
StyleSheet,
Text,
View,
TouchableOpacity,
Image,
ScrollView,
FlatList,
Button,
TextInput
} from 'react-native';
import parseDate from "../utils/parseDate";
import * as API from "../api/api"
export default function CommentList({ ride }) {
const [text, setText] = React.useState("");
const [commentsData, setComments] = useState([]);
const navigation = useNavigation();
useEffect(() => {
API.getCommentsByRideId(ride.ride_id).then((comments) => {
setComments(comments)
})
}, [ride.ride_id])
deleteComment = (comment_id) => {
// useEffect(() => {
API.deleteCommentsByCommentId(comment_id).then(() => {
const updatedComments = list.filter((item) => item.comment_id !== comment_id);
setComments(updatedComments)
})
// }, [comment_id])
}
//deletes on refresh only
addComment = (newComment, ride_id) => {
API.postCommentByRideId(newComment, ride_id).then(() => {
setComments(newComment)
})
}
return (
<FlatList
style={styles.root}
data={commentsData}
ItemSeparatorComponent={() => {
return (
<View style={styles.separator} />
)
}}
keyExtractor={(item) => {
return item.author;
}}
renderItem={(item) => {
const comment = item.item;
return (
<View style={styles.container}>
<TouchableOpacity onPress={() => navigation.navigate("UserProfile", { username: item.author })}>
{/* <Image style={styles.image} source={{ uri: comment.avatar_url }} /> */}
</TouchableOpacity>
<View style={styles.content}>
<View style={styles.contentHeader}>
<Text style={styles.name}>{comment.author}</Text>
<Text style={styles.time}>
{parseDate(comment.created_at)}
{comment.votes}
</Text>
</View>
<Text rkType='primary3 mediumLine'>{comment.body}</Text>
{/* <Text style={styles.time}> Likes: {comment.votes}</Text> */}
<TouchableOpacity onPress={() => deleteComment(comment.comment_id)}>
<Icon name="delete" size={20} color="#e33057" />
</TouchableOpacity>
</View>
</View>
);
}} />
);
}
This is the inputText I would like to add to allow users to post a comment.
<TextInput
value={text}
placeholder="write..."
onChangeText={text => setText(text)}
onSubmitEditing={() => addcomment(text, ride.ride_id)}
/>
if you want to add it at fixed position in bottom of screen you may do this
<View style={{flex : 1}}>
<Flatlist
contentContainerStyle={{paddingBottom: 50}}
.../>
<View style={{position : 'absolute', bottom : 0, width : '100%', height : 50}}>
//you input here
</View>
</View>
or if you want to add it last item of flatlist you may use ListFooterComponent
<FlatList
ListFooterComponent={<Input/>}
.../>
</FlatList>
I'm new in react native and trying to create an app with CRUD operation & RESTful API, but I'm stuck in the UPDATE/PUT, Can anyone help in this matter?? Below are my frontend + backend codes:
Backend side
// update data by id
router.put('/:id', validate, (req, res) => {
const bookId = req.params.id
const errors = validationResult(req)
if(!errors.isEmpty()){
return res.status(422).send({errors: errors.array()})
}
Book.findById(bookId)
.then(book => {
book.bookTitle = req.body.bookTitle,
book.ImgURL = req.body.ImgURL,
book.bookDescription = req.body.bookDescription,
book.bookAuthor = req.body.bookAuthor,
book.bookPrice = req.body.bookPrice,
book.bookTypes = req.body.bookTypes,
book.bookYear = req.body.bookYear,
book.bookRating = req.body.bookRating,
book.bookPages = req.body.bookPages
return book.save()
})
.then(result => res.send(result))
.catch(errors => console.log(errors))
})
Result in POSTMAN, I changed title from how to brew -> how to brew like professional
ReduxAction.js
export const editBook = ({id, bookTitle, ImgURL, bookDescription, bookAuthor, bookPrice, bookTypes, bookYear, bookRating, bookPages}) => {
return async dispatch => {
const response = await fetch(`http://localhost:3000/api/books/${id}`, {
method: 'PUT',
body: JSON.stringify({id, bookTitle, ImgURL, bookDescription, bookAuthor, bookPrice, bookTypes, bookYear, bookRating, bookPages})
})
const responseData = await response.json()
dispatch({
type: EDIT_BOOKS,
payload: responseData
})
}
}
EditScreen.js
import React, {useState, useEffect} from 'react'
import { StyleSheet, Text, View, ScrollView, TextInput, Button, KeyboardAvoidingView, Alert,
ActivityIndicator } from 'react-native'
import { useDispatch, useSelector } from 'react-redux'
import * as bookAction from '../redux/actions/bookAction'
import { Formik } from 'formik'
import * as Yup from 'yup'
import DropDownPicker from 'react-native-dropdown-picker'
const formSchema = Yup.object({
bookTitle: Yup.string().required('*required').min(5, '*must be between 5 to 50 characters').max(50, '*must be between 5 to 50 characters'),
ImgURL: Yup.string().required('*required'),
bookDescription: Yup.string().required('*required').min(30, '*must be at least 30 characters'),
bookAuthor: Yup.string().required('*required'),
bookPrice: Yup.number().required('*required'),
bookTypes: Yup.string().required('*required'),
bookYear: Yup.number().required('*required'),
bookRating: Yup.number().required('*required'),
bookPages: Yup.number().required('*required')
})
const AddBookScreen = props => {
const {id} = props.route.params
const book = useSelector(state => state.book.books.find(book => book._id === id))
const [isLoading, setIsLoading] = useState(false)
if(isLoading) {
return (
<View style={styles.centered}>
<ActivityIndicator size="large" />
</View>
)
}
const dispatch = useDispatch()
return (
<KeyboardAvoidingView
behavior="padding"
keyboardVerticalOffset={100}
style={{flex: 1}}>
<ScrollView>
<Formik
initialValues={{
id: id,
bookTitle: book.bookTitle,
ImgURL: book.ImgURL,
bookDescription: book.bookDescription,
bookAuthor: book.bookAuthor,
bookPrice: book.bookPrice.toString(),
bookTypes: book.bookTypes,
bookYear: book.bookYear.toString(),
bookRating: book.bookRating.toString(),
bookPages: book.bookPages.toString()
}}
validationSchema={formSchema}
onSubmit={(values) => {
console.log(values)
setIsLoading(true)
dispatch(bookAction.editBook(values))
.then(() => {
setIsLoading(false)
Alert.alert('book edited successfrully')
})
.catch(() => {
setIsLoading(false)
Alert.alert('an error occurred, please try again!')
})
}}>
{(props) =>
(
<View style={styles.form}>
<View style={styles.formGroup}>
<Text style={styles.label}>Book Title</Text>
<TextInput
style={styles.input}
onChangeText={props.handleChange('bookTitle')}
onBlur={props.handleBlur('bookTitle')}
value={props.values.bookTitle}
/>
<Text style={styles.error}>{props.touched.bookTitle && props.errors.bookTitle}</Text>
</View>
<View style={styles.formGroup}>
<Text style={styles.label}>Imgae URL</Text>
<TextInput
style={styles.input}
onChangeText={props.handleChange('ImgURL')}
onBlur={props.handleBlur('ImgURL')}
value={props.values.ImgURL}
/>
<Text style={styles.error}>{props.touched.ImgURL && props.errors.ImgURL}</Text>
</View>
<View style={styles.formGroup}>
<Text style={styles.label}>Book Description</Text>
<TextInput
style={styles.input}
onChangeText={props.handleChange('bookDescription')}
onBlur={props.handleBlur('bookDescription')}
value={props.values.bookDescription}
/>
<Text style={styles.error}>{props.touched.bookDescription && props.errors.bookDescription}</Text>
</View>
<View style={styles.formGroup}>
<Text style={styles.label}>Book Author</Text>
<TextInput
style={styles.input}
onChangeText={props.handleChange('bookAuthor')}
onBlur={props.handleBlur('bookAuthor')}
value={props.values.bookAuthor}
/>
<Text style={styles.error}>{props.touched.bookAuthor && props.errors.bookAuthor}</Text>
</View>
<View style={styles.formGroup}>
<Text style={styles.label}>Book Price</Text>
<TextInput
style={styles.input}
onChangeText={props.handleChange('bookPrice')}
onBlur={props.handleBlur('bookPrice')}
value={props.values.bookPrice}
keyboardType='numeric'
/>
<Text style={styles.error}>{props.touched.bookPrice && props.errors.bookPrice}</Text>
</View>
<View style={styles.formGroup}>
<Text style={styles.label}>Book Types</Text>
<TextInput
style={styles.input}
onChangeText={props.handleChange('bookTypes')}
onBlur={props.handleBlur('bookTypes')}
value={props.values.bookTypes}
/>
<Text style={styles.error}>{props.touched.bookTypes && props.errors.bookTypes}</Text>
</View>
<View style={styles.formGroup}>
<Text style={styles.label}>Book Year</Text>
<TextInput
style={styles.input}
onChangeText={props.handleChange('bookYear')}
onBlur={props.handleBlur('bookYear')}
value={props.values.bookYear}
keyboardType='numeric'
/>
<Text style={styles.error}>{props.touched.bookYear && props.errors.bookYear}</Text>
</View>
<View style={styles.formGroup}>
<Text style={styles.label}>Book Rating</Text>
<TextInput
style={styles.input}
onChangeText={props.handleChange('bookRating')}
onBlur={props.handleBlur('bookRating')}
value={props.values.bookRating}
keyboardType='numeric'
/>
<Text style={styles.error}>{props.touched.bookRating && props.errors.bookRating}</Text>
</View>
<View style={styles.formGroup}>
<Text style={styles.label}>Book Pages</Text>
<TextInput
style={styles.input}
onChangeText={props.handleChange('bookPages')}
onBlur={props.handleBlur('bookPages')}
value={props.values.bookPages}
keyboardType='numeric'
/>
<Text style={styles.error}>{props.touched.bookPages && props.errors.bookPages}</Text>
</View>
<View style={styles.buttonContainer}>
<Button title='save edit' onPress={props.handleSubmit} color='steelblue' />
</View>
</View>
)}
</Formik>
</ScrollView>
</KeyboardAvoidingView>
)
}
export default AddBookScreen
const styles = StyleSheet.create({
form: {
backgroundColor: "#ffffff",
padding: 20,
borderRadius: 10,
},
formGroup: {
width: "100%",
},
label: {
marginVertical: 10,
},
input: {
paddingHorizontal: 2,
paddingVertical: 8,
borderBottomColor: "#ccc",
borderBottomWidth: 1,
},
buttonContainer: {
marginTop: 20,
},
error: {
color: 'red'
},
centered: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
}
})
React Native Debugger
Edited
Manage to fix the error in debugger, by modifying the ReduxReducer.js
case EDIT_BOOKS:
return {
...state,
books: state.books.map(book => action.payload.find(item => item.id === book._id) || book)
}
The error is gone, but it didn't update the data
So I found the solution of my issue by Editing the ReduxReducer.js to
case EDIT_BOOKS:
return {
...state,
books: [...state.books]
}