Skip to content

Commit

Permalink
Deep linking handling
Browse files Browse the repository at this point in the history
  • Loading branch information
themichaellai committed Dec 27, 2015
1 parent 6e48029 commit 4a34609
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 11 deletions.
25 changes: 23 additions & 2 deletions index.ios.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
const React = require('react-native');
const {
AppRegistry,
LinkingIOS,
Navigator,
StyleSheet,
StatusBarIOS,
TabBarIOS,
} = React;

const _ = require('underscore');

const Frontpage = require('./src/Frontpage');
const LinksListing = require('./src/LinksListing');
const PostDetail = require('./src/components/PostDetail');
const PostDetailLoader = require('./src/PostDetailLoader');
const Sections = require('./src/Sections');

const NavigationActionCreators = require('./src/actions/NavigationActionCreators');
const PostActionCreators = require('./src/actions/PostActionCreators');

const { NavigationBarRouteMapper } = require('./src/NavigationBarRouteMapper.ios');

Expand Down Expand Up @@ -60,6 +65,18 @@ const chronreact = React.createClass({
componentDidMount() {
tabCursor.on('change', this.updateTab);
StatusBarIOS.setStyle('light-content');

const url = LinkingIOS.popInitialURL();
if (!_.isNull(url)) {
const slug = url.replace(/dukechronicle:\/\//, '');
PostActionCreators.getPost(slug);
this.refs.frontpageNav.push({
type: 'PostDetailLoader',
passProps: {
slug: slug,
},
});
}
},

componentWillUnmount() {
Expand Down Expand Up @@ -89,6 +106,10 @@ const chronreact = React.createClass({
return (
<PostDetail style={styles.innerComponent} {...route.passProps} />
);
case 'PostDetailLoader':
return (
<PostDetailLoader style={styles.innerComponent} {...route.passProps} />
);
case 'Frontpage':
return (
<Frontpage style={styles.innerComponent} navigator={navigator} />
Expand Down Expand Up @@ -123,6 +144,7 @@ const chronreact = React.createClass({
icon={{uri: 'newspaper'}}
onPress={this.switchTabHandler('frontpage')} >
<Navigator
ref="frontpageNav"
style={styles.container}
barTintColor="#083e8c"
tintColor="#eee"
Expand Down Expand Up @@ -166,8 +188,7 @@ const chronreact = React.createClass({
initialRoute={{
title: 'Links',
type: 'LinksListing',
}}
/>
}} />
</TabBarIOS.Item>
</TabBarIOS>
);
Expand Down
62 changes: 62 additions & 0 deletions src/PostDetailLoader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
const React = require('react-native');
const {
View,
} = React;
const PostDetail = require('./components/PostDetail');

const _ = require('underscore');

const helpers = require('./helpers.js');
const { LoadingView } = helpers;

const store = require('./store');

const styles = {};

const PostDetailLoader = React.createClass({
propTypes: {
slug: React.PropTypes.string.isRequired,
},

getInitialState: function() {
return {
post: undefined,
loaded: false,
};
},

componentDidMount: function() {
this.cursor = store.select('models', 'posts', this.props.slug);
this.cursor.on('update', this.updateState);
this.updateState();
},

updateState: function() {
const post = this.cursor.get();
if (!_.isUndefined(post)) {
this.setState({
post,
loaded: true,
});
}
},

renderLoadingView: function() {
return (
<View style={styles.container}>
<LoadingView />
</View>
);
},

render: function() {
if (!this.state.loaded) {
return this.renderLoadingView();
}
return (
<PostDetail post={this.state.post} />
);
},
});

module.exports = PostDetailLoader;
36 changes: 27 additions & 9 deletions src/actions/PostActionCreators.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,25 @@ const sectionIdsCursor = store.select('models', 'sectionIds');
const { rawDataToPost } = require('../utils/Post');

/**
* urlBuilder builds the url used to query for a section's articles.
* sectionUrlBuilder builds the url used to query for a section's articles.
* @param {String} sectionSlug Section slug. Should mirror the slug used on the
* website.
* @return {String} Url of the section API endpoint.
*/
const urlBuilder = (sectionName) => {
const sectionUrlBuilder = (sectionName) => {
if (sectionName !== 'frontpage') {
return `http://www.dukechronicle.com/section/${sectionName}.json`;
} else {
return 'http://www.dukechronicle.com/.json';
}
};

const postUrlBuilder = (slug) => {
// strips leading and trailing slashes
const stripped = slug.replace(/^\/|\/$/g, '');
return `http://www.dukechronicle.com/article/${stripped}.json`;
};

/**
* getSection issues an API request to retrieve the articles for a section. On a
* successful request, it will populate postsCursor with the new article bodies
Expand All @@ -28,7 +34,7 @@ const urlBuilder = (sectionName) => {
* website.
*/
const getSection = (section) => {
const p = fetch(urlBuilder(section))
const p = fetch(sectionUrlBuilder(section))
.then((response) => response.json())
.then((responseData) => {
const articles = responseData[0].articles;
Expand All @@ -45,13 +51,25 @@ const getSection = (section) => {
return p;
};

const getPost = (slug) => {
const p = fetch(postUrlBuilder(slug))
.then((response) => response.json())
.then((responseData) => {
const article = rawDataToPost(responseData[0].article);
postsCursor.merge({[slug]: article});
})
.catch((error) => {
console.warn(error);
// TODO: change some view state
});
p.done();
return p;
};

const PostActionCreators = {
getFrontpage: () => {
return getSection('frontpage');
},
getSection: (section) => {
return getSection(section);
},
getFrontpage: getSection.bind(null, 'frontpage'),
getSection: getSection,
getPost: getPost,
};

module.exports = PostActionCreators;

0 comments on commit 4a34609

Please sign in to comment.