Commit 2094eed8 authored by Gijs Hendriksen's avatar Gijs Hendriksen Committed by Gijs Hendriksen
Browse files

Add deeplinking functionality to the push notifications.

When the app is opened through a push notification, it will handle it as
follows:

If the app is in the background or closed when the push notification
arrives, it will check whether the push notification contains a URL. If
it doesn't, the homepage will simply be shown. If it does have a URL, it
checks whether the URL is recognised as an URL for which we have a
deeplinking action. If so, it will open the corresponding screen
in the app. Otherwise, it will open the URL in the user's browser.

If the app is in the foreground when the notification arrives, it will
open an alert with the notifications title and contents. If the
notification has an URL, we show two buttons: one for opening the URL,
one for dismissing the notification. Otherwise, there is only a button
for dismissing the notification.
parent 8343ee82
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`deeplinking actions should create an action to notify of a new deeplink 1`] = `
exports[`deeplinking actions should create an action to notify of a new deeplink that should leave the app 1`] = `
Object {
"payload": Object {
"stayInApp": false,
"url": "http://example.org",
},
"type": "DEEPLINKING_DEEPLINK",
}
`;
exports[`deeplinking actions should create an action to notify of a new deeplink that should stay in the app 1`] = `
Object {
"payload": Object {
"stayInApp": true,
"url": "http://example.org",
},
"type": "DEEPLINKING_DEEPLINK",
......
......@@ -5,7 +5,11 @@ describe('deeplinking actions', () => {
expect(actions.DEEPLINK).toEqual('DEEPLINKING_DEEPLINK');
});
it('should create an action to notify of a new deeplink', () => {
it('should create an action to notify of a new deeplink that should stay in the app', () => {
expect(actions.deepLink('http://example.org')).toMatchSnapshot();
});
});
\ No newline at end of file
it('should create an action to notify of a new deeplink that should leave the app', () => {
expect(actions.deepLink('http://example.org', false)).toMatchSnapshot();
});
});
......@@ -3,6 +3,10 @@
exports[`translations should expose the translations 1`] = `
Object {
"nl": Object {
"app/App": Object {
"Dismiss": "Sluiten",
"Open": "Openen",
},
"components/errorScreen/ErrorScreen": Object {
"Try again later.": "Probeer het later opnieuw.",
},
......
export const DEEPLINK = 'DEEPLINKING_DEEPLINK';
export function deepLink(url) {
export function deepLink(url, stayInApp = true) {
return {
type: DEEPLINK,
payload: { url },
payload: { url, stayInApp },
};
}
......@@ -4,12 +4,13 @@ import {
} from 'react-native';
import { applyMiddleware, createStore } from 'redux';
import { Provider } from 'react-redux';
import { I18nextProvider } from 'react-i18next';
import { I18nextProvider, translate } from 'react-i18next';
import createSagaMiddleware from 'redux-saga';
import firebase from 'react-native-firebase';
import locale from 'react-native-locale-detector';
import Moment from 'moment';
import 'moment/locale/nl';
import PropTypes from 'prop-types';
import reducers from './reducers';
......@@ -48,14 +49,35 @@ class Main extends Component {
store.dispatch(register());
});
this.notificationListener = firebase.notifications().onNotification((notification) => {
Alert.alert(notification.title, notification.body, [
{ text: 'OK' },
]);
let buttons;
if (notification.data.url) {
buttons = [
{ text: this.props.t('Dismiss') },
{
text: this.props.t('Open'),
onPress: () => store.dispatch(
deepLinkingActions.deepLink(notification.data.url, false),
),
},
];
} else {
buttons = [
{ text: 'OK' },
];
}
Alert.alert(notification.title, notification.body, buttons);
});
this.notificationOpenedListener = firebase.notifications()
.onNotificationOpened(this.handleOpenNotification);
firebase.notifications().getInitialNotification().then(this.handleOpenNotification);
}
componentWillUnmount() {
this.notificationListener();
this.notificationOpenedListener();
this.onTokenRefreshListener();
Linking.removeEventListener('url', this.handleOpenURL);
}
......@@ -74,6 +96,15 @@ class Main extends Component {
store.dispatch(deepLinkingActions.deepLink(event.url));
};
handleOpenNotification = (notificationOpen) => {
if (notificationOpen) {
const notification = notificationOpen.notification;
if (notification.data.url) {
store.dispatch(deepLinkingActions.deepLink(notification.data.url, false));
}
}
};
render() {
return (
<I18nextProvider i18n={i18n}>
......@@ -89,4 +120,8 @@ class Main extends Component {
}
}
export default Main;
Main.propTypes = {
t: PropTypes.func.isRequired,
};
export default translate('app/App')(Main);
......@@ -13,6 +13,7 @@ files['app/ui/screens/events/EventScreenNL'] = require('./nl/app/ui/screens/even
files['app/ui/components/standardHeader/StandardHeaderNL'] = require('./nl/app/ui/components/standardHeader/StandardHeader.json');
files['app/ui/components/errorScreen/ErrorScreenNL'] = require('./nl/app/ui/components/errorScreen/ErrorScreen.json');
files['app/ui/components/sidebar/SidebarNL'] = require('./nl/app/ui/components/sidebar/Sidebar.json');
files['app/AppNL'] = require('./nl/app.json');
export default {
nl: {
......@@ -30,5 +31,6 @@ export default {
'components/standardHeader/StandardHeader': files['app/ui/components/standardHeader/StandardHeaderNL'],
'components/errorScreen/ErrorScreen': files['app/ui/components/errorScreen/ErrorScreenNL'],
'components/sidebar/Sidebar': files['app/ui/components/sidebar/SidebarNL'],
'app/App': files['app/AppNL'],
},
};
{
"Dismiss": "Sluiten",
"Open": "Openen"
}
\ No newline at end of file
import { Linking } from 'react-native';
import {
put, take, takeEvery, select,
} from 'redux-saga/effects';
......@@ -35,7 +36,7 @@ export const parseURL = (url) => {
const deepLink = function* deepLink(action) {
const { url } = action.payload;
const { url, stayInApp } = action.payload;
if (!url) {
return;
......@@ -74,6 +75,10 @@ const deepLink = function* deepLink(action) {
return;
}
}
if (!stayInApp) {
Linking.openURL(url);
}
};
const deepLinkingSaga = function* deepLinkingSaga() {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment