I'm doing a welcome flatlist for the first-time users, I have an image and text to be shown, but it does not render any image, what am I doing wrong? When I put the path in the View it works, but when I put in the imagePath it shows a blank screen
import React from 'react';
import {
View,
Text,
Image,
TouchableOpacity,
FlatList,
} from 'react-native';
import ProgressCircle from 'react-native-progress-circle';
import Icon from 'react-native-vector-icons/AntDesign';
import {SafeAreaView} from 'react-native-safe-area-context';
import {TextInput, Button} from 'react-native-paper';
import styles from './styles';
import {blue} from 'chalk';
<FlatList
horizontal={true}
data={onboardingList}
renderItem={this.Welcome}
keyExtractor={(item, index) => index.toString()}
/>;
const onboardingList = [
{
screenText1: 'Get weekly overviews and find',
screenText2: 'out whats impacting your health',
screenText3: 'and wellness.',
imagePath: require('../../assets/images/wellbeing.png'),
nextScreen: 'HabitTracking',
progressCirclePercentage: 20,
},
{
screenText1: 'Explore healthyroutines and get',
screenText2: 'reminders to stay motivated along',
screenText3: 'the way.',
imagePath: require('../../assets/images/HabitTracking.png'),
nextScreen: 'Recommendation',
progressCirclePercentage: 40,
},
];
const Welcome = (item, navigation) => {
return (
<View style={styles.container}>
<View>
<Image source={item.imagePath} style={styles.image} />
</View>
<View style={styles.text_field}>
<Text style={styles.textContent}>{item.screenText1}</Text>
<Text style={styles.textContent}>{item.screenText2}</Text>
<Text style={styles.textContent}>{item.screenText3}</Text>
</View>
<View style={styles.footer}>
<TouchableOpacity onPress={() => navigation.navigate(item.nextScreen)}>
<ProgressCircle
percent={item.progressCirclePercentage}
radius={30}
borderWidth={2}
color="#3399FF"
shadowColor="white"
bgColor={'white'}>
<Icon name="arrowright" size={25} color="black"></Icon>
</ProgressCircle>
</TouchableOpacity>
</View>
</View>
);
};
export default Welcome;
Bonus question, the progressCircle is not getting the numbers I'm giving on progressCirclePercentage
Found the solution, the problem was on my View, I was using item.screenText and it should be only screentext
<View style={styles.container}>
<View>
<Image source={imagePath} style={styles.image} />
</View>
<View style={styles.text_field}>
<Text style={styles.textContent}>{screenText1}</Text>
<Text style={styles.textContent}>{screenText2}</Text>
<Text style={styles.textContent}>{screenText3}</Text>
</View>
<View style={styles.footer}>
<TouchableOpacity onPress={() => handleModal(2)}>
<ProgressCircle
percent={progressCirclePercentage}
radius={30}
borderWidth={2}
color="#3399FF"
shadowColor="white"
bgColor={'white'}>
<Icon name="arrowright" size={25} color="black"></Icon>
</ProgressCircle>
</TouchableOpacity>
</View>
</View>
Related
Hi I am new to React Native.
I want to open a modal from another modal.
I have a modal showing event details and user can delete this event. When they press delete button, I want to add another modal saying 'are you sure ?' as in the picture
[![enter image description here][1]][1]
My code doesn't work. I used onModalHide with setTimeOut to close the first one and opend the second one. But did not work. What can be the error here ?
import React, {useRef, useState} from 'react';
import {View, ScrollView, Text, Pressable} from 'react-native';
import styles from '#/screens/dashboard/events/CreatedEventDetails.styles';
import Modal from 'react-native-modal';
import common from '#/config/common';
import {useDispatch, useSelector} from 'react-redux';
import FastImage from 'react-native-fast-image';
import images from '#/config/images';
import {Icon, LoadingIndicator} from '#/components';
import {
closeEventDetailsModal,
fetchEventsList,
handleDeleteEvent,
handleWithDrawEvent,
LOADING,
} from '#/store/events/events';
import {EVENT_STATUS} from '#/constants/eventStatus';
import {strings} from '#/localization';
import moment from 'moment';
const CreatedEventDetails = ({isVisible, closeModal}) => {
const createdEventDetails = useSelector(state => state?.events?.eventDetails);
const userInfo = useSelector(state => state.profile.user);
const dispatch = useDispatch();
const currentEventId = useSelector(state => state.events.currentEventId);
const isLoading =
useSelector(state => state?.events?.eventResponseStatus) === LOADING;
const capitilizedLetter = createdEventDetails?.name
?.toLowerCase()
.charAt(0)
.toUpperCase();
const restOfTheName = createdEventDetails?.name?.slice(1);
const deleteEvent = id => {
dispatch(handleDeleteEvent(id));
dispatch(closeEventDetailsModal());
};
const withDrawEvent = id => {
dispatch(handleWithDrawEvent(id));
dispatch(closeEventDetailsModal());
};
function getBgColor(condition) {
switch (condition) {
case EVENT_STATUS.STATUS_NEW:
return '#ef9d50';
case EVENT_STATUS.STATUS_ACCEPTED:
return '#a1dc6a';
case EVENT_STATUS.STATUS_TENTATIVE:
return 'blue';
case EVENT_STATUS.STATUS_REJECTED:
return 'red';
default:
return '#ef9d50';
}
}
// to change the modal action according to created events or accepted events, we have to check
// if the logged in user id is matching with event owner id. ( delete - withdraw action )
const isOwner = createdEventDetails?.owner?.id === userInfo?.id;
const createdEventDate = createdEventDetails?.event_date;
const formattedDate = moment(createdEventDate).format('DD MMM, ddd');
const fromTime = createdEventDetails?.from_time?.toString();
const formattedFromTime = moment(fromTime, 'hh:mm').format('LT');
const toTime = createdEventDetails?.to_time?.toString();
const formattedToTime = moment(toTime, 'hh:mm').format('LT');
// second modal state
const [isDeleteModalVisible, setIsDeleteModalVisible] = useState(false);
// second modal function
const toggleModal = () => {
// when the second modal is open, I close the first one here.
dispatch(closeEventDetailsModal());
setIsDeleteModalVisible(!isDeleteModalVisible);
};
return (
<>
<View style={styles.modalContainer}>
<Modal
isVisible={isVisible}
propagateSwipe
onBackdropPress={() => this.setState(isVisible)}
onModalHide={() => {
setTimeout(() => {
setIsDeleteModalVisible(!isDeleteModalVisible);
}, 100);
}}
onModalWillHide={() => {
setTimeout(() => {
dispatch(fetchEventsList());
}, 500);
}}>
<View style={styles.content}>
{/* we have to check if event id is matching with currentEventId to prevent undefined problem
and also modal detail can have previous event detail. this will prevent the issue */}
{createdEventDetails.id !== currentEventId ? (
<LoadingIndicator visible />
) : (
<View>
<LoadingIndicator visible={isLoading} />
<View style={styles.closeBtnContainer}>
<Pressable style={styles.closeBtn} onPress={closeModal}>
<Text style={styles.closeText}>X</Text>
</Pressable>
</View>
<View>
<Text
style={
styles.contentTitle
}>{`${capitilizedLetter}${restOfTheName}`}</Text>
<Text style={styles.contenSubtTitle}>
{formattedDate}
{'\n'}
{formattedFromTime} - {formattedToTime}
</Text>
<Text style={styles.contentText}>
At {createdEventDetails?.location}
</Text>
<View style={styles.participantsContainer}>
<Text style={styles.contentTitle}>
{strings.eventDetails.participantsTitle} (
{createdEventDetails?.invites?.length})
</Text>
<View style={common.stickyButtonLine} />
<ScrollView>
{createdEventDetails?.invites?.map(invite => (
<View style={styles.checkboxContainer} key={invite.id}>
<View style={styles.imageContainer}>
{invite?.user?.thumb ? (
<FastImage
source={{uri: invite?.user?.thumb}}
style={styles.listItemUserImage}
resizeMode={FastImage.resizeMode.cover}
/>
) : (
<Icon
icon={images.ic_user}
style={styles.noUserIcon}
/>
)}
<Text style={styles.contentPersonName}>
{invite?.user?.name}
</Text>
</View>
<View
style={{
backgroundColor: getBgColor(invite?.status),
width: 25,
height: 25,
borderRadius: 25,
}}>
<Text>{''}</Text>
</View>
</View>
))}
</ScrollView>
</View>
<View>
<View>
<Text style={styles.contentTitle}>
{strings.eventDetails.hobbiesTitle} (
{createdEventDetails?.hobbies?.length})
</Text>
<View style={common.stickyButtonLine} />
<View style={styles.hobbiesContainer}>
{createdEventDetails?.hobbies?.map(hobby => (
<View style={styles.emojiContainer} key={hobby.id}>
<Text>{hobby.emoji}</Text>
</View>
))}
</View>
<View style={common.stickyButtonLine} />
</View>
<View style={[styles.buttons, styles.singleButtonAlign]}>
{isOwner ? (
<>
<Pressable
style={styles.decline}
onPress={toggleModal}
// onPress={() =>
// deleteEvent(createdEventDetails?.id)
// }
>
<Text style={styles.declineText}>
{strings.eventDetails.delete}
</Text>
</Pressable>
// second modal content here
{/* <Modal
isVisible={isDeleteModalVisible}
propagateSwipe>
<View style={styles.content}>
<Text>Hello!</Text>
<Pressable
title="Hide modal"
onPress={toggleModal}
/>
</View>
</Modal> */}
</>
) : (
<Pressable
style={styles.decline}
onPress={() =>
withDrawEvent(createdEventDetails?.id)
}>
<Text style={styles.declineText}>
{strings.eventDetails.withdraw}
</Text>
</Pressable>
)}
</View>
</View>
</View>
</View>
)}
</View>
</Modal>
</View>
// second modal content here
<View style={styles.modalContainer}>
<Modal isVisible={isDeleteModalVisible} propagateSwipe>
<View style={styles.content}>
<Text>Hello!</Text>
<Pressable title="Hide modal" onPress={toggleModal} />
</View>
</Modal>
</View>
</>
);
};;
export default CreatedEventDetails;
````
[1]: https://i.stack.imgur.com/BUMfa.png
Here are some way of debugging.
first check both the modal is showing up by passing harcoded true value for one by one.
if its working correctly, remove those timeouts and apicalls and
just check with useState only.
if all are fine then try to call
the api.
can anyone explain me why keyboard dismiss not works ? No errors and nothing happens.
In my last project it works, but not there. What do I am wrong?
Code:
import React, { useState, useEffect } from 'react';
import { StyleSheet, View, Text, TextInput, TouchableOpacity, KeyboardAvoidingView, ScrollView, Dimensions, Keyboard } from 'react-native';
import { AntDesign } from '#expo/vector-icons';
import { LinearGradient } from 'expo-linear-gradient';
const width = Dimensions.get('window').width;
const height = Dimensions.get('window').height;
const Home = () => {
const [searchInput, setSearchInput] = useState('');
return (
<KeyboardAvoidingView onPress={() => Keyboard.dismiss()} style={styles.container}>
<LinearGradient
style={styles.header}
colors={['blue', 'red', 'orange']}
>
<View style={{alignItems: 'flex-end'}}>
<TouchableOpacity>
<AntDesign style={{textAlign: 'right'}} name="pluscircleo" size={42} color="#fff" />
</TouchableOpacity>
</View>
<View style={styles.headerBottom}>
<Text style={styles.headerText}>Treffpunkt</Text>
<TextInput
placeholder="Gebe deinen Code ein"
value={searchInput}
onChangeText={value => setSearchInput(value)}
style={styles.searchInput}
/>
</View>
</LinearGradient>
</KeyboardAvoidingView>
)
};
As Konstantin had mentioned in the comment, KeyboardAvoidingView does not have an onPress event.
You can have a child element before the gradient that will handle the press for you.
You can refer to the expo example here
<KeyboardAvoidingView
style={styles.container}>
<TouchableWithoutFeedback onPress={() => Keyboard.dismiss()}>
<LinearGradient
style={styles.header}
colors={['blue', 'red', 'orange']}>
<View style={{ alignItems: 'flex-end' }}>
...
</View>
</LinearGradient>
</TouchableWithoutFeedback>
</KeyboardAvoidingView>
I'm getting this error.[ErrorImg][1]
This is Require cycles error but I can't find what is the reason.
I want to use ListItem component to View.js through component.js and I already use that like this import {ListItem } from '../components/';.
The result is good but there is this warning and I want to fix. Please help me.
Require cycle: Components.js->
import Button from './Button';
import Select from './Select';
import Icon from './Icon';
import Tabs from './Tabs';
import Product from './Product';
import Drawer from './Drawer';
import Header from './Header';
import Switch from './Switch';
import ListItem from './ListItem';
import HorizontalListItem from './HorizontalListItem';
export {
Button,
Select,
Icon,
Tabs,
Product,
Drawer,
Header,
Switch,
ListItem,
HorizontalListItem,
};```
View.js->
```const renderPatientsList = () => {
return(
<Block style={{ paddingHorizontal: theme.SIZES.BASE }}>
<ScrollView vertical={true} showsVerticalScrollIndicator={false} style={{marginBottom: theme.SIZES.BASE * 3}}>
<ListItem product={products[0]} horizontal />
<ListItem product={products[1]} horizontal />
<ListItem product={products[2]} horizontal />
</ScrollView>
</Block>
)
}```
ListItem.js -->
```import React from 'react';
import { withNavigation } from '#react-navigation/compat';
import { StyleSheet, Dimensions, Image, TouchableWithoutFeedback } from 'react-native';
import { Block, Text, theme } from 'galio-framework';
import { Icon } from '../components/';
import { LinearGradient } from 'expo-linear-gradient';
const { width } = Dimensions.get('screen');
const ListItem = props => {
const { navigation, product, horizontal, full, style, priceColor, imageStyle, time, unReaden, weekday } = props;
const imageStyles = [styles.image, full ? styles.fullImage : styles.horizontalImage, imageStyle];
return (
<Block row={horizontal} card flex style={[styles.product, styles.shadow, style]}>
<TouchableWithoutFeedback onPress={() => navigation.navigate('Product', { product: product })}>
<Block style={[styles.imageContainer, styles.shadow]}>
<Image source={{ uri: product.image }} style={imageStyles}/>
</Block>
</TouchableWithoutFeedback>
<TouchableWithoutFeedback onPress={() => navigation.navigate('Product', { product: product })}>
<Block flex={3}>
<Text size={16} style={styles.userName}>{product.title}</Text>
<Block flexDirection={'row'}>
<Icon name="photo" family="font-awesome" color={theme.COLORS.MUTED} size={theme.SIZES.BASE} style={styles.icons}> </Icon>
<Icon name="check" family="font-awesome" color={theme.COLORS.MUTED} size={theme.SIZES.BASE} style={styles.icons}> </Icon>
<Text size={16} muted={!priceColor} color={priceColor}>${product.price}</Text>
</Block>
</Block>
</TouchableWithoutFeedback>
<TouchableWithoutFeedback onPress={() => navigation.navigate('Product', { product: product })}>
<Block flex={1}>
<>
{(product.time) ? (
<Text size={12} style={styles.times} color={"#06D81E"}>{product.time}</Text>
) : (
<Text size={12} style={styles.times} color={"#000"}>{product.weekday}</Text>
)}
</>
<Block style={{borderRadius: 100, backgroundColor: "#06D81E", width: theme.SIZES.BASE * 1.2, height: theme.SIZES.BASE * 1.2, position: "absolute", right: theme.SIZES.BASE, bottom: theme.SIZES.BASE}}>
<Text size={12} center style={{justifyContent: 'center', alignItems: 'center'}} color={"#FFF"} fontWeight={"semiBold"}>{product.unReaden}</Text>
</Block>
</Block>
</TouchableWithoutFeedback>
</Block>
);
}```
[1]: https://i.stack.imgur.com/rDB6i.png
You are getting require cycle warning because you end up creating a loop ( require from Component.js in ListItem.js and require from ListItem.js in Component.js)
In ListItem.js,
import {Icon} from Icon.js
The general idea is to write the module in another file and import that module from there.
see this for a detailed explanation:
Require cycles are allowed, but can result in uninitialized values. Consider refactoring to remove the need for a cycle
I have added the below reusable code to show Modal and close the Modal when clicked outside of that Modal, when I click on a button the Modal is shown and when I click outside of that Modal it gets closed till here it is working properly but again when I click on a button to open Modal, the Modal is not shown, and I can't use props on can anyone tell me any other solution and what mistake I have made in the below code.
import React, { FunctionComponent, useState } from 'react';
import { Modal, FlatList,TouchableWithoutFeedback } from 'react-native';
interface Props {
visible: boolean;
onClose: () => void;
}
const BottomSheet: FunctionComponent<Props> = (props) => {
const [showBottomSheet,setBottomSheet]=useState(true);
if(showBottomSheet){
return (
<Modal animationType={ANIMATIONS.SlideType} transparent={true} visible={props.visible}>
<TouchableWithoutFeedback onPress={()=> setBottomSheet(false)}>
<View style={Styles.opacityContainer}></View>
</TouchableWithoutFeedback>
<View style={Styles.container}>
<View style={Styles.headerContainer}>
<View style={[Styles.header, Styles.directionRow]}>
<View>
<Text style={Styles.headerText}>Add</Text>
</View>
<View style={Styles.iconContainer}>
<Icon
name={cancel}
size={18}
IconClick={props.onClose}
/>
</View>
</View>
</View>
<View style={Styles.viewContainer}>
<SafeAreaView>
<FlatList
horizontal={false}
data={props.navData}
renderItem={renderActions}
keyExtractor={(item) => item.id}
/>
</SafeAreaView>
</View>
</View>
</Modal>
);
}
return null;
};
This is the other file where I am using the above reusable component
customer.tsx
const [showBottomSheet, setShowBottomSheet] = useState(false);
const hideBottomSheet = () => {
setShowBottomSheet(false);
};
<View style={Styles.profileContainer}>
<AddButton
onButtonPress={() => {
setShowBottomSheet(true);
}}
iconObject={{
iconName: plus,
iconSize: Sizes.plusLargeSize,
}}
/>
<BottomSheet
visible={showBottomSheet}
onClose={hideBottomSheet}
/>
</View>
I'm trying to implement a flatlist of comments alongside a textinput at the bottom. However, when I try to place the textinput in a keyboard avoiding view so that it gets pushed to the top to see the input being typed in, it doesn't go to the top and stays at the bottom. Here is my code:
render() {
return (
<KeyboardAvoidingView enabled behavior='padding' style={styles.container}>
<View style={styles.commentStyles}>
<FlatList
keyExtractor={(item) => JSON.stringify(item.date)}
data={this.props.post.comments}
renderItem={({item}) => (
<View style={[styles.row, styles.commentContainer]}>
<Image style={styles.roundImage} source={{uri: item.commenterPhoto}}/>
<View style={[styles.left]}>
<Text>{item.commenterName}</Text>
<Text style={styles.commentText}>{item.comment}</Text>
</View>
</View>
)}
/>
<TextInput
style={styles.input}
onChangeText={(comment) => this.setState({comment})}
value={this.state.comment}
returnKeyType='send'
placeholder='Add Comment'
onSubmitEditing={this.postComment}
/>
</View>
</KeyboardAvoidingView>
);
}
My container just has a flex: 1 styling applied to it. I tried reading through the documentation for KeyboardAvoidingView but found it to be very confusing. If you guys can help me in any way, would greatly appreciate it!
Give this a try.
import React, {Component} from 'react';
import {
StyleSheet,
Text,
View,
KeyboardAvoidingView,
Platform,
Dimensions,
TextInput
} from 'react-native';
const {height: fullHeight} = Dimensions.get('window');
class Comment extends Component {
constructor(props) {
super(props);
this.state = {
pageOffset: 0,
};
}
onLayout = ({
nativeEvent: {
layout: {height},
},
}) => {
const pageOffset =
fullHeight - height;
this.setState({pageOffset});
};
render() {
return (
<View style={styles.viewContainer} onLayout={this.onLayout}>
<KeyboardAvoidingView
style={styles.container}
keyboardVerticalOffset={this.state.pageOffset}
behavior={Platform.OS === 'ios' ? 'padding' : null}>
<FlatList
keyExtractor={(item) => JSON.stringify(item.date)}
data={this.props.post.comments}
renderItem={({item}) => (
<View style={[styles.row, styles.commentContainer]}>
<Image style={styles.roundImage} source={{uri: item.commenterPhoto}}/>
<View style={[styles.left]}>
<Text>{item.commenterName}</Text>
<Text style={styles.commentText}>{item.comment}</Text>
</View>
</View>
)}
/>
<TextInput
style={styles.input}
onChangeText={(comment) => this.setState({comment})}
value={this.state.comment}
returnKeyType='send'
placeholder='Add Comment'
onSubmitEditing={this.postComment}
/>
</KeyboardAvoidingView>
</View>
);
}
}
export default Comment;
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'space-between',
},
viewContainer: {
flex: 1,
},
});