I am using react-native-bouncy-checkbox and Flatlist.
I have created an array object which has id, name, amount.
So far I have achieved:
User can select individual items from the Flatlist, and it will add the amount and display it
as total amount.
User can also edit the amount they have selected using TextInput.
However, I am trying to create a 'Select All' feature.
So, when user presses 'Select All' or taps on the 'checkbox' it should:
select all the items from the FlatList
add the total amount
allow user to edit all the selected amount individually
update the checkbox to show that it is selected.
So far I have tried getting all the 'checkbox' to show that it is selected when 'Select All' text is pressed or when 'checkbox' is pressed (beside select all text).
I have been trying to get this to work for the last couple of hours but couldn't manage to do it. So any help regarding this issue are most welcome.
CODE SNIPPETS AND APP SCREENSHOTS PROVIDED BELOW:
Code Sample:
import 'react-native-gesture-handler';
import React, { useState, useEffect, Component } from 'react';
import { StyleSheet, View, Text, TouchableOpacity, FlatList } from 'react-native';
import { Button, Divider, TextInput } from 'react-native-paper';
import BouncyCheckbox from 'react-native-bouncy-checkbox';
import TextInputMask from 'react-native-text-input-mask';
function AccountMultiplePayment({ navigation }) {
const [apiData, setApiData] = useState([
{
id: 1,
name: 'John',
address: 'address 1',
amount: '79.90',
},
{
id: 2,
name: 'Simon',
address: 'address 2',
amount: '35.50',
},
{
id: 3,
name: 'Tim',
address: 'address 3',
amount: '15.50',
},
{
id: 4,
name: 'Rob',
address: 'address 4',
amount: '33.33',
},
{
id: 5,
name: 'Sarah',
address: 'address 5',
amount: '77.77',
},
])
const [billPaymentAmount, setBillPaymentAmount] = useState({})
const [selectedBill, setSelectedBill] = useState([]);
const [totalPaymentAmount, setTotalPaymentAmount] = useState(0);
const computeBillPaymentAmount = () => {
let newBillPaymentAmount = {}
apiData.forEach(({ id, amount }) => {
newBillPaymentAmount[id] = amount
})
return newBillPaymentAmount
}
const computeTotalPaymentAmount = () => {
let total = 0
selectedBill.forEach(id => {
total += parseFloat(billPaymentAmount[id])
})
// Prevent NaN issue, because once user delete amount will become empty string
return total ? total : 0
}
useEffect(() => {
setBillPaymentAmount(computeBillPaymentAmount())
}, [apiData])
useEffect(() => {
setTotalPaymentAmount(computeTotalPaymentAmount())
}, [selectedBill, billPaymentAmount])
const [checked, setChecked] = useState(false);
return (
<>
<View style={{flexDirection: 'row'}}>
<TouchableOpacity
style={{ alignItems: 'center', paddingVertical: 10 }}
onPress={() => setChecked(!checked)}
>
<Text style={{ color: 'black', fontSize: 25 }}>Select All</Text>
</TouchableOpacity>
<BouncyCheckbox
isChecked={checked}
fillColor={'green'}
unfillColor={'#FFFFFF'}
onPress={() => {
setChecked(!checked)
}}
/>
</View>
<FlatList
data={apiData}
renderItem={({ item }) => {
return (
<View style={{ flexDirection: 'row' }}>
<View style={[styles.subHeaderContainer, { flex: 1 }]}>
<Text
style={[
styles.defaultText,
{ fontWeight: 'bold', fontSize: 16 },
]}>
{item.name}
</Text>
<Divider style={{ marginVertical: 5 }} />
<View style={{ flexDirection: 'row' }}>
<Text
style={[styles.defaultText, { fontWeight: 'bold', flex: 2 }]}>
Total Payable Amount:
</Text>
<View style={{ flex: 1 }}>
<TextInput
value={billPaymentAmount[item.id]}
onChangeText={value => setBillPaymentAmount({ ...billPaymentAmount, [item.id]: value })}
keyboardType={'numeric'}
mode={'outlined'}
label={'RM'}
dense={true}
render={props =>
<TextInputMask
{...props}
mask='[9990].[99]'
/>
}
/>
</View>
</View>
</View>
<BouncyCheckbox
isChecked={checked}
fillColor={'green'}
unfillColor={'#FFFFFF'}
onPress={() => {
if (selectedBill.includes(item.id)) {
setSelectedBill(selectedBill.filter(value => value !== item.id))
} else {
setSelectedBill([...selectedBill, item.id])
}
}}
/>
</View>
);
}}
keyExtractor={item => item.id}
removeClippedSubviews={false}
/>
{
<>
<View
style={{
paddingVertical: 10,
paddingHorizontal: 20,
flexDirection: 'row',
backgroundColor:'blue'
}}>
<Text
style={{ color: 'white', flex: 1, fontWeight: 'bold', fontSize: 18 }}>
Total Amount:{' '}
</Text>
<View>
<Text style={{ color: 'white', fontWeight: 'bold', fontSize: 24 }}>
RM {totalPaymentAmount.toFixed(2)}
</Text>
{totalPaymentAmount <= 0 ? null : (
<TouchableOpacity
onPress={() => {
//navigation.goBack();
navigation.goBack();
navigation.navigate('Account');
}}>
<Text>Reset</Text>
</TouchableOpacity>
)}
</View>
</View>
<Button
mode={'contained'}
color={'limegreen'}
style={{
borderRadius: 5,
marginHorizontal: 20,
marginVertical: 10,
justifyContent: 'center',
}}
labelStyle={{ color: 'white', padding: 10 }}
uppercase={false}
onPress={() => { }}
disabled={totalPaymentAmount <= 0 ? true : false}>
<Text>Pay Bill</Text>
</Button>
</>
}
</>
);
}
class Account extends Component {
constructor(props) {
super(props);
this._isMounted = false;
this.state = {
};
}
render() {
return (
<>
{<AccountMultiplePayment {...this.props} {...this.navigation} />}
</>
);
}
}
export default Account;
const styles = StyleSheet.create({
flex: {
flex: 1,
},
headerTitle: {
alignItems: 'center',
borderBottomLeftRadius: 25,
borderBottomRightRadius: 25,
paddingHorizontal: 20,
paddingVertical: 20,
},
subHeaderContainer: {
paddingVertical: 10,
paddingHorizontal: 20,
backgroundColor: 'white',
borderRadius: 10,
elevation: 5,
marginVertical: 5,
marginHorizontal: 10,
},
subHeaderTitle: {
color: 'white',
fontWeight: 'bold',
fontSize: 16,
backgroundColor: '#2c1855',
padding: 10,
borderRadius: 10,
},
defaultText: {
color: 'black',
},
});
This is what it looks like currently. All checked items are individually selected:
This is what I am trying to achieve:
After checking the documentation of react-native-bouncy-checkbox, the following is important.
isCheckeddetermines the default internal checkbox state. It is only evaluated once.
The check-state handling is handled internally by the library.
We want to handle this on our own, in order to check all checkbox with a single state change. To do so, we need to set the disableBuiltInState prop to true "if you want to manually handle the isChecked prop and disable built in handling".
Thus, I would suggest the following workflow.
Create a state array for isChecked which contains a boolean flag for each of the elements.
Create a custom onPress-handler which gets the index from the FlatList as a parameter. With that index, we are able to to set the correct boolean flag in our state array to true or false.
If Select All is pressed, our onPress-handler sets all boolean flags of our state array to true. This will cause a rerendering of our screen and since we set disableBuiltInState prop to true, react-native-bouncy-checkbox will use our custom state handling.
Here is a minimal working example.
// set inititial all to false, you might want some different initial state
const [checks, setChecks] = useState(Array.from({ length: apiData.length }, () => false))
const onCheck = React.useCallback(
(index) => {
let previous = [...checks]
previous[index] = !previous[index]
setChecks(previous)
},
[checks, setChecks]
)
const selectAll = React.useCallback(() => {
let previous = [...checks]
setChecks(previous.map(() => true))
}, [checks, setChecks])
return (
<View style={{ padding: 40, marginTop: 50 }}>
<FlatList
data={apiData}
renderItem={({ item, index }) => (
<View style={{ padding: 20 }}>
<BouncyCheckbox
isChecked={checks[index]}
fillColor={"green"}
unfillColor={"#FFFFFF"}
onPress={() => onCheck(index)}
disableBuiltInState={true}
/>
</View>
)}
keyExtractor={(item) => "" + item.id}
removeClippedSubviews={false}
/>
<TouchableOpacity onPress={selectAll}>
<Text style={{ fontSize: 20, color: "red" }}> Select All</Text>
</TouchableOpacity>
</View>
)
This looks as follows.
Pressing Select All yields
Since you want to calculate additional values (total payable amount for each selected item) I would suggest to just add the checks state to your already implemented useEffect. When the checks state changes, this useEffect will be called. You can calculate all fields for which the boolean flag inside checks is true and set the state for the input fields.
Let refactor code as below
import "react-native-gesture-handler";
import React, { useState, useEffect, Component } from "react";
import {
StyleSheet,
View,
Text,
TouchableOpacity,
FlatList,
} from "react-native";
import { Button, Divider, TextInput } from "react-native-paper";
import BouncyCheckbox from "react-native-bouncy-checkbox";
function AccountMultiplePayment({ navigation }) {
const [apiData, setApiData] = useState([
{
id: 1,
name: "John",
address: "address 1",
amount: "79.90",
},
{
id: 2,
name: "Simon",
address: "address 2",
amount: "35.50",
},
{
id: 3,
name: "Tim",
address: "address 3",
amount: "15.50",
},
{
id: 4,
name: "Rob",
address: "address 4",
amount: "33.33",
},
{
id: 5,
name: "Sarah",
address: "address 5",
amount: "77.77",
},
]);
const [billPaymentAmount, setBillPaymentAmount] = useState({});
const [selectedBill, setSelectedBill] = useState([]);
const [totalPaymentAmount, setTotalPaymentAmount] = useState(0);
const computeBillPaymentAmount = () => {
let newBillPaymentAmount = {};
apiData.forEach(({ id, amount }) => {
newBillPaymentAmount[id] = amount;
});
return newBillPaymentAmount;
};
const computeTotalPaymentAmount = () => {
let total = 0;
selectedBill.forEach((id) => {
total += parseFloat(billPaymentAmount[id]);
});
// Prevent NaN issue, because once user delete amount will become empty string
return total ? total : 0;
};
useEffect(() => {
setBillPaymentAmount(computeBillPaymentAmount());
}, [selectedBill.length]);
useEffect(() => {
setTotalPaymentAmount(computeTotalPaymentAmount());
}, [billPaymentAmount]);
const selectAllBill = () => {
if (selectedBill.length < apiData.length) {
setSelectedBill([...new Set(apiData.map((item) => item.id))]);
}
if (selectedBill.length === apiData.length) {
setSelectedBill([]);
}
};
const isBillAdded = (id) => selectedBill.some((el) => el === id);
const hasAllBillselected = apiData.length === selectedBill.length;
return (
<>
<View style={{ flexDirection: "row" }}>
<TouchableOpacity
style={{ alignItems: "center", paddingVertical: 10 }}
onPress={selectAllBill}
>
<Text style={{ color: "black", fontSize: 25 }}>Select All</Text>
</TouchableOpacity>
<BouncyCheckbox
disableBuiltInState
isChecked={hasAllBillselected}
fillColor={"green"}
unfillColor={"#FFFFFF"}
onPress={selectAllBill}
/>
</View>
<FlatList
data={apiData}
renderItem={({ item }) => {
return (
<View style={{ flexDirection: "row" }}>
<View style={[styles.subHeaderContainer, { flex: 1 }]}>
<Text
style={[
styles.defaultText,
{ fontWeight: "bold", fontSize: 16 },
]}
>
{item.name}
</Text>
<Divider style={{ marginVertical: 5 }} />
<View style={{ flexDirection: "row" }}>
<Text
style={[
styles.defaultText,
{ fontWeight: "bold", flex: 2 },
]}
>
Total Payable Amount:
</Text>
<View style={{ flex: 1 }}>
<TextInput
value={billPaymentAmount[item.id]}
onChangeText={(value) =>
setBillPaymentAmount({
...billPaymentAmount,
[item.id]: value,
})
}
keyboardType={"numeric"}
mode={"outlined"}
label={"RM"}
dense={true}
/>
</View>
</View>
</View>
<BouncyCheckbox
disableBuiltInState
isChecked={selectedBill.includes(item.id)}
fillColor={"green"}
unfillColor={"#FFFFFF"}
onPress={() => {
if (selectedBill.includes(item.id)) {
setSelectedBill(
selectedBill.filter((value) => value !== item.id)
);
} else {
setSelectedBill([...new Set([...selectedBill, item.id])]);
}
}}
/>
</View>
);
}}
keyExtractor={(item) => item.id}
removeClippedSubviews={false}
/>
{
<>
<View
style={{
paddingVertical: 10,
paddingHorizontal: 20,
flexDirection: "row",
backgroundColor: "blue",
}}
>
<Text
style={{
color: "white",
flex: 1,
fontWeight: "bold",
fontSize: 18,
}}
>
Total Amount:{" "}
</Text>
<View>
<Text
style={{ color: "white", fontWeight: "bold", fontSize: 24 }}
>
RM {totalPaymentAmount.toFixed(2)}
</Text>
{totalPaymentAmount <= 0 ? null : (
<TouchableOpacity
onPress={() => {
//navigation.goBack();
navigation.goBack();
navigation.navigate("Account");
}}
>
<Text>Reset</Text>
</TouchableOpacity>
)}
</View>
</View>
<Button
mode={"contained"}
color={"limegreen"}
style={{
borderRadius: 5,
marginHorizontal: 20,
marginVertical: 10,
justifyContent: "center",
}}
labelStyle={{ color: "white", padding: 10 }}
uppercase={false}
onPress={() => {}}
disabled={totalPaymentAmount <= 0 ? true : false}
>
<Text>Pay Bill</Text>
</Button>
</>
}
</>
);
}
class Account extends Component {
constructor(props) {
super(props);
this._isMounted = false;
this.state = {};
}
render() {
return (
<>{<AccountMultiplePayment {...this.props} {...this.navigation} />}</>
);
}
}
export default Account;
const styles = StyleSheet.create({
flex: {
flex: 1,
},
headerTitle: {
alignItems: "center",
borderBottomLeftRadius: 25,
borderBottomRightRadius: 25,
paddingHorizontal: 20,
paddingVertical: 20,
},
subHeaderContainer: {
paddingVertical: 10,
paddingHorizontal: 20,
backgroundColor: "white",
borderRadius: 10,
elevation: 5,
marginVertical: 5,
marginHorizontal: 10,
},
subHeaderTitle: {
color: "white",
fontWeight: "bold",
fontSize: 16,
backgroundColor: "#2c1855",
padding: 10,
borderRadius: 10,
},
defaultText: {
color: "black",
},
});
Working example here - https://snack.expo.dev/#emmbyiringiro/971a0c
Related
First I want to tell you that my English is not too good so please compromise with me.
I am a beginner in React Native. I am working on project. In this project I am facing an issue. The issues is when I try to use FlatList or ScrollView to scroll the screen, the issue is irritating me. The half part of data is is disappeared. When I add color in FlatList it covers the half of the screen. I want to get rid off from this issue. I want that all the components should be show and when I want to scroll the screen the screen will easily scroll and no color disturb the content.
You can see the image here
const SignUp: FC = () => {
const data = [
{ key: 'Full Name', value: '' },
{ key: 'Email Address', value: '' },
{ key: 'Password', value: '' },
];
const [formData, setFormData] = useState(data);
const handleInputChange = (value, index) => {
const updatedFormData = [...formData];
updatedFormData[index].value = value;
setFormData(updatedFormData);
};
const renderItem = ({ item, index }) => (
<View style={styles.inputSetting}>
<Text style={styles.inputTxt}>{item.key}</Text>
<TextInput style={styles.input} value={item.value} onChangeText={(value) => handleInputChange(value, index)} />
</View>
);
return (
<SafeAreaView style={styles.bg}>
<View style={styles.imgSetting}>
<Image style={styles.img} source={require('../assets/WeHAP-1.png')} />
</View>
<View style={styles.SignUpSetting}>
<Text style={styles.createAccountTxt}>Create Account</Text>
<FlatList data={formData}
renderItem={renderItem}
keyExtractor={(item) => item.key}
/>
</View>
</SafeAreaView>
);
};
export default SignUp;
......Styling......
bg: {
backgroundColor: '#fff',
flex: 1,
}
SignUpSetting: {
backgroundColor: '#F2F2F2',
flex: 1,
borderTopLeftRadius: 40,
borderTopRightRadius: 40,
},
createAccountTxt: {
color: '#000',
fontSize: 25,
fontWeight: 'bold',
textAlign: 'center',
top: 40,
},
inputSetting: {
justifyContent: 'flex-start',
alignItems: 'flex-start',
top: 60,
left: 30,
margin: 5,
},
inputTxt: {
color: '#a1a1a1',
},
input: {
backgroundColor: '#fff',
borderRadius: 10,
paddingLeft: 15,
paddingRight: 250,
top: 5,
borderColor: '#229954',
borderWidth: 0.6,
},
I'm new to React native, I'm creating a online store app my problem is : when the person selects a repeated item it does not appear in the cart it just updates , I would like it to include and list in the cart this repeated item ... as I said I'm new to react native, but I believe the problem is in the listing and not in the register ...
Function add in cart in AddCart.js
const addToCart = async (id) => {
let itemArray = await AsyncStorage.getItem('cartItems');
itemArray = JSON.parse(itemArray);
if (itemArray) {
let array = itemArray;
array.push(id);
try {
await AsyncStorage.setItem('cartItems', JSON.stringify(array));
ToastAndroid.show(
'Item Added Successfully to cart',
ToastAndroid.SHORT,
);
navigation.navigate('Home');
} catch (error) {
return error;
}
} else {
let array = [];
array.push(id);
try {
await AsyncStorage.setItem('cartItems', JSON.stringify(array));
ToastAndroid.show(
'Item Added Successfully to cart',
ToastAndroid.SHORT,
);
navigation.navigate('Home');
} catch (error) {
return error;
}
}
};
MyCart.js
import React, {useState, useEffect} from 'react';
import {
View,
Text,
TouchableOpacity,
Image,
Alert
} from 'react-native';
import AsyncStorage from '#react-native-async-storage/async-storage';
const MyCart = ({navigation}) => {
const [product, setProduct] = useState();
useEffect(() => {
const unsubscribe = navigation.addListener('focus', () => {
getDataFromDB();
});
return unsubscribe;
}, [navigation]);
const getDataFromDB = async id =>{
let items = await AsyncStorage.getItem('cartItems');
items = JSON.parse(items);
if(items.length===0){
Alert.alert(
"Ops",
"The cart is empty",
[
{
text: "Ok",
onPress: () => navigation.navigate('Home'),
style: "cancel"
}
]
);
}else{
let productData = [];
if (items) {
Items.forEach(data => {
if (items.includes(data.id)) {
productData.push(data);
return;
}
});
setProduct(productData);
getTotal(productData);
} else {
setProduct(false);
getTotal(false);
}
}
};
const renderProducts = (data, index) => {
return (
<TouchableOpacity
key={data.key}
onPress={() => navigation.navigate('ProductInfo', {productID: data.id})}
style={{
width: '100%',
height: 100,
marginVertical: 6,
flexDirection: 'row',
alignItems: 'center',
}}>
<View
style={{
width: '30%',
height: 100,
padding: 14,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: COLOURS.backgroundLight,
borderRadius: 10,
marginRight: 22,
}}>
<Image
source={data.productImage}
style={{
width: '100%',
height: '100%',
resizeMode: 'contain',
}}
/>
</View>
<View
style={{
flex: 1,
height: '100%',
justifyContent: 'space-around',
}}>
<View style={{}}>
<Text
style={{
fontSize: 14,
maxWidth: '100%',
color: COLOURS.black,
fontWeight: '600',
letterSpacing: 1,
}}>
{data.productName},
</Text>
<View
style={{
marginTop: 4,
flexDirection: 'row',
alignItems: 'center',
opacity: 0.6,
}}>
<Text
style={{
fontSize: 14,
fontWeight: '400',
maxWidth: '85%',
marginRight: 4,
}}>
R$ {data.productPrice2}.00 , {data.id}
</Text>
<Text>
</Text>
</View>
</View>
<View
style={{
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
}}>
<View
style={{
flexDirection: 'row',
alignItems: 'center',
}}>
<View
style={{
borderRadius: 100,
marginRight: 20,
padding: 4,
borderWidth: 1,
borderColor: COLOURS.backgroundMedium,
opacity: 0.5,
}}>
<MaterialCommunityIcons
name="minus"
style={{
fontSize: 16,
color: COLOURS.backgroundDark,
}}
/>
</View>
<Text>1</Text>
<View
style={{
borderRadius: 100,
marginLeft: 20,
padding: 4,
borderWidth: 1,
borderColor: COLOURS.backgroundMedium,
opacity: 0.5,
}}>
<MaterialCommunityIcons
name="plus"
style={{
fontSize: 16,
color: COLOURS.backgroundDark,
}}
/>
</View>
</View>
<TouchableOpacity onPress={() => removeItemFromCart(data.id)}>
<MaterialCommunityIcons
name="delete-outline"
style={{
fontSize: 16,
color: COLOURS.backgroundDark,
backgroundColor: COLOURS.backgroundLight,
padding: 8,
borderRadius: 100,
}}
/>
</TouchableOpacity>
</View>
</View>
</TouchableOpacity>
);
};
return (
<View> {product ? product.map(renderProducts) : null} </View>
);
};
export default MyCart;
I would be grateful to help me
Good day guys, I've been stuck with react native, I have a withdrawal screen that navigates to transactionPin screen, I have a not so wonderful custom onScreen keyboard, that only accepts maximum of 4 input. I am checking if length equals 4, the verify function will trigger and perform any of the transfer or makeWithdraw, but it results in Maximum depth... looping, how do I rewrite this, please. Below is my code. I appreciate any help greatly.
withdrawScreen.js
import React, { Component } from "react";
import { Text, View, StyleSheet, SafeAreaView, StatusBar, Image, TouchableOpacity, ScrollView, TextInput, ActivityIndicator } from "react-native";
import { withNavigation } from "react-navigation";
import * as Yup from 'yup';
import { Colors, Sizes } from "../../constant/styles";
import { MaterialIcons, MaterialCommunityIcons, Feather } from '#expo/vector-icons';
import Swipeable from 'react-native-gesture-handler/Swipeable';
import AppForm from "../../component/appForm";
import AppFormField from "../../component/appFormField";
import AppButton from "../../component/appButton";
import dashApi from "../../api/dashApi";
import Loader from "../../component/Loader";
import TransactionPinScreen from "./transactionPinScreen";
const validationSchema = Yup.object().shape({
withdrawal_method: Yup.object().required('Select withdrawal method'),
authorization_mode: Yup.object().required('Select verification type')
});
const initialState = {
initialState: 0,
text: '',
withdrawalMethod: [{ label: 'Select withdrawal method', value: '-', disabled: true }],
authorizationMode: [{ label: 'Select authorization mode', value: '-', disabled: true }],
initialLoading: false,
withdrawMethodDesc: '',
verification: '',
withdrawalWindow: {},
}
class WithdrawScreen extends Component {
componentDidMount() {
this.getWithdrawalData();
}
componentWillUnmount() {
this.setState(initialState);
}
constructor(props) {
super(props);
this.state = initialState;
// this.makeWithdraw = this.makeWithdraw.bind(this);
};
getWithdrawalData = async () => {
this.setState({ initialLoading: true });
const result = await dashApi.withdrawalData();
if (result.status == 200) {
let withdrawalMethod = [];
let authorizationMode = [];
result.data.withdrawal_method.map(e => withdrawalMethod.push({ label: e.name, value: e.name, ...e }));
result.data.authorization_mode.map(e => authorizationMode.push({ label: e.text, ...e }));
this.setState({ initialLoading: false });
this.setState({ withdrawalMethod: [...this.state.withdrawalMethod, ...withdrawalMethod] });
this.setState({ authorizationMode: [...this.state.authorizationMode, ...authorizationMode] });
this.setState({ withdrawalWindow: result.data.withdrawal_window })
}
else if (result.status == 401) {
this.setState({ errorText: result.data.message });
this.setState({ initialLoading: false });
}
else {
this.setState({ initialLoading: false });
this.setState({ errorText: 'Network Error' })
}
};
onPress1 = () => {
this.setState({ text: this.state.text + '1' })
}
onPress2 = () => {
this.setState({ text: this.state.text + '2' })
}
onPress3 = () => {
this.setState({ text: this.state.text + '3' })
}
onPress4 = () => {
this.setState({ text: this.state.text + '4' })
}
onPress5 = () => {
this.setState({ text: this.state.text + '5' })
}
onPress6 = () => {
this.setState({ text: this.state.text + '6' })
}
onPress7 = () => {
this.setState({ text: this.state.text + '7' })
}
onPress8 = () => {
this.setState({ text: this.state.text + '8' })
}
onPress9 = () => {
this.setState({ text: this.state.text + '9' })
}
onPress0 = () => {
this.setState({ text: this.state.text + '0' })
}
onPressDecimal = () => {
this.setState({ text: this.state.text + '.' })
}
onPressBackspace = () => {
let text = this.state.text.slice(0, this.state.text.length - 1);
this.setState({ text: text })
}
render() {
return (
<SafeAreaView style={styles.screenContainer}>
<StatusBar backgroundColor={Colors.backgroundColor} barStyle="dark-content" />
<View>
{this.header()}
<ScrollView showsVerticalScrollIndicator={false}
showsHorizontalScrollIndicator={false} style={{ marginBottom: 50 }}>
{this.state.initialState == 0 ?
<View>
{this.withdrawalMethod()}
<Loader loading={this.state.initialLoading} />
</View>
:
<View>
{this.transferDetCard()}
{this.inputAmountLine()}
{this.buttonKeyboardMode()}
{this.swiper()}
</View>
}
</ScrollView>
</View>
</SafeAreaView>
)
}
header() {
return (
<View>
<View style={[styles.flex, { alignItems: 'center' }]}>
<TouchableOpacity style={[styles.flex, { justifyContent: 'center', alignItems: 'center' }]} onPress={() => this.props.navigation.goBack()}>
<MaterialIcons name="keyboard-arrow-left" size={35} color="black" />
<Text style={styles.textStyle}>Withdraw</Text>
</TouchableOpacity>
</View>
</View>
)
}
transferDetCard() {
return (
<View style={[styles.trnsferDetCard, styles.flex]}>
<View style={styles.flex}>
<Image source={require('../../assets/images/dashboard/avatar.jpg')} style={styles.userImage} />
<View style={{ paddingHorizontal: 15, alignSelf: 'center' }}>
<Text style={{ fontWeight: '700', fontSize: 20, lineHeight: 24 }}>Ann</Text>
<View style={[styles.flex, { alignItems: 'center' }]}>
<Feather name="credit-card" size={24} color="black" />
<View style={[styles.flex, { alignItems: 'center', paddingHorizontal: 7 }]}>
<Image source={require('../../assets/images/dashboard/ellipsisFour.png')} style={{ tintColor: 'black' }} />
<Text style={{ paddingHorizontal: 7 }}>
6301
</Text>
</View>
</View>
</View>
</View>
<View style={{ alignSelf: 'center' }}>
<MaterialIcons name="keyboard-arrow-down" size={35} color="black" />
</View>
</View>
)
}
inputAmountLine() {
return (
<View style={styles.inputAmount}>
<Text style={this.state.text != '' ? [{ left: 5 }, styles.inputIcon] : [{ left: 110 }, styles.inputIcon]}>₦</Text>
<TextInput
style={this.state.text != '' ? [styles.input, { width: '90%' }] : [{ width: '100%' }, styles.input]}
placeholder="0.00"
value={this.state.text}
underlineColorAndroid="transparent"
placeholderTextColor={'#E5E5E5'}
showSoftInputOnFocus={false}
autoFocus
caretHidden={true}
/>
</View>
)
}
buttonKeyboardMode() {
return (
<View style={{ padding: 20 }}>
<View style={[styles.flex, { marginBottom: 15 }]}>
<TouchableOpacity style={styles.keys} onPress={this.onPress1}>
<Text style={{ fontSize: 30, fontWeight: 'bold' }}>1</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.keys} onPress={this.onPress2}>
<Text style={{ fontSize: 30, fontWeight: 'bold' }}>2</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.keys} onPress={this.onPress3}>
<Text style={{ fontSize: 30, fontWeight: 'bold' }}>3</Text>
</TouchableOpacity>
</View>
<View style={[styles.flex, { marginBottom: 15 }]}>
<TouchableOpacity style={styles.keys} onPress={this.onPress4}>
<Text style={{ fontSize: 30, fontWeight: 'bold' }}>4</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.keys} onPress={this.onPress5}>
<Text style={{ fontSize: 30, fontWeight: 'bold' }}>5</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.keys} onPress={this.onPress6}>
<Text style={{ fontSize: 30, fontWeight: 'bold' }}>6</Text>
</TouchableOpacity>
</View>
<View style={[styles.flex, { marginBottom: 15 }]} onPress={this.onPress7}>
<TouchableOpacity style={styles.keys} onPress={this.onPress7}>
<Text style={{ fontSize: 30, fontWeight: 'bold' }}>7</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.keys} onPress={this.onPress8}>
<Text style={{ fontSize: 30, fontWeight: 'bold' }}>8</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.keys} onPress={this.onPress9}>
<Text style={{ fontSize: 30, fontWeight: 'bold' }}>9</Text>
</TouchableOpacity>
</View>
<View style={[styles.flex, { marginBottom: 15 }]}>
<TouchableOpacity style={styles.keys} onPress={this.onPressDecimal}>
<Text style={{ fontSize: 30, fontWeight: 'bold' }}>.</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.keys} onPress={this.onPress0}>
<Text style={{ fontSize: 30, fontWeight: 'bold' }}>0</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.keys} onPress={this.onPressBackspace}>
<Feather name="delete" size={24} color="black" />
</TouchableOpacity>
</View>
</View>
)
}
swiper() {
const LeftSwipeActions = () => {
return (
<View
style={{
flex: 1, backgroundColor: '#fff7da',
borderRadius: 35, justifyContent: 'center'
}}
>
</View>
);
};
const swipeFromLeftOpen = () => {
this.props.navigation.navigate('TransactionPin', { withdraw_method: this.state.withdrawMethodDesc.id, verification: this.state.verification.value, amount: this.state.text, window_status: this.state.withdrawalWindow.status, type: "withdraw" });
this.setState({ initialState: false });
};
let color = '';
return (
<Swipeable
renderLeftActions={LeftSwipeActions}
onSwipeableLeftWillOpen={swipeFromLeftOpen}
>
<View
style={{
backgroundColor: color == '' ? '#fff7da' : color,
borderRadius: 35,
flex: 0,
flexDirection: 'row',
alignItems: 'center'
}}
>
<View style={[styles.flex, styles.yellowSwiper]}>
<Image source={require('../../assets/images/dashboard/Rectangle431.png')} />
<Image source={require('../../assets/images/dashboard/Rectangle432.png')} />
<Image source={require('../../assets/images/dashboard/Rectangle433.png')} />
</View>
<Text style={{ fontSize: 20, fontWeight: 'bold', textTransform: 'uppercase', left: 50 }}>
Swipe to pay
</Text>
</View>
</Swipeable>
)
}
withdrawalMethod() {
return (
<View style={{ flex: 0, height: 570.40, backgroundColor: Colors.backgroundColor, margin: Sizes.fixPadding * 1.0, borderRadius: 20 }}>
<View style={{ padding: Sizes.fixPadding * 6.0 }}>
<Text style={styles.title}>
Select a Withdrawal Method
</Text>
</View>
<View>
<AppForm initialValues={{ withdrawal_method: '', authorization_mode: '' }} onSubmit={() => this.setState({ initialState: 1 })} validationSchema={validationSchema}>
<AppFormField dropDown={true} textValue={'Withdrawal Method'} name="withdrawal_method"
items={this.state.withdrawalMethod}
defaultValue={'-'}
disabled={this.state.initialLoading ? true : false}
onChange={(e) => this.setState({ withdrawMethodDesc: e })}
containerStyle={{ height: 60 }}
style={{ backgroundColor: Colors.backgroundColor, borderColor: '#adadad' }}
itemStyle={{
justifyContent: 'flex-start'
}}
dropDownStyle={{ backgroundColor: '#fafafa' }}
/>
{
this.state.withdrawMethodDesc != '' ?
<Text style={styles.methodDescription}>
Withdrawal Limit: {this.state.withdrawMethodDesc.min_limit} - {this.state.withdrawMethodDesc.max_limit} NGN,{'\n'}
Charge: {this.state.withdrawMethodDesc.charge} NGN
</Text>
:
null
}
<AppFormField dropDown={true} textValue={'Authorization mode'} name="authorization_mode"
items={this.state.authorizationMode}
defaultValue={'-'}
disabled={this.state.initialLoading ? true : false}
onChange={(e) => this.setState({ verification: e })}
containerStyle={{ height: 60 }}
style={{ backgroundColor: Colors.backgroundColor, borderColor: '#adadad' }}
itemStyle={{
justifyContent: 'flex-start'
}}
dropDownStyle={{ backgroundColor: '#fafafa' }}
/>
<AppButton text={'proceed'} />
</AppForm>
</View>
</View>
)
}
}
WithdrawScreen.navigationOptions = () => {
return {
header: () => null
}
}
export default withNavigation(WithdrawScreen);
const styles = StyleSheet.create({
flex: {
flex: 0,
flexDirection: 'row',
justifyContent: 'space-between'
},
trnsferDetCard: {
justifyContent: 'center',
backgroundColor: '#f4f2f6',
borderRadius: 20,
paddingVertical: 10,
paddingHorizontal: 20,
width: '100%',
height: 100,
marginVertical: 10,
},
screenContainer: {
flex: 1,
padding: 5,
backgroundColor: 'white'
},
textStyle: {
fontSize: 34,
fontWeight: 'bold',
color: '#476355'
},
userImage: { height: 70, width: 70, borderRadius: 27 },
inputAmount: {
flex: 0,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#fff',
},
inputIcon: {
color: "#E5E5E5",
fontSize: 45,
fontWeight: '600',
zIndex: 1
},
input:
{
height: 70,
borderBottomWidth: 1,
borderBottomColor: '#E5E5E5',
textAlign: 'center',
fontSize: 50,
fontWeight: '700',
textDecorationLine: 'none'
}
,
yellowSwiper: { width: 70, height: 70, borderRadius: 70, backgroundColor: '#fdd544', lineHeight: 70, alignItems: 'center', justifyContent: 'space-around', padding: 10 },
keys: { height: 71, width: 71, borderRadius: 71, borderWidth: 1, justifyContent: 'center', alignItems: 'center', borderColor: '#f4f6f5' },
title: { fontSize: 16, fontWeight: '500' },
methodDescription: {
color: Colors.dangerColor,
marginTop: -25,
paddingHorizontal: 20,
marginBottom: 35,
lineHeight: 25,
}
});
And this is the transactionPin screen
transactionPinScreen.js
import React, { Component } from "react";
import { Image, Text, View, StyleSheet, SafeAreaView, StatusBar, TouchableOpacity, TextInput, Dimensions, BackHandler } from "react-native";
import { withNavigation } from "react-navigation";
import { MaterialIcons, Feather } from '#expo/vector-icons';
import { Colors, Fonts, Sizes } from "../../constant/styles";
import TransferComplete from "../../component/transferComplete";
import dashApi from "../../api/dashApi";
import toast from "../../component/toaster";
import Loader from "../../component/Loader";
const { height, width } = Dimensions.get('screen');
let processing = false;
class TransactionPinScreen extends Component {
componentDidMount() {
BackHandler.addEventListener('hardwareBackPress', this.handleBackButton.bind(this));
}
componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress', this.handleBackButton.bind(this));
}
componentDidUpdate(prevProps) {
if (this.state.text.length == 4) {
(this.state.text)
? this.verify()
: console.log("Focused");
}
}
handleBackButton = () => {
this.props.navigation.pop();
return true;
};
onPress1 = () => {
this.pin('1')
}
onPress2 = () => {
this.pin('2')
}
onPress3 = () => {
this.pin('3')
}
onPress4 = () => {
this.pin('4')
}
onPress5 = () => {
this.pin('5')
}
onPress6 = () => {
this.pin('6')
}
onPress7 = () => {
this.pin('7')
}
onPress8 = () => {
this.pin('8')
}
onPress9 = () => {
this.pin('9')
}
onPress0 = () => {
this.pin('0')
}
onPressBackspace = () => {
let text = this.state.text.slice(0, this.state.text.length - 1);
this.setState({ text: text })
}
pin(val) {
this.state.text.length != 4 ? this.setState({ text: this.state.text + val }) : null;
}
constructor(props) {
super(props)
this.state = {
text: '',
completeScreen: false,
processing: processing ?? false,
};
this.verify = this.verify.bind(this)
}
verify = () => {
// For Withdrawal code is 2, Transfer is 1;
var pinLenght = this.state.text.length;
// console.log(pinLenght, this.state.text, this.props.navigation.state.params);
if (pinLenght == 4) {
console.log(this.state.text);
const data = {
...this.props.navigation.state.params ?? null,
pin: this.state.text,
}
data.type == 'withdraw' ? this.makeWithdraw(data)
: this.transfer(data);
}
}
makeWithdraw = async (data) => {
console.log('prod');
this.setState({ processing: true });
const result = await dashApi.withdrawal(data);
if (result.status == 200) {
this.setState({ processing: false });
this.setState({ completeScreen: 1 });
}
else if (result.status == 401 || result.data.data == null) {
// this.setState({ errorText: result.data.message });
toast('red', result.data.message);
this.setState({ processing: false });
}
else {
this.setState({ processing: false });
// this.setState({ errorText: 'Network Error' })
}
console.log(result);
}
transfer = async (data) => {
// this.setState({ processing: true });
const result = await dashApi.transfer(data);
let output;
if (result.status == 200) {
// output = {success: 200};
this.setState({ processing: false });
this.setState({ completeScreen: 1 });
}
else if (result.status == 401) {
// output = {error: result.data.message};
this.setState({ outputText: { error: result.data.message } });
this.setState({ processing: false });
}
else if (result.status == 422) {
// output = {error: result.data.message}
this.setState({ outputText: 'Network output' })
}
let finale = { output: output }
console.log(finale, result);
return finale;
}
render() {
return (
<View>
<SafeAreaView style={this.state.completeScreen == true ? [{ backgroundColor: 'white', flex: 1, alignSelf: "center", alignItems: 'center' }] : styles.screenContainer}>
<StatusBar backgroundColor={Colors.backgroundColor} barStyle="dark-content" />
{
this.state.completeScreen == false ?
<View>
{this.iconText()}
{this.buttonKeyboardMode()}
</View>
:
<View>
<TransferComplete showing={true} onPress={() => this.props.navigation.navigate('Dashboard')} buttonText="Done" subtitle="Your transaction is processing. Payment is usually completed within a minute." />
</View>
}
</SafeAreaView>
</View>
)
}
iconText() {
return (
<View style={{ justifyContent: 'center', alignItems: 'center', paddingTop: 50 }}>
<Image source={require('../../assets/images/dashboard/fingerPrint.png')} style={styles.fingerTip} />
<Text>enter pin code or use fingerprint</Text>
<Loader loading={this.state.processing} />
<View style={styles.searchSection}>
<TouchableOpacity style={styles.searchIcon} onPress={() => this.onPressBackspace()} >
<MaterialIcons name="backspace" size={24} color="black" />
</TouchableOpacity>
<TextInput
style={styles.input}
value={this.state.text}
secureTextEntry
// onChange={() => this.verify()}
maxLength={4}
underlineColorAndroid="transparent"
showSoftInputOnFocus={false}
autoFocus
caretHidden={true}
/>
</View>
</View>
)
}
buttonKeyboardMode() {
return (
<View style={{ paddingHorizontal: 40, paddingTop: 20, paddingBottom: 50 }}>
<View style={[styles.flex, { marginBottom: 15 }]}>
<TouchableOpacity style={styles.keys} onPress={this.onPress1}>
<Text style={{ fontSize: 30, fontWeight: 'bold' }}>1</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.keys} onPress={this.onPress2}>
<Text style={{ fontSize: 30, fontWeight: 'bold' }}>2</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.keys} onPress={this.onPress3}>
<Text style={{ fontSize: 30, fontWeight: 'bold' }}>3</Text>
</TouchableOpacity>
</View>
<View style={[styles.flex, { marginBottom: 15 }]}>
<TouchableOpacity style={styles.keys} onPress={this.onPress4}>
<Text style={{ fontSize: 30, fontWeight: 'bold' }}>4</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.keys} onPress={this.onPress5}>
<Text style={{ fontSize: 30, fontWeight: 'bold' }}>5</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.keys} onPress={this.onPress6}>
<Text style={{ fontSize: 30, fontWeight: 'bold' }}>6</Text>
</TouchableOpacity>
</View>
<View style={[styles.flex, { marginBottom: 15 }]} >
<TouchableOpacity style={styles.keys} onPress={this.onPress7}>
<Text style={{ fontSize: 30, fontWeight: 'bold' }}>7</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.keys} onPress={this.onPress8}>
<Text style={{ fontSize: 30, fontWeight: 'bold' }}>8</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.keys} onPress={this.onPress9}>
<Text style={{ fontSize: 30, fontWeight: 'bold' }}>9</Text>
</TouchableOpacity>
</View>
<View style={[styles.flex, { marginBottom: 15, alignSelf: 'center' }]}>
<TouchableOpacity style={styles.keys} onPress={this.onPress0}>
<Text style={{ fontSize: 30, fontWeight: 'bold' }}>0</Text>
</TouchableOpacity>
</View>
</View>
)
}
completeScreen() {
// console.log(height, width);
return (
<View style={[styles.flex, { justifyContent: 'center', top: 250 }]}>
<View style={{ width: 100, height: 100, borderRadius: 100, backgroundColor: 'yellow', justifyContent: 'center', alignItems: 'center' }}>
<MaterialIcons name="check" size={80} color="white" />
</View>
</View>
)
}
export default withNavigation(TransactionPinScreen);
const styles = StyleSheet.create({
flex: {
flex: 0,
flexDirection: 'row',
justifyContent: 'space-between'
},
screenContainer: {
flex: 0,
padding: 5,
backgroundColor: 'white',
},
fingerTip: { tintColor: '#83968c', width: 58.37, height: 56.73, marginBottom: 45.7 },
searchSection: {
flex: 0,
flexDirection: 'row',
alignItems: 'center',
backgroundColor: '#fff',
marginVertical: 20,
},
searchIcon: {
position: 'absolute',
left: 240,
zIndex: 1
},
input:
{ width: 284, borderRadius: 10, backgroundColor: '#f7f7f7', textAlign: 'center', fontSize: 50, fontWeight: '700' }
,
keys: { height: 71, width: 71, borderRadius: 71, borderWidth: 1, justifyContent: 'center', alignItems: 'center', borderColor: '#f4f6f5' },
});
I'm using react native. The images are in svg, so I'm using "react-native-svg" library. The images are working normally in the web, but when I try to show in mobile appear this crazy error:
Expected closing tag </head> to match opening tag <meta> (6:4). If this is valid SVG, it's probably a bug. Please raise an issue
</head>
^
Here where I'm trying to show the images:
<View style={styles.itemsContainer}>
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
contentContainerStyle={{paddingHorizontal: 20}}
>
{items.map(item => (
<TouchableOpacity
key={String(item.id)}
style={[
styles.item,
selectedItems.includes(item.id) ? styles.selectedItem : {}
]}
onPress={() => handleSelectItem(item.id)}
activeOpacity={0.6}
>
<SvgUri width={42} height={42} uri={item.image_url}/>
<Text style={styles.itemTitle}>{item.name}</Text>
</TouchableOpacity>
))}
</ScrollView>
</View>
This is the entire code:
import React, {useState, useEffect} from 'react'
import {View, StyleSheet, TouchableOpacity, Text, ScrollView, Image, Alert} from "react-native";
import {Feather as Icon} from '#expo/vector-icons';
import {useNavigation, useRoute} from '#react-navigation/native';
import Constants from 'expo-constants';
import api from '../../services/api';
import MapView, {Marker} from 'react-native-maps';
import {SvgUri} from 'react-native-svg';
import * as Location from 'expo-location';
interface Item {
id: number;
name: string;
image_url: string
}
interface Point {
id: number;
name: string;
image: string;
latitude: number;
longitude:number;
image_url: string;
}
interface Params {
uf: string,
city: string,
}
const Points = () => {
const navigation = useNavigation();
const [items, setItems] = useState<Item[]>([]);
const [selectedItems, setSelectedItems] = useState<number[]>([]);
const [initialPosition, setInitialPosition] = useState<[number, number]>([0, 0]);
const [points, setPoints] = useState<Point[]>([]);
const route = useRoute();
const routeParams = route.params as Params;
useEffect(() => {
api.get('items').then(response => {
setItems(response.data);
});
}, []);
useEffect(() => {
async function loadPosition() {
const { status } = await Location.requestPermissionsAsync();
if (status !== 'granted') {
Alert.alert('Oooops...', 'precisamos de sua permissão para mostrarmos sua localização');
return ;
}
const location = await Location.getCurrentPositionAsync();
const { latitude, longitude } = location.coords;
setInitialPosition([
latitude,
longitude
]);
}
loadPosition();
}, []);
useEffect(() => {
api.get('points', {
params: {
city: routeParams.city,
uf: routeParams.uf,
items: selectedItems,
},
}).then((response) => {
setPoints(response.data)
})
}, [selectedItems]);
function handleNavigateBack() {
navigation.goBack();
}
function handleNavigateToDetail(id: number) {
navigation.navigate('Detail', { point_id: id})
}
function handleSelectItem(id: number) {
const alreadySelected = selectedItems.findIndex(item => item === id );
if (alreadySelected >= 0) {
const filteredItems = selectedItems.filter(item => item !== id);
setSelectedItems(filteredItems)
} else {
setSelectedItems([...selectedItems, id])
}
}
return (
<>
< View style={styles.container}>
<TouchableOpacity onPress={handleNavigateBack}>
<Icon name="arrow-left" size={20} color="#34cb79"/>
</TouchableOpacity>
<Text style={styles.title}>Bem Vindo.</Text>
<Text style={styles.description}>Encontre no mapa um ponto de coleta</Text>
<View style={styles.mapContainer}>
{ initialPosition[0] !== 0 && (
<MapView
style={styles.map}
loadingEnabled={initialPosition[0] === 0}
initialRegion={{
latitude: initialPosition[0],
longitude: initialPosition[1],
latitudeDelta: 0.014,
longitudeDelta: 0.014 ,
}} >
{points.map(point => (
<Marker
key={String(point.id)}
style={styles.mapMarker}
onPress={() => handleNavigateToDetail(point.id)}
coordinate={{
latitude: point.latitude,
longitude: point.longitude,
}}>
<View style={styles.mapMarkerContainer}>
<Image style={styles.mapMarkerImage} source={{uri: point.image_url}}/>
<Text style={styles.mapMarkerTitle}>{point.name}</Text>
</View>
</Marker>
))}
</MapView>
) }
</View>
</View>
<View style={styles.itemsContainer}>
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
contentContainerStyle={{paddingHorizontal: 20}}
>
{items.map(item => (
<TouchableOpacity
key={String(item.id)}
style={[
styles.item,
selectedItems.includes(item.id) ? styles.selectedItem : {}
]}
onPress={() => handleSelectItem(item.id)}
activeOpacity={0.6}
>
<SvgUri width={42} height={42} uri={item.image_url}/>
<Text style={styles.itemTitle}>{item.name}</Text>
</TouchableOpacity>
))}
</ScrollView>
</View>
</>
)
};
const styles = StyleSheet.create({
container: {
flex: 1,
paddingHorizontal: 32,
paddingTop: 20 + Constants.statusBarHeight,
},
title: {
fontSize: 20,
fontFamily: 'Ubuntu_700Bold',
marginTop: 24,
},
description: {
color: '#6C6C80',
fontSize: 16,
marginTop: 4,
fontFamily: 'Roboto_400Regular',
},
mapContainer: {
flex: 1,
width: '100%',
borderRadius: 10,
overflow: 'hidden',
marginTop: 16,
},
map: {
width: '100%',
height: '100%',
},
mapMarker: {
width: 90,
height: 80,
},
mapMarkerContainer: {
width: 90,
height: 70,
backgroundColor: '#34CB79',
flexDirection: 'column',
borderRadius: 8,
overflow: 'hidden',
alignItems: 'center'
},
mapMarkerImage: {
width: 90,
height: 45,
resizeMode: 'cover',
},
mapMarkerTitle: {
flex: 1,
fontFamily: 'Roboto_400Regular',
color: '#FFF',
fontSize: 13,
lineHeight: 23,
},
itemsContainer: {
flexDirection: 'row',
marginTop: 16,
marginBottom: 32,
},
item: {
backgroundColor: '#fff',
borderWidth: 2,
borderColor: '#eee',
height: 120,
width: 120,
borderRadius: 8,
paddingHorizontal: 16,
paddingTop: 20,
paddingBottom: 16,
marginRight: 8,
alignItems: 'center',
justifyContent: 'space-between',
textAlign: 'center',
},
selectedItem: {
borderColor: '#34CB79',
borderWidth: 2,
},
itemTitle: {
fontFamily: 'Roboto_400Regular',
textAlign: 'center',
fontSize: 13,
},
});
export default Points;
i need your helps.
I have a functional based component call WelcomeSlidePage. I want to pass a functional to the functional component. i try to console.log the function in functional component, in the first state, console.log is printing the function, but after the second state, it's becomes undefine.
this is my component that calling the functional component
WebViewPage.jsx
<Modal transparent={true} visible={this.state.WelcomeSlidePageModal} animationType="
<WelcomeSlidePage onDone={()=>{console.log('test bro');this.setState({WelcomeSlidePageModal:false})}}/>
</Modal>
and this is my functional component
WelcomeSlidePage.jsx
import React, { useState, useEffect } from 'react';
import { StyleSheet, View, Text, Image, TouchableOpacity } from 'react-native';
import AppIntroSlider from 'react-native-app-intro-slider';
import string from '../string'
import { _storeData, _getData } from '../components/StoreAsync';
export default WelcomeSlide = (props) => {
const [language, setLanguage] = useState('english');
const [showRealApp, setShowRealApp] = useState(false);
const welcomeSlide = string.welcome_slide[language]
useEffect(() => {
console.log('testing bro',props.onDone)
// getData();
});
async function getData() {
setLanguage( await _getData("language"));
setShowRealApp( await _getData("showRealApp"));
}
_renderItem = ({ item }) => {
switch (item.key) {
case ('k4'):
return (
<View style={{backgroundColor : '#a0c83a', flex: 1}}>
<Text style={styles.title}>{item.title}</Text>
<View style={{justifyContent: 'center', paddingHorizontal: 20, flex: 1}}>
<Text style={styles.text}>{item.text_4_a}</Text>
<View style={{flexDirection: 'row'}}>
<Image style={styles.icon} source={item.icon} />
<Text style={{paddingStart: 5, paddingEnd: 20, ...styles.text}}>{item.text_4_b}</Text>
</View>
<Text style={styles.text}>{item.text_4_c}</Text>
<View style={{flexDirection: 'row'}}>
<Image style={styles.icon} source={item.icon} />
<Text style={{paddingStart: 5, paddingEnd: 20, ...styles.text}}>{item.text_4_d}</Text>
</View>
</View>
</View>
);
case ('k5'):
return (
<View style={styles.slide}>
<Text style={styles.title}>{item.text_5}</Text>
<TouchableOpacity style={{marginVertical: 24}} onPress={()=>{ props.navigation.navigate('WebView', { url: string.onboarding[language].login_url }); }}>
<Text style={styles.button}>{item.text_5_btn1}</Text>
</TouchableOpacity>
<TouchableOpacity style={{marginVertical: 24}} onPress={()=>{ props.navigation.navigate('WebView', { url: string.onboarding[language].register_url }); }}>
<Text style={styles.button}>{item.text_5_btn2}</Text>
</TouchableOpacity>
</View>
);
default:
return (
<View style={styles.slide}>
<Text style={styles.title}>{item.title}</Text>
<Image style={styles.image} source={item.image} />
<Text style={{paddingHorizontal: 20, ...styles.text}}>{item.text}</Text>
</View>
);
}
}
_onDone = () => {
setShowRealApp(true);
_storeData('isPassSlide',true);
props.navigation.navigate('WebView', { url: string.onboarding[language].login_url,splashScreen:false });
}
const slides = [
{
key: 'k1',
title: welcomeSlide.title,
text: welcomeSlide.a,
image: require('../images/my_library_card_white_notext_nopadding.png'),
backgroundColor: '#a0c83a',
},
{
key: 'k2',
title: welcomeSlide.title,
text: welcomeSlide.b,
image: require('../images/my_account_white_notext_nopadding.png'),
backgroundColor: '#a0c83a',
},
{
key: 'k3',
title: welcomeSlide.title,
text: welcomeSlide.c,
image: require('../images/library_catalog_white_notext_nopadding.png'),
backgroundColor:'#a0c83a',
},
{
key: 'k4',
title: welcomeSlide.title,
text_4_a: welcomeSlide.d_a,
text_4_b: welcomeSlide.d_b,
text_4_c: welcomeSlide.d_c,
text_4_d: welcomeSlide.d_d,
icon: require('../images/icon-hand-right.png'),
backgroundColor: '#a0c83a',
},
{
key: 'k5',
text_5: welcomeSlide.e,
text_5_btn1: welcomeSlide.e_btn1,
text_5_btn2: welcomeSlide.e_btn2,
backgroundColor:'#a0c83a',
},
];
return(
<AppIntroSlider
renderItem={_renderItem}
prevLabel={string.back[language]}
nextLabel={string.next[language]}
doneLabel={string.next[language]}
showPrevButton={true}
slides={slides}
onDone={()=>props.onDone()}/>
)
}
const styles = StyleSheet.create({
slide : {
flex: 1,
paddingTop: (Platform.OS) === 'ios' ? 20 : 0,
paddingBottom: 80,
backgroundColor : '#a0c83a',
alignItems: 'center',
},
title: {
fontSize: 24,
color: '#fff',
fontWeight: 'bold',
textAlign: 'center',
marginTop : 30,
},
text: {
fontSize : 20,
color: '#fff',
textAlign: 'left',
},
image: {
width: 200,
height: 200,
resizeMode: 'contain',
flex:1,
},
icon: {
top: 10,
width: 25,
height: 15,
width: 25,
marginTop: -3,
},
content: {
paddingHorizontal: 20,
},
button: {
borderRadius: 8,
paddingVertical: 12,
paddingHorizontal: 12,
color: 'white',
fontSize: 24,
fontWeight: 'bold',
textAlign: 'center',
marginHorizontal: 40,
backgroundColor: '#e46825',
shadowColor: '#000',
shadowOffset: { width: 0, height: 1 },
shadowOpacity: 0.8,
shadowRadius: 2,
elevation: 5,
},
});
and then this is the console log
testing bro function onDone() {
console.log('test bro');
_this2.setState({
WelcomeSlidePageModal: false
});
} b11b05fa-4e76-41da-9d58-218edc178e45:157683:15
testing bro undefined
please help me guys, thanks