From 08a896364cdd3b1a47af6435c49754ba67175dad Mon Sep 17 00:00:00 2001 From: Bruno Lemos Date: Sun, 27 Nov 2016 05:50:24 -0200 Subject: [PATCH] Loading user feed using redux-saga --- .../main/java/com/devhub/MainApplication.java | 4 -- src/actions/index.js | 17 ++++++-- src/api/github.js | 3 ++ src/components/ThemeProvider.js | 6 +-- src/containers/HomeScreen.js | 35 +++++++++++------ src/index.js | 13 ------- src/reducers/feed.js | 39 +++++++++++-------- src/sagas/index.js | 27 ++++++++----- src/store.js | 3 +- src/utils/constants/actions.js | 6 +-- src/utils/helpers/actions.js | 14 ++++++- src/utils/types/actions.js | 12 +++--- 12 files changed, 105 insertions(+), 74 deletions(-) create mode 100644 src/api/github.js diff --git a/android/app/src/main/java/com/devhub/MainApplication.java b/android/app/src/main/java/com/devhub/MainApplication.java index c57302d9..e06c750b 100644 --- a/android/app/src/main/java/com/devhub/MainApplication.java +++ b/android/app/src/main/java/com/devhub/MainApplication.java @@ -4,8 +4,6 @@ import android.app.Application; import android.util.Log; import com.facebook.react.ReactApplication; -import com.rnfs.RNFSPackage; -import com.rnfs.RNFSPackage; import com.BV.LinearGradient.LinearGradientPackage; import com.reactnativenavigation.NavigationReactPackage; import com.oblador.vectoricons.VectorIconsPackage; @@ -31,8 +29,6 @@ public class MainApplication extends Application implements ReactApplication { protected List getPackages() { return Arrays.asList( new MainReactPackage(), - new RNFSPackage(), - new RNFSPackage(), new LinearGradientPackage(), new NavigationReactPackage(), new VectorIconsPackage(), diff --git a/src/actions/index.js b/src/actions/index.js index 3ea89589..8f306c5a 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -3,11 +3,22 @@ import { SET_THEME, - LOAD_FEED_REQUEST, + LOAD_USER_FEED_REQUEST, + LOAD_USER_FEED_SUCCESS, + LOAD_USER_FEED_FAILURE, } from '../utils/constants/actions'; -import { action } from '../utils/helpers/actions'; +import { action, errorAction } from '../utils/helpers/actions'; import type { Theme } from '../utils/types'; export const setTheme = (theme: Theme) => action(SET_THEME, theme); -export const loadFeedRequest = () => action(LOAD_FEED_REQUEST); + +export const loadUserFeedRequest = (username: string) => ( + action(LOAD_USER_FEED_REQUEST, { username }) +); + +export const loadUserFeedSuccess = (username: string, data: any, meta: Object) => ( + action(LOAD_USER_FEED_SUCCESS, { username, data, meta }) +); + +export const loadUserFeedFailure = (error: any) => errorAction(LOAD_USER_FEED_FAILURE, error); diff --git a/src/api/github.js b/src/api/github.js new file mode 100644 index 00000000..fd9bebc2 --- /dev/null +++ b/src/api/github.js @@ -0,0 +1,3 @@ +import GitHubAPI from 'github'; + +export default new GitHubAPI(); diff --git a/src/components/ThemeProvider.js b/src/components/ThemeProvider.js index 7921ee74..61010514 100644 --- a/src/components/ThemeProvider.js +++ b/src/components/ThemeProvider.js @@ -19,12 +19,8 @@ export default class extends React.Component { theme: this.props.theme || this.context.theme, }); - children: { - theme: ThemeObject, - }; - props: { - children: React.Element<*>, + children?: ?React.Element<*>, theme: ThemeObject, }; diff --git a/src/containers/HomeScreen.js b/src/containers/HomeScreen.js index e45f0013..20ca125b 100644 --- a/src/containers/HomeScreen.js +++ b/src/containers/HomeScreen.js @@ -6,21 +6,34 @@ import { connect } from 'react-redux'; import Columns from '../components/Columns'; import Screen from '../components/Screen'; import ThemeProvider from '../components/ThemeProvider'; +import { loadUserFeedRequest } from '../actions'; import { loadTheme } from '../reducers/config'; import type { State, ThemeObject } from '../utils/types'; -type Props = State & { - theme: ThemeObject, -}; +class Page extends React.Component { + componentDidMount() { + this.props.loadUserFeedRequest('brunolemos'); + } -const Page = ({ feed, theme }: Props) => ( - - - - - -); + props: State & { + theme: ThemeObject, + loadUserFeedRequest: Function, + }; + + render() { + const { feed, theme } = this.props; + + return ( + + + + + + ); + } +} const mapStateToProps = ({ feed, config }: State) => ({ feed, theme: loadTheme(config) }); +const mapDispatchToProps = { loadUserFeedRequest }; -export default connect(mapStateToProps)(Page); +export default connect(mapStateToProps, mapDispatchToProps)(Page); diff --git a/src/index.js b/src/index.js index c9b7a9a9..65780dac 100644 --- a/src/index.js +++ b/src/index.js @@ -17,16 +17,3 @@ export default () => ( ); - -// import GitHubAPI from 'github'; -// -// const github = new GitHubAPI(); -// -// (async () => { -// try { -// const result = await github.activity.getEventsReceived({ username: 'brunolemos' }); -// console.log(result); -// } catch(e) { -// console.log('Error', e); -// } -// })(); diff --git a/src/reducers/feed.js b/src/reducers/feed.js index 4ca8bf68..e5a173dd 100644 --- a/src/reducers/feed.js +++ b/src/reducers/feed.js @@ -2,29 +2,34 @@ import { combineReducers } from 'redux'; -import { LOAD_FEED_SUCCESS } from '../utils/constants/actions'; +import { LOAD_USER_FEED_SUCCESS } from '../utils/constants/actions'; import type { Action } from '../utils/types'; import type { GithubEvent } from '../utils/types/github'; -// static data -import allEventsData from '../../test/data/github-bigquery.json'; -import repoEventsData from '../../test/data/github-repo-events.json'; -import userEventsData from '../../test/data/github-user-events.json'; -import userReceivedEventsData from '../../test/data/github-user-received_events.json'; +// // static data +// import allEventsData from '../../test/data/github-bigquery.json'; +// import repoEventsData from '../../test/data/github-repo-events.json'; +// import userEventsData from '../../test/data/github-user-events.json'; +// import userReceivedEventsData from '../../test/data/github-user-received_events.json'; +// +// const data = [ +// { id: 0, title: 'all', data: allEventsData }, +// { id: 1, title: 'react', data: repoEventsData }, +// { id: 2, title: 'sibelius', data: userReceivedEventsData }, +// { id: 3, title: 'brunolemos', data: userEventsData }, +// ]; -const data = [ - { id: 0, title: 'all', data: allEventsData }, - { id: 1, title: 'react', data: repoEventsData }, - { id: 2, title: 'sibelius', data: userReceivedEventsData }, - { id: 3, title: 'brunolemos', data: userEventsData }, -]; +type Column = { id: string, title: string, data: Array, meta: Object }; +type LoadUserFeedPayload = { username: string, data: Array }; +export default (state :Array = [], action: Action): Array => { + const { type, payload: { username, data } = {} } = action || {}; -export default (state:Array = data, { type, payload }: Action>): Array => { switch (type) { - case LOAD_FEED_SUCCESS: return [ - ...payload, - ...state, - ]; + case LOAD_USER_FEED_SUCCESS: return [{ + id: '0', + title: username, + data, + }]; default: return state; } }; diff --git a/src/sagas/index.js b/src/sagas/index.js index 65e87c12..bdb1fdf0 100644 --- a/src/sagas/index.js +++ b/src/sagas/index.js @@ -1,24 +1,33 @@ // @flow -import { put, takeEvery } from 'redux-saga'; +import { takeEvery } from 'redux-saga'; +import { call, put } from 'redux-saga/effects'; + +import { LOAD_USER_FEED_REQUEST } from '../utils/constants/actions'; import { - LOAD_FEED_REQUEST, -} from '../utils/constants/actions'; + loadUserFeedSuccess, + loadUserFeedFailure, +} from '../actions'; -import { loadFeedRequest } from '../actions'; +import github from '../api/github'; -export function* loadFeed(): Generator<*, *, *> { - yield put(loadFeedRequest()) +export function* loadUserFeed({ payload: { username } = {} }: Object): Generator<*, *, *> { + try { + const { data, meta } = yield call(github.activity.getEventsReceived, { username }); + yield put(loadUserFeedSuccess(username, data, meta)) + } catch (error) { + yield put(loadUserFeedFailure(error)) + } } // Our watcher Saga: spawn a new incrementAsync task on each INCREMENT_ASYNC -export function* watchLoadFeed(): Generator<*, *, *> { - yield takeEvery(LOAD_FEED_REQUEST, loadFeed) +export function* watchloadUserFeed(): Generator<*, *, *> { + yield takeEvery(LOAD_USER_FEED_REQUEST, loadUserFeed) } export default function* (): Generator<*, *, *> { return yield [ - watchLoadFeed + watchloadUserFeed() ]; } diff --git a/src/store.js b/src/store.js index a492e08f..33286083 100644 --- a/src/store.js +++ b/src/store.js @@ -26,7 +26,6 @@ const store = createStoreWithNavigation( sagaMiddleware.run(sagas); -// TODO: Don't ignore feed -persistStore(store, { storage: AsyncStorage, whitelist: ['config'] }); +persistStore(store, { storage: AsyncStorage, blacklist: ['navigation'] }); export default store; diff --git a/src/utils/constants/actions.js b/src/utils/constants/actions.js index 71f28fa7..e1e2bc1d 100644 --- a/src/utils/constants/actions.js +++ b/src/utils/constants/actions.js @@ -2,6 +2,6 @@ /* eslint-disable import/prefer-default-export */ export const SET_THEME = 'SET_THEME'; -export const LOAD_FEED_REQUEST = 'LOAD_FEED_REQUEST'; -export const LOAD_FEED_SUCCESS = 'LOAD_FEED_SUCCESS'; -export const LOAD_FEED_FAILURE = 'LOAD_FEED_FAILURE'; +export const LOAD_USER_FEED_REQUEST = 'LOAD_USER_FEED_REQUEST'; +export const LOAD_USER_FEED_SUCCESS = 'LOAD_USER_FEED_SUCCESS'; +export const LOAD_USER_FEED_FAILURE = 'LOAD_USER_FEED_FAILURE'; diff --git a/src/utils/helpers/actions.js b/src/utils/helpers/actions.js index 302b7f74..f61dc54c 100644 --- a/src/utils/helpers/actions.js +++ b/src/utils/helpers/actions.js @@ -3,7 +3,7 @@ import type { ActionType } from '../types'; /** - * Create the action object + * Create an action object * * Example: * action('LOGIN_REQUEST', { email, password }) @@ -13,3 +13,15 @@ import type { ActionType } from '../types'; export function action(type: ActionType, payload: any) { return { type, payload }; } + +/** + * Create an action error object + * + * Example: + * errorAction('LOGIN_FAILURE', { message: 'No internet connection' }) + * produces + * { type: 'LOGIN_FAILURE', error: { message: '...' } } + */ +export function errorAction(type: ActionType, error: any) { + return { type, error }; +} diff --git a/src/utils/types/actions.js b/src/utils/types/actions.js index 703952b5..2d528c07 100644 --- a/src/utils/types/actions.js +++ b/src/utils/types/actions.js @@ -4,15 +4,15 @@ */ export type SET_THEME = 'SET_THEME'; -export type LOAD_FEED_REQUEST = 'LOAD_FEED_REQUEST'; -export type LOAD_FEED_SUCCESS = 'LOAD_FEED_SUCCESS'; -export type LOAD_FEED_FAILURE = 'LOAD_FEED_FAILURE'; +export type LOAD_USER_FEED_REQUEST = 'LOAD_USER_FEED_REQUEST'; +export type LOAD_USER_FEED_SUCCESS = 'LOAD_USER_FEED_SUCCESS'; +export type LOAD_USER_FEED_FAILURE = 'LOAD_USER_FEED_FAILURE'; export type ActionType = | SET_THEME - | LOAD_FEED_REQUEST - | LOAD_FEED_SUCCESS - | LOAD_FEED_FAILURE; + | LOAD_USER_FEED_REQUEST + | LOAD_USER_FEED_SUCCESS + | LOAD_USER_FEED_FAILURE; export type Action = { type: ActionType,