...
 
Commits (4)
import service from '../../../src/common/services/deeplinks-router.service';
import { MINDS_DEEPLINK } from '../../../src/config/Config';
import navigationService from '../../../src/navigation/NavigationService';
import service from '../../../src/common/services/deeplinks-router.service';
/**
* Tests
......@@ -10,19 +7,43 @@ import navigationService from '../../../src/navigation/NavigationService';
describe('Deeplinks router service', () => {
navigationService.navigate = jest.fn();
beforeEach(() => {
navigationService.navigate.mockClear();
});
it('should add route', async () => {
expect(service.routes.length).toBe(12)
service.clearRoutes();
expect(service.routes.length).toBe(0);
service.add('crypto/:someparam', 'screen1');
service.add('myurl/:someparam1', 'screen2');
expect(service.routes.length).toBe(14);
service.add('twoparams/:someparam1/:someparam2', 'screen2');
expect(service.routes.length).toBe(3);
service.navigate('http://www.minds.com/crypto/somevalue');
expect(navigationService.navigate).toHaveBeenCalledWith('screen1', {someparam: 'somevalue'});
expect(navigationService.navigate).toHaveBeenCalledWith('screen1', {
someparam: 'somevalue',
});
service.navigate('http://www.minds.com/myurl/somevalue');
expect(navigationService.navigate).toHaveBeenCalledWith('screen2', {someparam1: 'somevalue'});
expect(navigationService.navigate).toHaveBeenCalledWith('screen2', {
someparam1: 'somevalue',
});
service.navigate('http://www.minds.com/twoparams/somevalue/somevalue1');
expect(navigationService.navigate).toHaveBeenCalledWith('screen2', {
someparam1: 'somevalue',
someparam2: 'somevalue1',
});
service.navigate(
'http://www.minds.com/twoparams/somevalue/somevalue1?other=1&other2=2',
);
expect(navigationService.navigate).toHaveBeenCalledWith('screen2', {
someparam1: 'somevalue',
someparam2: 'somevalue1',
other: '1',
other2: '2',
});
service.navigate('http://www.minds.com/myurl/somevalue?other=1');
expect(navigationService.navigate).toHaveBeenCalledWith('screen2', {
someparam1: 'somevalue',
other: '1',
});
});
});
\ No newline at end of file
});
......@@ -50,12 +50,13 @@
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https"
android:host="mobile.minds.com" android:path="/"/>
<data android:pathPattern="/channels/..*"/>
android:host="www.minds.com" android:path="/"/>
<data android:pathPattern="/email-confirmation"/>
<!-- <data android:pathPattern="/channels/..*"/>
<data android:pathPattern="/newsfeed/..*"/>
<data android:pathPattern="/groups/profile/..*"/>
<data android:pathPattern="/wallet/..*"/>
<data android:pathPattern="/..*"/>
<data android:pathPattern="/..*"/> -->
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
......
......@@ -6,8 +6,8 @@
<string>development</string>
<key>com.apple.developer.associated-domains</key>
<array>
<string>applinks:mobile.minds.com</string>
<string>activitycontinuation:mobile.minds.com</string>
<string>applinks:www.minds.com</string>
<string>activitycontinuation:www.minds.com</string>
</array>
</dict>
</plist>
......@@ -5,7 +5,9 @@ import navigationService from '../../navigation/NavigationService';
* Deeplinks router
*/
class DeeplinksRouter {
/**
* Routes
*/
routes = [];
/**
......@@ -15,6 +17,28 @@ class DeeplinksRouter {
MINDS_DEEPLINK.forEach(r => this.add(r[0], r[1]));
}
/**
* Clear routes
*/
clearRoutes() {
this.routes = [];
}
/**
* Parse params
* @param {string} url
*/
parseQueryParams(url) {
let regex = /[?&]([^=#]+)=([^&#]*)/g,
params = {},
match;
while ((match = regex.exec(url))) {
params[match[1]] = match[2];
}
return params;
}
/**
* Add a new route
* @param {string} url ex: newsfeed/:guid
......@@ -28,7 +52,7 @@ class DeeplinksRouter {
this.routes.push({
screen,
params,
re: new RegExp('^' + url.replace(re, '([^\/]+?)') + '\/?$')
re: new RegExp('^' + url.replace(re, '([^\/]+?)') + '(\/?$|\/?\\?)')
});
}
......@@ -63,8 +87,9 @@ class DeeplinksRouter {
if (match) {
const params = {};
route.params.forEach((v, i) => params[v] = match[i + 1]);
const urlParams = this.parseQueryParams(url);
return { screen: route.screen, params }
return { screen: route.screen, params: {...params, ...urlParams}}
}
}
return null;
......
......@@ -23,7 +23,7 @@ export const MINDS_URI_SETTINGS = {
export const MINDS_MAX_VIDEO_LENGTH = 5; // in minutes
export const SOCKET_URI = 'wss://ha-socket-io-us-east-1.minds.com:3030'
export const SOCKET_URI = 'wss://ha-socket-io-us-east-1.minds.com:3030';
export const MINDS_CDN_URI = 'https://cdn.minds.com/';
export const MINDS_ASSETS_CDN_URI = 'https://cdn-assets.minds.com/';
......@@ -45,6 +45,7 @@ export const MINDS_FEATURES = {
* Deeplink to screen/params maping
*/
export const MINDS_DEEPLINK = [
['email-confirmation', 'EmailConfirmation'],
['groups/profile/:guid/feed', 'GroupView'],
['groups/profile/:guid', 'GroupView'],
['notifications', 'Notifications'],
......
......@@ -49,6 +49,7 @@ import {withErrorBoundaryScreen} from '../common/components/ErrorBoundary';
import DeleteChannelScreen from '../settings/screens/DeleteChannelScreen';
import DiscoveryFeedScreen from '../discovery/DiscoveryFeedScreen';
import Gathering from '../gathering/Gathering';
import EmailConfirmationScreen from '../onboarding/EmailConfirmationScreen';
/**
* Main stack navigator
......@@ -57,6 +58,9 @@ const Stack = createStackNavigator({
Tabs: {
screen: withErrorBoundaryScreen(TabsScreen),
},
EmailConfirmation: {
screen: withErrorBoundaryScreen(EmailConfirmationScreen)
},
// Logs: {
// screen: LogsScreen
// },
......
import React, {Component} from 'react';
import {View, Text} from 'react-native';
import { CommonStyle } from '../styles/Common';
/**
* Email confirmation screen
*/
export default class EmailConfirmationScreen extends Component {
/**
* Component did mount
*/
componentDidMount() {
// TODO: Implement call to the api for confirmation using the deeplinks params (this.props.navigation.state.params)
console.log('ConfirmParams', this.props.navigation.state.params);
}
/**
* Render
*/
render() {
return (
<View style={CommonStyle.flexContainer}>
<Text style={CommonStyle.fontL}>Sending email confirmation</Text>
</View>
);
}
}
......@@ -38,26 +38,15 @@ export default class Topbar extends Component {
<View style={styles.container} >
<View style={styles.topbar}>
{ featuresService.has('crypto') &&
<TouchableOpacity
onPress={() => this.props.navigation.navigate('BoostConsole', { navigation: this.props.navigation })}
{ featuresService.has('crypto') &&
<TouchableOpacity
onPress={() => this.props.navigation.navigate('BoostConsole', { navigation: this.props.navigation })}
{...testID('boost-console button')} >
<View style={styles.topbarLeft}>
<Icon name="trending-up" size={22} color='#444' style={ styles.button }/>
</View>
</TouchableOpacity>}
<View style={styles.topbarCenter}>
{ this.props.user.me && <Avatar
rounded
source={{ uri: MINDS_CDN_URI + 'icon/' + this.props.user.me.guid + '/medium/' + this.props.user.me.icontime}}
width={38}
height={38}
onPress={() => this.props.navigation.push('Channel', { guid: this.props.user.me.guid })}
testID="AvatarButton"
/> }
</View>
<View style={styles.topbarCenter}>
{ this.props.user.me && <Avatar
rounded
......@@ -65,7 +54,7 @@ export default class Topbar extends Component {
width={38}
height={38}
onPress={() => this.props.navigation.push('Channel', { guid: this.props.user.me.guid })}
{...testID('topbar avatar button')}
testID="AvatarButton"
/> }
</View>
......