Logout user by sending them to a Logout Webview - react-native

I'm having a difficult time trying to figure out how to log out both the user on the expo app as well as logging them out from the react-native-webview.
The user can log out of the expo app by pressing logout (which just handles the auth logic), however; the user is still logged in inside the webview (which is the shop uri).
At the moment, I came up with two possible ways: either set incognito to true on the webview, or send the user to a Screen which returns another webview to the shopify's logout uri.
// sending user to shopify logout webview
//navigator
<Stack.Navigator>
<Stack.Screen
name="AccountDetails"
component={AccountDetailsScreen}
/>
<Stack.Screen
name="ShopWebview"
component={ShopWebview}
/>
<Stack.Screen
name="LogOut"
component={LogOutWebView}
/>
</Stack.Navigator>
// from `AccountDetails` component, user presses handleLogout()
const handleLogOut = () => navigation.navigate('LogOut');
// shopify logout webview
export const LogOutWebView = () => {
return (
<WebView
source={{ uri: 'https://www.quarantotto.co.jp/account/logout' }}
/>
);
};
This seems to work w/ android, but it doesn't seem to work on iOS? I'm not quite sure why that is.
I can still set the incognito to true likeso:
// ShopWebview
<WebView
incognito
source={{ uri: 'someshop.com/' }}
/>
and this would help me not store the logged in user's session, but not quite sure if this is the proper way to handle auth.
If I can use the first method of sending the user to a webview that handles logout when a user visits it, that would be great. But not sure why it's not working from ios.
any ideas?
UPDATE: possible working solution?
Whenever the user logs out, they are sent back to a screen w/ login or register.
The issue was that whenever the user pressed login, since their session was cached, they are redirect to their account screen (which is what I don't want since if a user presses logout, I want them to be logged out and have to log back in).
what I have done is just inject some js in the LoginWebview
const handleNavigationStateChange = (newNavState) => {
if (webViewRef.current) {
webViewRef.current.injectJavaScript(scriptFetchCustomer());
}
if (newNavState.url.includes('logout')) {
setTimeout(() => {
const redirectTo = `window.location = "${someshop.com/login}"`;
webViewRef.current.injectJavaScript(redirectTo);
}, 500);
}
};
seems to work, but I don't enjoy using the settimeout. any recommendations?
second update... doesn't work on android
Android isn't working properly. I've set the source to the shopify's /account/logout uri, but inside handleNavigationStateChange the newNavState's url isn't the logout as it's set on the source.
....
Last update:
It finally works as I wanted to. I had to check for the url changes inside onNavigationStateChange of the webview. Then I could do what I wanted. I basically sent user to /account/logout, then set current logged in user state back into null which fires a redirect to login screen.
Hope it helps someone.

Related

React Native WebView - Open link in external browser only in case of user interaction

I have the following WebView component that is used multiple times for various embeds inside news articles
<WebView
useWebKit={true}
ref={(ref) => this.webview = ref}
javaScriptEnabled={true}
injectedJavaScript={"(" + injectedScript + ")()"}
onMessage={this.onMessage}
onNavigationStateChange={this.onNavigationStateChange}
{...this.props}
/>
and the following navigation state change listener, used for opening links in an external browser
onNavigationStateChange = (event) => {
this.webview.stopLoading();
Linking.openURL(event.url);
}
The problem is that the navigation change listener doesn't seem capable of differentiating between user interaction and automatic page redirects (which social media embeds will often do). How can I open the link in an external browser ONLY for user interaction?
I don't know exactly if automatic page redirects trigger click events, but they should not, so you can listen to only click events, which I suppose can only be triggered by the user.
onNavigationStateChange = (navState) =>
{
if (navState.navigationType === 'click') {
// User clicked something
}
}

Navigating from a login screen to home page on RN

I am learning RN, and as a part of my project, I am building an app that will take me to my toolbelt of items I will be making or have made such as animations. I am currently struggling with the login component of it. I am looking to login to my app so that it can take me to the homepage. I am using asyncstorage. When I log in, nothing happens except it stays on the login page. I have provided the lines of code as to how I have it built out. I really am just looking for something to get to the homepage on my simulator. I won't be deploying it or anything as I am keeping it to myself, but if any of you have any recommendations for articles or videos on how to achieve this in a "simpler" fashion, I am open to that option as well.
<TouchableOpacity
style={styles.buttonContainer}
onPress={this._signInAsync}
>
<Text style={styles.buttonText}>LOGIN</Text>
</TouchableOpacity>
</View>
);
}
_signInAsync = async () => {
await AsyncStorage.setItem("userToken", "abc");
this.props.navigation.navigate("app");
};
}

instagram api login with two-factor authentication

I'm using Instagram API for authentication in my app. the API works fine but when a user is using two-factor authentication the redirect_uri doesn't work and user redirected to the Instagram main page instead of the correct URL (my app login URL). I don't know how should I handle this and couldn't find any good answer. please help me
Note: this scenario happens for the first time and when Instagram's login session is available in browser user logged in correctly.
Not sure if this is still helpful. But I implemented the following on React Native WebView component and resolved Instagram's clear misstep.
Note - A more robust solution would be for Instagram to actually solve the bug.
As props on WebView:
source={{ uri: this.state.uri }}
onNavigationStateChange={this._onNavigationStateChange}
The handling method:
_onNavigationStateChange(webViewState){
const url = webViewState.url || ''
if(url.includes('challenge')){
this.setState({challenged: true})
}
if(url === 'https://www.instagram.com/' && this.state.challenged){
this.setState({
uri: `${URI}&indifferent_query_param=${(new Date).getTime()}`
})
}
}
The handling method forces rerender of WebView and sends the user to the "authorize" page. Depending on your platform of implementation, you could apply something similar to the above.

webview onNavigationStateChange returns url of previous page

In react native webview, when I navigate to a page the onNavigationStateChange returns url of the previous page? I think its an issue and posted it to github react native issues.
<WebView
ref={r => this.webview = r}
style = {{marginTop : 0}}
onNavigationStateChange=
{this._onNavigationStateChange.bind(this)}
startInLoadingState = {true}
source = {{uri: 'https://www.youtube.com' }}
/>
_onNavigationStateChange(webViewState)
{
this.setState(
{
youtube_video_url: webViewState.url
})
}
When I print this youtube_video_url, it is of the previous page or previous browsed video.
Sadly, all the webview methods like onNavigationStateChange, onLoad, onLoadStart etc are not working as expected in cases of single page application websites or websites that don't trigger a window.load event.
Normaly onNavigationStateChange gets triggered in the beginning of a request with {loading: true, url: "someUrl", ...} and once after the loading of the url with {loading: false, url: "someUrl", ...}.
There is no global workaround (to my knowledge) that will work correctly for all websites and for both iOs/Android but maybe this can help in your case:
https://snack.expo.io/H1idX8vpM
Basically you inject a custom javascript in the webview that notifies the WebView which is the loaded page. You can enhance it if you want to catch custom window.history manipulation events.

React-Router using a loading page while fetching a DB

So, I finished my app using React Router and everything works as expected. When the user enters the page, he gets redirected to a loading screen while my App component fetches a DB, and after the fetch is done the user gets redirected to the category that was fetched.
/ -> <Loader /> -> /App().state.data[0].category.
The fetch is done so fast that the user cannot even see the loading screen, as expected. So the user experiences.
/ -> /App().state.data[0].category.
So my problem is that when the user is on the /App().state.data[0].category page, and he hits the back button, he will see and stay on the loading screen. So he basically has to double click to go back to the previous page. This is not desired.
What the user experiences
/App().state.data[0].category -> <Loader /> -> Page before entering the "/"
What the user should experience
/App().state.data[0].category -> Page before entering the "/"
My Question is there a way to jump the loading screen if the user presses the back button?
I started looking into the history npm thing, am I on the right track?
My current config looks like this in pseudocode:
main.js
render(
<Router history={hashHistory}>
<Route path="/" component={App}>
/* This returns the first category from my api */
<IndexRedirect to={App().state.data[0].category} />
<Route path=":category" component={App} />
</Route>
</Router>
,document.getElementById('main'));
App.js
class App extends React.Component{
componentWillMount() {
const router = this.context.router;
fetchData().then(function(results){
router.push(results.data[0].category);
})
}
render() {
return (<Loader/>);
}
}
why not do a conditional render on a single component.
if database -> render the page
else -> render the loader
as soon as your db fetch is complete, the render will mount and you will see your page instead of your loader