Disable back button while opening Paypal webview in React Native App - react-native

I have a Webview from react-native-webview which open to Paypal's payment url. This is my code :
const PaypalWebview = ({ route }) => {
const url = route?.params.url ?? '';
const { setCartPaymentSuccess } = cart.actions;
const dispatch = useDispatch();
const insets = useSafeAreaInsets();
const cancel = () => {
goBack();
BottomMsgService.showMessage("Payment canceled")
}
const handleUrlChange = ({ url }) => {
console.log(url);
if (url.includes('finish')) {
dispatch(setCartPaymentSuccess());
navigate('ResultScreen');
return false
}
else return true
}
return (
<View style={{ flex: 1, backgroundColor: 'white' }}>
<View style={{ width: '100%', height: insets.top / 1.5, }}></View>
<View style={{
flexDirection: 'row', width: '100%', height: 60, alignItems: 'center'
}}>
<Pressable hitSlop={8} onPress={cancel}>
<Icon type="antdesign" name="close" size={14} color={'black'}
style={{ marginLeft: 20 }}
/>
</Pressable>
</View>
<WebView
style={{ flexGrow: 1, flexBasis: 1 }}
//onNavigationStateChange={handleUrlChange}
onShouldStartLoadWithRequest={handleUrlChange}
source={{ uri: url }}
/>
</View>
)
}
You can see I have a back button which go back to previous screen if user want to cancel payment. What I want to achieve is when user press "Continue" button in the webview (to proceed payment), the back button will be disabled (prevent user going back while payment is processing, image below ).I don't know if Paypal button can send any event to my app so the app can listen the event and make the back button disable. Anyone can give me some solutions? Thanks.

"Continue" does not confirm the payment, there is supposed to be an order review step before capture. If you intend to capture immediately on return you should correct your integration to make the PayPal button's verbiage say "Pay Now". This correction is much more important than worrying about the back button, which should be able to stay as it is and function normally (there's no trigger to change it anyway other than the return URI itself loading, which might then be able to disable the back button initially if you actually needed it to)
If using the v2/checkout/orders API, the parameter to set in the order creation request body is application_context.user_action to PAY_NOW; other integration methods/APIs will have an equivalent parameter.

Related

How to display a button at the bottom of a Webview in react-native?

Inside my component (PrivacyPolicy.js), i have a header view, a webview, and a footer view. the webview, depending on the size, gets scrollable. my issue is that the footer view is displayed at the bottom of the screen like if its style was "position: 'absolute'" so it keeps displayed while scrolling. I need to have it after all webview is displayed.
<View style={styles.main_container}>
<View style={styles.header_container}>
...
</View>
<WebView originWhitelist={['*']} source={{ html: privacyPolicyContent }}/>
<View style={styles.footer_container}>
<CheckBox
disabled={false}
value={this.state.isChecked}
onValueChange={(newValue) => this.setState({
isChecked: newValue
})}
style={styles.checkbox}
tintColors={{ true: '#157dfa' }}
/>
<Text style={styles.checkbox_text}>I have read and accept the Privacy Polic</Text>
</View>
</View>
My styles:
const styles = StyleSheet.create({
main_container: {
flex: 1,
paddingHorizontal:'5%'
},
header_container: {
height: scale(90),
flexDirection: 'row',
marginLeft: 10
},
checkbox_container: {
flexDirection: 'row'
},
checkbox: {
marginLeft: -5,
},
checkbox_text: {
marginTop: 8,
fontSize: 10
}
})
I can see few suggestions:
Since your button is a React Native Button => You can show/hide based on the scrollY positions. For that, you need to communicate over the Bridge to dispatch an event accordingly.
As an alternative solution => You can create the button on the Webview its self to have the same functionality.

React-Native: Passing functions in props.navigation.navigate("XYZScreen", myFunction())

in my react-native application, there are two screens. I want to navigate from one screen to another such that if I press a button in the next screen, the first screen should be refreshed using a method doRefreshing() in the first screen.
Example:
const FirstScreen = (props) => {
const doRefreshing = () => {
...
};
return (
<View>
<TouchableOpacity
onPress={()=>props.navigation.navigate("secondScreen",doRefreshing())}
>
</TouchableOpacity>
</View>
);
}
The example code of second screen:
const SecondScreen = (props) => {
const doRefreshingInFirstScreen = () => {
/** What should I do here? */
};
return (
<View>
<Button
onPress={()=>doRefreshingInFirstScreen()}
>
</Button>
</View>
);
}
Can someone please tell me how shall I refresh the first screen when the button in second screen is pressed and call goes to doRefreshingInFirstScreen()? Or what else I can do to refresh the first screen upon clicking the button in the second screen? Will be really grateful for this help. Thanks in advance.
Did you mean this?
Snack
function HomeScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<Button
title="Go to Details"
onPress={() => navigation.navigate('Details', {onRefresh: () => console.log('refreshing...')})}
/>
</View>
);
}
function DetailsScreen(props) {
const { route } = props;
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
<Button onPress={route.params.onRefresh} title="Refresh" />
</View>
);
}
React Native re-renders the screen whenever there is state change but this re-rendering will not happen if the screen is not being displayed. As for your scenario, I will suggest using redux to store the values that need to be refreshed from the second screen. Now whenever you go back to the first screen, then if you are reading value from the redux store, it will read the new values for all the variables that needed to be refreshed from the second screen, thus you will have the new values instead of the old ones.

Android: React Native Overlap TouchableOpacity and View behave differently when there is backgroundColor style

I created 2 Views that display overlaps to each others. The top and the bottom
When the bottom view background wasn't configured. It responded to the press event correctly. Let's say when I press on the overlap zone, it showed that the bottom one had been pressed
However, when I configured the bottom view backgroundColor. When I pressed on the overlap zone, on Android, it responded as I pressed on the top view which I think it's incorrect. (iOS it responded correctly that the bottom was pressed)
Steps To Reproduce
Provide a detailed list of steps that reproduce the issue.
Here is an example component
const OverlapseTouchExample = ({backgroundColor}) => {
const [pressedBox, setPressefBox] = React.useState('')
return (
<View>
<Text>{pressedBox} pressed</Text>
<TouchableOpacity style={[styles.box, {backgroundColor: 'blue'}]} onPress={() => setPressefBox('top')} />
<View style={backgroundColor ? { backgroundColor: 'orange' } : null}>
<View style={{marginTop: -75}}>
<TouchableOpacity style={[styles.boxBottom, backgroundColor ? { backgroundColor: 'green '} : null]} onPress={() => setPressefBox('bottom')} />
</View>
</View>
</View>
);
}
const styles = StyleSheet.create({
box: {
width: 150,
height: 150,
borderWidth: 1,
},
boxBottom: {
width: 120,
height: 200,
borderWidth: 1,
}
})
The problem found when set the backgroundColor to true
<OverlapseTouchExample backgroundColor={true} />
You could see it in Snack https://snack.expo.io/#gie3d/9b6c32 (Android)

How to show loading icon in react native until the API response in react native?

I am creating a new app. After tapping the submit button I want to show the loading icon in the login page until the API response. Please help me
First create a state variable for showing and hiding loader as follows
this.state = {
..
loading: false,
..
};
In the api call before the request send, you can set loading state to true and after completing the response set it to false
getData() {
this.setState({loading:true});// For showing loader
axios.get('api_link_goes_here')
.then(response => {
this.setState({loading:false});// For hiding loader
console.log(response.data);
})
.catch(error => {
this.setState({loading:false});// For hiding loader
console.log(error);
});
}
In your render template, you can add a View for showing the loader based on the state, You can add it to the bottom and position and make it full screen to avoid further clicks until response is received
render() {
return (
<View style={container}>
.....
{this.state.loading === true &&
<View style={styles.myloader}>
<CustomLoader /> // You can define this in another component or simply write <Text>Please wait...</Text>
</View>
}
....
</View>
)}
Style is given below for loader container
const styles = StyleSheet.create({
.....
myloader: {
position: "absolute",
top: 0,
left: 0,
zIndex: 10,
backgroundColor: "#ffffff",
opacity: 0.9,
justifyContent: 'center',
alignItems: 'center',
width: "100%",
height: "100%"
}
...
});

Update react native app with code push

I'm trying to update my app with code-push. I have next code-push options in my index file:
let codePushOptions = {
checkFrequency: codePush.CheckFrequency.ON_APP_RESUME,
installMode: codePush.InstallMode.ON_NEXT_RESUME,
minimumBackgroundDuration: 60 * 5
};
MainApp = codePush(codePushOptions)(Item);
export default MainApp;
Thus, on every app resume it will be checked if there is an update, but the update will be installed on next app resume.
But I want to show a button on a home screen to the users that the update is available if it is available, that they can install it manually on button click.
The problem is that the button is shown on main screen and they can see it if the update is still downloading in the background and if they click during the downloading process nothing happens. Only when the update is downloaded then the click on the button will install it. I try to AVOID that the button is show during downloading update.
I want to show the button only if the update is downloaded completely.
I check if the update is available in componentDidMount as follows:
checkForNewUpdate(){
let self = this;
codePush.checkForUpdate().then(update => {
if (!update) {
codePush.getUpdateMetadata(codePush.UpdateState.PENDING).then((data) => {
if (data) {
self.setState({updateAvailable: true, checkingForUpdate: false})
}else{
self.setState({updateAvailable: false, checkingForUpdate: false})
}
});
}else{
self.setState({updateAvailable: true, checkingForUpdate: false})
}
})
}
And I show button depending on the state as follows:
if(this.state.checkingForUpdate){
return (
<View style={{paddingTop: 10, paddingBottom: 10, alignItems: 'center'}}>
<Text style={{color: s.success, fontSize: 12}}>{gettext("Checking for update...")}</Text>
</View>
)
}
if (this.state.updateAvailable){
return (
<View style={{flexDirection: "row", alignItems: "center", justifyContent: "center", padding: 5, backgroundColor: s.success}}>
<Text style={styles.updateText}>{gettext("Update available")}</Text>
<TouchableHighlight style={styles.updateButton} underlayColor={"transparent"} onPress={this.handleUpdate.bind(this)}>
<Text style={styles.updateButtonText}>{gettext("Click to install")}</Text>
</TouchableHighlight>
</View>
)
}
Any idea how to solve it?