From 6b5b2fdf544e85026538d30bd2849f0a9a4e45db Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Tue, 21 Aug 2018 11:11:22 +0200 Subject: [PATCH 01/19] Add a startup saga --- App/Containers/Example/ExampleScreen.js | 4 +++- App/Sagas/StartupSaga.js | 11 +++++++++++ App/Sagas/index.js | 4 ++++ App/Stores/Startup/Actions.js | 8 ++++++++ 4 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 App/Sagas/StartupSaga.js create mode 100644 App/Stores/Startup/Actions.js diff --git a/App/Containers/Example/ExampleScreen.js b/App/Containers/Example/ExampleScreen.js index 19c300bc8..0af244313 100644 --- a/App/Containers/Example/ExampleScreen.js +++ b/App/Containers/Example/ExampleScreen.js @@ -3,6 +3,7 @@ import { Platform, Text, View, Button } from 'react-native' import { connect } from 'react-redux' import { PropTypes } from 'prop-types' import ExampleActions from 'App/Stores/Example/Actions' +import StartupActions from 'App/Stores/Startup/Actions' import { isHot } from 'App/Stores/Example/Selectors' import Style from './ExampleScreenStyle' @@ -13,7 +14,7 @@ const instructions = Platform.select({ class ExampleScreen extends React.Component { componentDidMount() { - this.props.fetchTemperature() + this.props.startup() } render() { @@ -49,6 +50,7 @@ const mapStateToProps = (state) => ({ }) const mapDispatchToProps = (dispatch) => ({ + startup: () => dispatch(StartupActions.startup()), fetchTemperature: () => dispatch(ExampleActions.fetchTemperature()), }) diff --git a/App/Sagas/StartupSaga.js b/App/Sagas/StartupSaga.js new file mode 100644 index 000000000..2e8c384fb --- /dev/null +++ b/App/Sagas/StartupSaga.js @@ -0,0 +1,11 @@ +import { put } from 'redux-saga/effects' +import ExampleActions from 'App/Stores/Example/Actions' + +/** + * The startup saga is the place to define behavior to execute when the application starts. + */ +export function* startup() { + // Dispatch a redux action using `put()` + // @see https://redux-saga.js.org/docs/basics/DispatchingActions.html + yield put(ExampleActions.fetchTemperature()) +} diff --git a/App/Sagas/index.js b/App/Sagas/index.js index 28348f01d..198086b81 100644 --- a/App/Sagas/index.js +++ b/App/Sagas/index.js @@ -1,12 +1,16 @@ import { takeLatest } from 'redux-saga/effects' import { ExampleTypes } from 'App/Stores/Example/Actions' +import { StartupTypes } from 'App/Stores/Startup/Actions' import { fetchTemperature } from './ExampleSaga' +import { startup } from './StartupSaga' export default function* root() { yield [ /** * @see https://redux-saga.js.org/docs/basics/UsingSagaHelpers.html */ + // Run the startup saga when the application starts + takeLatest(StartupTypes.STARTUP, startup), // Call `fetchTemperature()` when a `FETCH_TEMPERATURE` action is triggered takeLatest(ExampleTypes.FETCH_TEMPERATURE, fetchTemperature), ] diff --git a/App/Stores/Startup/Actions.js b/App/Stores/Startup/Actions.js new file mode 100644 index 000000000..91e248210 --- /dev/null +++ b/App/Stores/Startup/Actions.js @@ -0,0 +1,8 @@ +import { createActions } from 'reduxsauce' + +const { Types, Creators } = createActions({ + startup: null, +}) + +export const StartupTypes = Types +export default Creators From 413fc05e346fd70aadd91886ca7c7efe852cc997 Mon Sep 17 00:00:00 2001 From: Jeremy Dolle Date: Tue, 4 Sep 2018 11:47:40 +0200 Subject: [PATCH 02/19] add Navigation and splash screen --- App/App.js | 4 +- App/Containers/Example/ExampleScreen.js | 5 - App/Containers/Root/RootScreen.js | 48 +++++++ App/Containers/Root/RootScreenStyle.js | 8 ++ App/Containers/SplashScreen/SplashScreen.js | 15 +++ .../SplashScreen/SplashScreenStyle.js | 21 +++ App/Sagas/ExampleSaga.js | 3 +- App/Sagas/StartupSaga.js | 5 + App/Services/NavigationService.js | 23 ++++ App/{Service => Services}/README.md | 0 App/{Service => Services}/WeatherService.js | 0 package.json | 1 + yarn.lock | 126 +++++++++++++++++- 13 files changed, 249 insertions(+), 10 deletions(-) create mode 100644 App/Containers/Root/RootScreen.js create mode 100644 App/Containers/Root/RootScreenStyle.js create mode 100644 App/Containers/SplashScreen/SplashScreen.js create mode 100644 App/Containers/SplashScreen/SplashScreenStyle.js create mode 100644 App/Services/NavigationService.js rename App/{Service => Services}/README.md (100%) rename App/{Service => Services}/WeatherService.js (100%) diff --git a/App/App.js b/App/App.js index 017eb645f..152f7b8fb 100644 --- a/App/App.js +++ b/App/App.js @@ -2,7 +2,7 @@ import React, { Component } from 'react' import { Provider } from 'react-redux' import { PersistGate } from 'redux-persist/lib/integration/react' import createStore from 'App/Stores' -import ExampleScreen from './Containers/Example/ExampleScreen' +import RootScreen from './Containers/Root/RootScreen' const { store, persistor } = createStore() @@ -21,7 +21,7 @@ export default class App extends Component { * @see https://github.com/rt2zz/redux-persist/blob/master/docs/PersistGate.md */} - + ) diff --git a/App/Containers/Example/ExampleScreen.js b/App/Containers/Example/ExampleScreen.js index 0af244313..ca196666c 100644 --- a/App/Containers/Example/ExampleScreen.js +++ b/App/Containers/Example/ExampleScreen.js @@ -13,10 +13,6 @@ const instructions = Platform.select({ }) class ExampleScreen extends React.Component { - componentDidMount() { - this.props.startup() - } - render() { let temperature = this.props.temperatureIsLoading ? '...' : this.props.temperature if (temperature === null) { @@ -50,7 +46,6 @@ const mapStateToProps = (state) => ({ }) const mapDispatchToProps = (dispatch) => ({ - startup: () => dispatch(StartupActions.startup()), fetchTemperature: () => dispatch(ExampleActions.fetchTemperature()), }) diff --git a/App/Containers/Root/RootScreen.js b/App/Containers/Root/RootScreen.js new file mode 100644 index 000000000..2be297b2f --- /dev/null +++ b/App/Containers/Root/RootScreen.js @@ -0,0 +1,48 @@ +import React, { Component } from 'react' +import { createStackNavigator } from 'react-navigation' +import NavigationService from 'App/Services/NavigationService' +import { View } from 'react-native' +import styles from './RootScreenStyle' +import ExampleScreen from 'App/Containers/Example/ExampleScreen' +import SplashScreen from 'App/Containers/SplashScreen/SplashScreen' +import { connect } from 'react-redux' +import StartupActions from '../../Stores/Startup/Actions' + +const AppNav = createStackNavigator( + { + SplashScreen: { screen: SplashScreen }, + InitialPage: { screen: ExampleScreen }, + }, + { + initialRouteName: 'SplashScreen', + headerMode: 'none', + } +) + +class RootScreen extends Component { + componentDidMount() { + this.props.startup() + } + + render() { + return ( + + { + NavigationService.setTopLevelNavigator(navigatorRef) + }} + /> + + ) + } +} +const mapStateToProps = (state) => ({}) + +const mapDispatchToProps = (dispatch) => ({ + startup: () => dispatch(StartupActions.startup()), +}) + +export default connect( + mapStateToProps, + mapDispatchToProps +)(RootScreen) diff --git a/App/Containers/Root/RootScreenStyle.js b/App/Containers/Root/RootScreenStyle.js new file mode 100644 index 000000000..90faa255c --- /dev/null +++ b/App/Containers/Root/RootScreenStyle.js @@ -0,0 +1,8 @@ +import { StyleSheet } from 'react-native' +import ApplicationStyles from 'App/Theme/ApplicationStyles' + +export default StyleSheet.create({ + container: { + ...ApplicationStyles.screen.container, + }, +}) diff --git a/App/Containers/SplashScreen/SplashScreen.js b/App/Containers/SplashScreen/SplashScreen.js new file mode 100644 index 000000000..cb8a51d84 --- /dev/null +++ b/App/Containers/SplashScreen/SplashScreen.js @@ -0,0 +1,15 @@ +import React from 'react' +import { Text, View } from 'react-native' +import styles from './SplashScreenStyle' + +export default class SplashScreen extends React.Component { + render() { + return ( + + + LOGO + + + ) + } +} diff --git a/App/Containers/SplashScreen/SplashScreenStyle.js b/App/Containers/SplashScreen/SplashScreenStyle.js new file mode 100644 index 000000000..fe3077e13 --- /dev/null +++ b/App/Containers/SplashScreen/SplashScreenStyle.js @@ -0,0 +1,21 @@ +import { StyleSheet } from 'react-native' +import Colors from 'App/Theme/Colors' +import ApplicationStyles from 'App/Theme/ApplicationStyles' + +export default StyleSheet.create({ + container: { + ...ApplicationStyles.screen.container, + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + backgroundColor: Colors.primary, + }, + logo: { + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + height: 70, + width: 70, + backgroundColor: 'white', + }, +}) diff --git a/App/Sagas/ExampleSaga.js b/App/Sagas/ExampleSaga.js index 431994778..28277989d 100644 --- a/App/Sagas/ExampleSaga.js +++ b/App/Sagas/ExampleSaga.js @@ -1,6 +1,7 @@ import { put, call } from 'redux-saga/effects' import ExampleActions from 'App/Stores/Example/Actions' -import { WeatherService } from 'App/Service/WeatherService' +import { WeatherService } from 'App/Services/WeatherService' +import NavigationService from '../Services/NavigationService' /** * A saga can contain multiple functions. diff --git a/App/Sagas/StartupSaga.js b/App/Sagas/StartupSaga.js index 2e8c384fb..a69afc601 100644 --- a/App/Sagas/StartupSaga.js +++ b/App/Sagas/StartupSaga.js @@ -1,5 +1,6 @@ import { put } from 'redux-saga/effects' import ExampleActions from 'App/Stores/Example/Actions' +import NavigationService from '../Services/NavigationService' /** * The startup saga is the place to define behavior to execute when the application starts. @@ -8,4 +9,8 @@ export function* startup() { // Dispatch a redux action using `put()` // @see https://redux-saga.js.org/docs/basics/DispatchingActions.html yield put(ExampleActions.fetchTemperature()) + // Do operation here : + // ... + // When operations are finished redirect to InitialPage + NavigationService.navigate('InitialPage') } diff --git a/App/Services/NavigationService.js b/App/Services/NavigationService.js new file mode 100644 index 000000000..1597bf508 --- /dev/null +++ b/App/Services/NavigationService.js @@ -0,0 +1,23 @@ +import { NavigationActions } from 'react-navigation' + +let _navigator + +function setTopLevelNavigator(navigatorRef) { + _navigator = navigatorRef +} + +function navigate(routeName, params) { + _navigator.dispatch( + NavigationActions.navigate({ + routeName, + params, + }) + ) +} + +// add other navigation functions that you need and export them + +export default { + navigate, + setTopLevelNavigator, +} diff --git a/App/Service/README.md b/App/Services/README.md similarity index 100% rename from App/Service/README.md rename to App/Services/README.md diff --git a/App/Service/WeatherService.js b/App/Services/WeatherService.js similarity index 100% rename from App/Service/WeatherService.js rename to App/Services/WeatherService.js diff --git a/package.json b/package.json index 4167b4468..3cfc7d950 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "prop-types": "^15.6.1", "react": "16.3.1", "react-native": "0.55.4", + "react-navigation": "^2.12.1", "react-redux": "^5.0.7", "redux": "^3.7.2", "redux-persist": "^5.9.1", diff --git a/yarn.lock b/yarn.lock index 6b228bf9d..09560f33c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1572,6 +1572,10 @@ circular-json@^0.3.1: version "0.3.3" resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" +clamp@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/clamp/-/clamp-1.0.1.tgz#66a0e64011816e37196828fdc8c8c147312c8634" + class-utils@^0.3.5: version "0.3.6" resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" @@ -1761,6 +1765,13 @@ create-react-class@^15.6.3: loose-envify "^1.3.1" object-assign "^4.1.1" +create-react-context@^0.2.1: + version "0.2.3" + resolved "https://registry.yarnpkg.com/create-react-context/-/create-react-context-0.2.3.tgz#9ec140a6914a22ef04b8b09b7771de89567cb6f3" + dependencies: + fbjs "^0.8.0" + gud "^1.0.0" + cross-spawn@^5.0.1, cross-spawn@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" @@ -2413,7 +2424,7 @@ fbjs-scripts@^0.8.1: semver "^5.1.0" through2 "^2.0.0" -fbjs@^0.8.14, fbjs@^0.8.16, fbjs@^0.8.9: +fbjs@^0.8.0, fbjs@^0.8.14, fbjs@^0.8.16, fbjs@^0.8.9: version "0.8.17" resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.17.tgz#c4d598ead6949112653d6588b01a5cdcd9f90fdd" dependencies: @@ -2688,6 +2699,10 @@ growly@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" +gud@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/gud/-/gud-1.0.0.tgz#a489581b17e6a70beca9abe3ae57de7a499852c0" + handlebars@^4.0.3: version "4.0.11" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.11.tgz#630a35dfe0294bc281edae6ffc5d329fc7982dcc" @@ -2764,7 +2779,7 @@ has@^1.0.1, has@^1.0.3: dependencies: function-bind "^1.1.1" -hoist-non-react-statics@^2.5.0: +hoist-non-react-statics@^2.2.0, hoist-non-react-statics@^2.3.1, hoist-non-react-statics@^2.5.0: version "2.5.5" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz#c5903cf409c0dfd908f388e619d86b9c1174cb47" @@ -3102,6 +3117,10 @@ is-windows@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -4493,6 +4512,12 @@ path-parse@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" +path-to-regexp@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d" + dependencies: + isarray "0.0.1" + path-type@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" @@ -4669,6 +4694,13 @@ qs@~6.5.1: version "6.5.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" +query-string@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.1.0.tgz#01e7d69f6a0940dac67a937d6c6325647aa4532a" + dependencies: + decode-uri-component "^0.2.0" + strict-uri-encode "^2.0.0" + ramda@^0.24.1: version "0.24.1" resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.24.1.tgz#c3b7755197f35b8dc3502228262c4c91ddb6b857" @@ -4723,6 +4755,26 @@ react-is@^16.3.1: version "16.4.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.4.1.tgz#d624c4650d2c65dbd52c72622bbf389435d9776e" +react-lifecycles-compat@^3, react-lifecycles-compat@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" + +react-native-dismiss-keyboard@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/react-native-dismiss-keyboard/-/react-native-dismiss-keyboard-1.0.0.tgz#32886242b3f2317e121f3aeb9b0a585e2b879b49" + +react-native-drawer-layout-polyfill@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/react-native-drawer-layout-polyfill/-/react-native-drawer-layout-polyfill-1.3.2.tgz#192c84d7a5a6b8a6d2be2c7daa5e4164518d0cc7" + dependencies: + react-native-drawer-layout "1.3.2" + +react-native-drawer-layout@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/react-native-drawer-layout/-/react-native-drawer-layout-1.3.2.tgz#b9740d7663a1dc4f88a61b9c6d93d2d948ea426e" + dependencies: + react-native-dismiss-keyboard "1.0.0" + react-native-rename@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/react-native-rename/-/react-native-rename-2.2.2.tgz#edbe16eea9d2d0e61b7b2c62ec4c2da585384f24" @@ -4733,6 +4785,30 @@ react-native-rename@^2.2.2: node-replace "^0.3.3" shelljs "^0.7.7" +react-native-safe-area-view@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/react-native-safe-area-view/-/react-native-safe-area-view-0.7.0.tgz#38f5ab9368d6ef9e5d18ab64212938af3ec39421" + dependencies: + hoist-non-react-statics "^2.3.1" + +react-native-safe-area-view@^0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/react-native-safe-area-view/-/react-native-safe-area-view-0.9.0.tgz#10ece2ecac70e7005a5b0b3f06c8833060e6d21f" + dependencies: + hoist-non-react-statics "^2.3.1" + +react-native-tab-view@^0.0.77: + version "0.0.77" + resolved "https://registry.yarnpkg.com/react-native-tab-view/-/react-native-tab-view-0.0.77.tgz#11ceb8e7c23100d07e628dc151b57797524d00d4" + dependencies: + prop-types "^15.6.0" + +react-native-tab-view@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/react-native-tab-view/-/react-native-tab-view-1.0.2.tgz#66e0bc6d38a227ed2b212e3a256b7902f6ce02ed" + dependencies: + prop-types "^15.6.1" + react-native@0.55.4: version "0.55.4" resolved "https://registry.yarnpkg.com/react-native/-/react-native-0.55.4.tgz#eecffada3750a928e2ddd07cf11d857ae9751c30" @@ -4797,6 +4873,48 @@ react-native@0.55.4: xmldoc "^0.4.0" yargs "^9.0.0" +react-navigation-deprecated-tab-navigator@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/react-navigation-deprecated-tab-navigator/-/react-navigation-deprecated-tab-navigator-1.3.0.tgz#015dcae1e977b984ca7e99245261c15439026bb7" + dependencies: + react-native-tab-view "^0.0.77" + +react-navigation-drawer@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/react-navigation-drawer/-/react-navigation-drawer-0.5.0.tgz#d91b6a6ec65c34ba78c00f814b1e6508922cc9ec" + dependencies: + react-native-drawer-layout-polyfill "^1.3.2" + +react-navigation-stack@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/react-navigation-stack/-/react-navigation-stack-0.2.3.tgz#9d1e2524aa1d178302c938948b8ece49d713f12b" + +react-navigation-tabs@0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/react-navigation-tabs/-/react-navigation-tabs-0.6.0.tgz#2f526194f4360e56c2702e736887449acc2080dc" + dependencies: + hoist-non-react-statics "^2.5.0" + prop-types "^15.6.1" + react-lifecycles-compat "^3.0.4" + react-native-safe-area-view "^0.7.0" + react-native-tab-view "^1.0.0" + +react-navigation@^2.12.1: + version "2.12.1" + resolved "https://registry.yarnpkg.com/react-navigation/-/react-navigation-2.12.1.tgz#17122a4162cd5a65d79814385cd61c2c0cb7ebb5" + dependencies: + clamp "^1.0.1" + create-react-context "^0.2.1" + hoist-non-react-statics "^2.2.0" + path-to-regexp "^1.7.0" + query-string "^6.1.0" + react-lifecycles-compat "^3" + react-native-safe-area-view "^0.9.0" + react-navigation-deprecated-tab-navigator "1.3.0" + react-navigation-drawer "0.5.0" + react-navigation-stack "0.2.3" + react-navigation-tabs "0.6.0" + react-proxy@^1.1.7: version "1.1.8" resolved "https://registry.yarnpkg.com/react-proxy/-/react-proxy-1.1.8.tgz#9dbfd9d927528c3aa9f444e4558c37830ab8c26a" @@ -5460,6 +5578,10 @@ stream-buffers@~2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/stream-buffers/-/stream-buffers-2.2.0.tgz#91d5f5130d1cef96dcfa7f726945188741d09ee4" +strict-uri-encode@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" + string-length@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/string-length/-/string-length-2.0.0.tgz#d40dbb686a3ace960c1cffca562bf2c45f8363ed" From 107b1142eed2fb3fa5f258904ead4f0740dc2135 Mon Sep 17 00:00:00 2001 From: Jeremy Dolle Date: Tue, 4 Sep 2018 11:56:42 +0200 Subject: [PATCH 03/19] lint fix --- App/Containers/Example/ExampleScreen.js | 1 - App/Sagas/ExampleSaga.js | 1 - 2 files changed, 2 deletions(-) diff --git a/App/Containers/Example/ExampleScreen.js b/App/Containers/Example/ExampleScreen.js index ca196666c..36f6b2fc7 100644 --- a/App/Containers/Example/ExampleScreen.js +++ b/App/Containers/Example/ExampleScreen.js @@ -3,7 +3,6 @@ import { Platform, Text, View, Button } from 'react-native' import { connect } from 'react-redux' import { PropTypes } from 'prop-types' import ExampleActions from 'App/Stores/Example/Actions' -import StartupActions from 'App/Stores/Startup/Actions' import { isHot } from 'App/Stores/Example/Selectors' import Style from './ExampleScreenStyle' diff --git a/App/Sagas/ExampleSaga.js b/App/Sagas/ExampleSaga.js index 28277989d..6ffa9c88b 100644 --- a/App/Sagas/ExampleSaga.js +++ b/App/Sagas/ExampleSaga.js @@ -1,7 +1,6 @@ import { put, call } from 'redux-saga/effects' import ExampleActions from 'App/Stores/Example/Actions' import { WeatherService } from 'App/Services/WeatherService' -import NavigationService from '../Services/NavigationService' /** * A saga can contain multiple functions. From 07cca9c94330ec7e888e2a906617b8b4ca05519d Mon Sep 17 00:00:00 2001 From: Jeremy Dolle Date: Tue, 4 Sep 2018 12:03:40 +0200 Subject: [PATCH 04/19] add navigateAndReset service --- App/Sagas/StartupSaga.js | 2 +- App/Services/NavigationService.js | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/App/Sagas/StartupSaga.js b/App/Sagas/StartupSaga.js index a69afc601..61a947573 100644 --- a/App/Sagas/StartupSaga.js +++ b/App/Sagas/StartupSaga.js @@ -12,5 +12,5 @@ export function* startup() { // Do operation here : // ... // When operations are finished redirect to InitialPage - NavigationService.navigate('InitialPage') + NavigationService.navigateAndReset('InitialPage') } diff --git a/App/Services/NavigationService.js b/App/Services/NavigationService.js index 1597bf508..4fd9866e7 100644 --- a/App/Services/NavigationService.js +++ b/App/Services/NavigationService.js @@ -1,4 +1,4 @@ -import { NavigationActions } from 'react-navigation' +import { NavigationActions, StackActions } from 'react-navigation' let _navigator @@ -15,9 +15,24 @@ function navigate(routeName, params) { ) } -// add other navigation functions that you need and export them +function navigateAndReset(routeName, params) { + _navigator.dispatch( + StackActions.reset({ + index: 0, + key: null, + actions: [ + NavigationActions.navigate({ + routeName, + params, + }), + ], + }) + ) +} +// add other navigation functions that you need and export them export default { navigate, + navigateAndReset, setTopLevelNavigator, } From 892b925e33a3c5580706d18032e0e3fa0ed8a9f6 Mon Sep 17 00:00:00 2001 From: Jeremy Dolle Date: Tue, 4 Sep 2018 14:18:25 +0200 Subject: [PATCH 05/19] remove full path --- App/Containers/Root/RootScreen.js | 2 +- App/Sagas/StartupSaga.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/App/Containers/Root/RootScreen.js b/App/Containers/Root/RootScreen.js index 2be297b2f..c098326ca 100644 --- a/App/Containers/Root/RootScreen.js +++ b/App/Containers/Root/RootScreen.js @@ -6,7 +6,7 @@ import styles from './RootScreenStyle' import ExampleScreen from 'App/Containers/Example/ExampleScreen' import SplashScreen from 'App/Containers/SplashScreen/SplashScreen' import { connect } from 'react-redux' -import StartupActions from '../../Stores/Startup/Actions' +import StartupActions from 'App/Stores/Startup/Actions' const AppNav = createStackNavigator( { diff --git a/App/Sagas/StartupSaga.js b/App/Sagas/StartupSaga.js index 61a947573..ae34b159b 100644 --- a/App/Sagas/StartupSaga.js +++ b/App/Sagas/StartupSaga.js @@ -1,6 +1,6 @@ import { put } from 'redux-saga/effects' import ExampleActions from 'App/Stores/Example/Actions' -import NavigationService from '../Services/NavigationService' +import NavigationService from 'App/Services/NavigationService' /** * The startup saga is the place to define behavior to execute when the application starts. From 82f8093a6b7abb0fb4d10d24d2e5a9fc77a3fe79 Mon Sep 17 00:00:00 2001 From: Jeremy Dolle Date: Tue, 4 Sep 2018 14:18:39 +0200 Subject: [PATCH 06/19] revert changes --- App/Containers/Example/ExampleScreen.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/App/Containers/Example/ExampleScreen.js b/App/Containers/Example/ExampleScreen.js index 36f6b2fc7..19c300bc8 100644 --- a/App/Containers/Example/ExampleScreen.js +++ b/App/Containers/Example/ExampleScreen.js @@ -12,6 +12,10 @@ const instructions = Platform.select({ }) class ExampleScreen extends React.Component { + componentDidMount() { + this.props.fetchTemperature() + } + render() { let temperature = this.props.temperatureIsLoading ? '...' : this.props.temperature if (temperature === null) { From 165aaec409c55058868e259cedad888646ff4569 Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Wed, 5 Sep 2018 17:26:04 +0200 Subject: [PATCH 07/19] Add missing link to the Services documentation and directory --- App/Services/README.md | 2 +- README.md | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/App/Services/README.md b/App/Services/README.md index cb1a72c83..849dd5ba3 100644 --- a/App/Services/README.md +++ b/App/Services/README.md @@ -1 +1 @@ -This directory contains services that are meant to connect the application to other APIs, for example +This directory contains services that are meant to connect the application to other APIs, for example an API client for Yahoo's weather service. diff --git a/README.md b/README.md index bde50f3bd..b7ec0e1b8 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ This boilerplate contains: - [`App/Images`](App/Images): images used by the application - [`App/Stores`](App/Stores): redux [actions, reducers and stores](https://redux.js.org/basics) - [`App/Sagas`](App/Sagas): redux sagas +- [`App/Services`](App/Services): application services - [`App/Theme`](App/Theme): base styles for the application For more information on each directory, click the link and read the directory's README. From 89dd3e75847372f78b53e8b46ba63e15e6f8f121 Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Wed, 5 Sep 2018 17:27:05 +0200 Subject: [PATCH 08/19] Improve comment --- App/Sagas/StartupSaga.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/App/Sagas/StartupSaga.js b/App/Sagas/StartupSaga.js index ae34b159b..8f691cd01 100644 --- a/App/Sagas/StartupSaga.js +++ b/App/Sagas/StartupSaga.js @@ -9,8 +9,10 @@ export function* startup() { // Dispatch a redux action using `put()` // @see https://redux-saga.js.org/docs/basics/DispatchingActions.html yield put(ExampleActions.fetchTemperature()) - // Do operation here : + + // Add more operations you need to do at startup here // ... - // When operations are finished redirect to InitialPage + + // When those operations are finished we redirect to the main screen NavigationService.navigateAndReset('InitialPage') } From 649d1c184c34812ab8ce3a95be2c6ea68fabed7b Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Wed, 5 Sep 2018 17:30:12 +0200 Subject: [PATCH 09/19] Add comment --- App/Containers/Root/RootScreen.js | 1 + 1 file changed, 1 insertion(+) diff --git a/App/Containers/Root/RootScreen.js b/App/Containers/Root/RootScreen.js index c098326ca..d4999a733 100644 --- a/App/Containers/Root/RootScreen.js +++ b/App/Containers/Root/RootScreen.js @@ -21,6 +21,7 @@ const AppNav = createStackNavigator( class RootScreen extends Component { componentDidMount() { + // Run the startup saga when the application is starting this.props.startup() } From a0d189c3343eda0daf704749bcb0d3a32d0db65a Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Wed, 5 Sep 2018 17:31:06 +0200 Subject: [PATCH 10/19] Code formatting to match other files --- App/Containers/Root/RootScreen.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/App/Containers/Root/RootScreen.js b/App/Containers/Root/RootScreen.js index d4999a733..a09f65011 100644 --- a/App/Containers/Root/RootScreen.js +++ b/App/Containers/Root/RootScreen.js @@ -16,7 +16,7 @@ const AppNav = createStackNavigator( { initialRouteName: 'SplashScreen', headerMode: 'none', - } + }, ) class RootScreen extends Component { @@ -37,6 +37,7 @@ class RootScreen extends Component { ) } } + const mapStateToProps = (state) => ({}) const mapDispatchToProps = (dispatch) => ({ From 768150d19b07ab6cf011776cbc4ae5fc6e0ac822 Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Wed, 5 Sep 2018 17:35:26 +0200 Subject: [PATCH 11/19] Code formatting --- App/Containers/Root/RootScreen.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/App/Containers/Root/RootScreen.js b/App/Containers/Root/RootScreen.js index a09f65011..98a79416e 100644 --- a/App/Containers/Root/RootScreen.js +++ b/App/Containers/Root/RootScreen.js @@ -16,7 +16,7 @@ const AppNav = createStackNavigator( { initialRouteName: 'SplashScreen', headerMode: 'none', - }, + } ) class RootScreen extends Component { From 49ddf51706c4981b74d2c5c02537df9700fd0d5c Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Wed, 5 Sep 2018 17:36:28 +0200 Subject: [PATCH 12/19] Add comment --- App/Containers/Root/RootScreen.js | 1 + 1 file changed, 1 insertion(+) diff --git a/App/Containers/Root/RootScreen.js b/App/Containers/Root/RootScreen.js index 98a79416e..7be77eca2 100644 --- a/App/Containers/Root/RootScreen.js +++ b/App/Containers/Root/RootScreen.js @@ -14,6 +14,7 @@ const AppNav = createStackNavigator( InitialPage: { screen: ExampleScreen }, }, { + // By default the application will show the splash screen initialRouteName: 'SplashScreen', headerMode: 'none', } From 37a5cc6eeba7fbd552c601c651633c876c739568 Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Wed, 5 Sep 2018 17:37:13 +0200 Subject: [PATCH 13/19] Rename `InitialPage` to `MainScreen` --- App/Containers/Root/RootScreen.js | 2 +- App/Sagas/StartupSaga.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/App/Containers/Root/RootScreen.js b/App/Containers/Root/RootScreen.js index 7be77eca2..7919c2893 100644 --- a/App/Containers/Root/RootScreen.js +++ b/App/Containers/Root/RootScreen.js @@ -11,7 +11,7 @@ import StartupActions from 'App/Stores/Startup/Actions' const AppNav = createStackNavigator( { SplashScreen: { screen: SplashScreen }, - InitialPage: { screen: ExampleScreen }, + MainScreen: { screen: ExampleScreen }, }, { // By default the application will show the splash screen diff --git a/App/Sagas/StartupSaga.js b/App/Sagas/StartupSaga.js index 8f691cd01..abcfbefaa 100644 --- a/App/Sagas/StartupSaga.js +++ b/App/Sagas/StartupSaga.js @@ -14,5 +14,5 @@ export function* startup() { // ... // When those operations are finished we redirect to the main screen - NavigationService.navigateAndReset('InitialPage') + NavigationService.navigateAndReset('MainScreen') } From a7bd25c2e64d031ec7915beefc10994a4b435b06 Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Wed, 5 Sep 2018 17:38:59 +0200 Subject: [PATCH 14/19] Mention the navigation in the README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 6a2c50d13..a0b52d4fb 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ This boilerplate contains: - an empty React Native application created with `react-native init` - [prettier](https://prettier.io/) and [eslint](https://eslint.org/) preconfigured for React Native - a [directory layout](#directory-layout) for organizing the code of the application +- a navigation using [react-native-navigation](https://github.com/wix/react-native-navigation) ## Directory layout From 3a44597b955fbb24dfc3cc9b5b484bfb2765ea13 Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Wed, 5 Sep 2018 17:42:18 +0200 Subject: [PATCH 15/19] Update wrong link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a0b52d4fb..eb1ffb5a1 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ This boilerplate contains: - an empty React Native application created with `react-native init` - [prettier](https://prettier.io/) and [eslint](https://eslint.org/) preconfigured for React Native - a [directory layout](#directory-layout) for organizing the code of the application -- a navigation using [react-native-navigation](https://github.com/wix/react-native-navigation) +- a navigation using [react-native-navigation](https://reactnavigation.org) ## Directory layout From bf774f13250db1c8581a8e90b04088c4d97903ee Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Wed, 5 Sep 2018 17:42:27 +0200 Subject: [PATCH 16/19] Add comment --- App/Containers/Root/RootScreen.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/App/Containers/Root/RootScreen.js b/App/Containers/Root/RootScreen.js index 7919c2893..383390c98 100644 --- a/App/Containers/Root/RootScreen.js +++ b/App/Containers/Root/RootScreen.js @@ -8,6 +8,11 @@ import SplashScreen from 'App/Containers/SplashScreen/SplashScreen' import { connect } from 'react-redux' import StartupActions from 'App/Stores/Startup/Actions' +/** + * The root screen contains the application's navigation. + * + * The navigation is handled using https://reactnavigation.org + */ const AppNav = createStackNavigator( { SplashScreen: { screen: SplashScreen }, From 1b8b5f9cbad3f24ac88aa108382235ea47489ca5 Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Wed, 5 Sep 2018 17:46:01 +0200 Subject: [PATCH 17/19] Document the navigation --- App/Containers/Root/RootScreen.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/App/Containers/Root/RootScreen.js b/App/Containers/Root/RootScreen.js index 383390c98..52fc42936 100644 --- a/App/Containers/Root/RootScreen.js +++ b/App/Containers/Root/RootScreen.js @@ -11,12 +11,13 @@ import StartupActions from 'App/Stores/Startup/Actions' /** * The root screen contains the application's navigation. * - * The navigation is handled using https://reactnavigation.org + * @see https://reactnavigation.org/docs/en/hello-react-navigation.html#creating-a-stack-navigator */ const AppNav = createStackNavigator( { - SplashScreen: { screen: SplashScreen }, - MainScreen: { screen: ExampleScreen }, + // Create the application routes here (the key is the route name, the value is the target screen) + SplashScreen: SplashScreen, + MainScreen: ExampleScreen, }, { // By default the application will show the splash screen From 1a20979cbb4c8c7b49bc54638ff30dcf93d34792 Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Wed, 12 Sep 2018 10:06:35 +0200 Subject: [PATCH 18/19] Reword the README following the merge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e19932230..b388048d4 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ The boilerplate contains: - [reduxsauce](https://github.com/infinitered/reduxsauce) (v0.7) to facilitate using Redux - [apisauce](https://github.com/infinitered/apisauce) (v0.15) to make [axios](https://github.com/axios/axios) even better - [prettier](https://prettier.io/) and [eslint](https://eslint.org/) preconfigured for React Native -- a navigation using [react-native-navigation](https://reactnavigation.org) +- [react-native-navigation](https://reactnavigation.org) (v2.12) for the application's navigation ## Updates From f74606e227fa368146e06d1612e2723f86da33e9 Mon Sep 17 00:00:00 2001 From: Matthieu Napoli Date: Mon, 24 Sep 2018 10:59:11 +0200 Subject: [PATCH 19/19] Add documentation for the navigation --- App/Containers/Root/RootScreen.js | 3 +++ App/Services/NavigationService.js | 33 ++++++++++++++++++++++++++----- App/Services/README.md | 2 +- README.md | 2 +- 4 files changed, 33 insertions(+), 7 deletions(-) diff --git a/App/Containers/Root/RootScreen.js b/App/Containers/Root/RootScreen.js index 52fc42936..83264b80f 100644 --- a/App/Containers/Root/RootScreen.js +++ b/App/Containers/Root/RootScreen.js @@ -16,12 +16,14 @@ import StartupActions from 'App/Stores/Startup/Actions' const AppNav = createStackNavigator( { // Create the application routes here (the key is the route name, the value is the target screen) + // See https://reactnavigation.org/docs/en/stack-navigator.html#routeconfigs SplashScreen: SplashScreen, MainScreen: ExampleScreen, }, { // By default the application will show the splash screen initialRouteName: 'SplashScreen', + // See https://reactnavigation.org/docs/en/stack-navigator.html#stacknavigatorconfig headerMode: 'none', } ) @@ -36,6 +38,7 @@ class RootScreen extends Component { return ( { NavigationService.setTopLevelNavigator(navigatorRef) }} diff --git a/App/Services/NavigationService.js b/App/Services/NavigationService.js index 4fd9866e7..73b387024 100644 --- a/App/Services/NavigationService.js +++ b/App/Services/NavigationService.js @@ -1,13 +1,28 @@ import { NavigationActions, StackActions } from 'react-navigation' -let _navigator +/** + * The navigation is implemented as a service so that it can be used outside of components, for example in sagas. + * + * @see https://reactnavigation.org/docs/en/navigating-without-navigation-prop.html + */ +let navigator + +/** + * This function is called when the RootScreen is created to set the navigator instance to use. + */ function setTopLevelNavigator(navigatorRef) { - _navigator = navigatorRef + navigator = navigatorRef } +/** + * Call this function when you want to navigate to a specific route. + * + * @param routeName The name of the route to navigate to. Routes are defined in RootScreen using createStackNavigator() + * @param params Route parameters. + */ function navigate(routeName, params) { - _navigator.dispatch( + navigator.dispatch( NavigationActions.navigate({ routeName, params, @@ -15,8 +30,17 @@ function navigate(routeName, params) { ) } +/** + * Call this function when you want to navigate to a specific route AND reset the navigation history. + * + * That means the user cannot go back. This is useful for example to redirect from a splashscreen to + * the main screen: the user should not be able to go back to the splashscreen. + * + * @param routeName The name of the route to navigate to. Routes are defined in RootScreen using createStackNavigator() + * @param params Route parameters. + */ function navigateAndReset(routeName, params) { - _navigator.dispatch( + navigator.dispatch( StackActions.reset({ index: 0, key: null, @@ -30,7 +54,6 @@ function navigateAndReset(routeName, params) { ) } -// add other navigation functions that you need and export them export default { navigate, navigateAndReset, diff --git a/App/Services/README.md b/App/Services/README.md index 849dd5ba3..4a91eb443 100644 --- a/App/Services/README.md +++ b/App/Services/README.md @@ -1 +1 @@ -This directory contains services that are meant to connect the application to other APIs, for example an API client for Yahoo's weather service. +This directory contains application services, for example services to connect the application to APIs. diff --git a/README.md b/README.md index b388048d4..4ae36f642 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ The boilerplate contains: - [reduxsauce](https://github.com/infinitered/reduxsauce) (v0.7) to facilitate using Redux - [apisauce](https://github.com/infinitered/apisauce) (v0.15) to make [axios](https://github.com/axios/axios) even better - [prettier](https://prettier.io/) and [eslint](https://eslint.org/) preconfigured for React Native -- [react-native-navigation](https://reactnavigation.org) (v2.12) for the application's navigation +- [react-native-navigation](https://reactnavigation.org) (v2.12) with a [`NavigationService`](App/Services/NavigationService.js) for the application's navigation ## Updates