generator-wolmo-bootstrap-rn
Advanced tools
Comparing version 0.3.3 to 0.3.4
@@ -144,3 +144,2 @@ // BASE PATHS | ||
// TEST | ||
module.exports.ARRAY_UTILS_TESTS = `${module.exports.TEST_PATH}/utils/arrayUtils.spec.js`; | ||
module.exports.TEST_ESLINT_CONFIG = `${module.exports.TEST_PATH}/.eslintrc.js`; |
@@ -29,3 +29,2 @@ const { copyFile, copyTemplateFile } = require('../../utils'); | ||
ARRAY_UTILS, | ||
ARRAY_UTILS_TESTS, | ||
TEST_ESLINT_CONFIG, | ||
@@ -73,3 +72,2 @@ HOME_STYLES, | ||
ARRAY_UTILS, | ||
ARRAY_UTILS_TESTS, | ||
I18N_CONFIG, | ||
@@ -76,0 +74,0 @@ I18N_UTILS, |
@@ -22,3 +22,4 @@ const latestSemver = require('latest-semver'); | ||
'react-native-config', | ||
'react-native-i18n' | ||
'react-native-i18n', | ||
'redux-recompose' | ||
]; | ||
@@ -25,0 +26,0 @@ |
@@ -5,3 +5,3 @@ import React, { Component } from 'react'; | ||
import { connect } from 'react-redux'; | ||
import { NavigationActions, addNavigationHelpers } from 'react-navigation'; | ||
import { NavigationActions } from 'react-navigation'; | ||
import { createReduxBoundAddListener } from 'react-navigation-redux-helpers'; | ||
@@ -31,7 +31,9 @@ | ||
render() { | ||
const { dispatch, nav, ...navigatorProps } = this.props; | ||
return ( | ||
<Navigator | ||
{...navigatorProps} | ||
navigation={addNavigationHelpers({ dispatch, state: nav, addListener: this.addListener })} | ||
navigation={{ | ||
dispatch: this.props.dispatch, | ||
state: this.props.nav, | ||
addListener: this.addListener | ||
}} | ||
/> | ||
@@ -38,0 +40,0 @@ ); |
@@ -24,5 +24,5 @@ import React, { Component } from 'react'; | ||
const mapStateToProps = store => ({ | ||
loading: store.auth.loading | ||
loading: store.auth.currentUserLoading | ||
}); | ||
export default connect(mapStateToProps)(LoginContainer); |
@@ -1,67 +0,40 @@ | ||
import { NavigationActions } from 'react-navigation'; | ||
import { StackActions, NavigationActions } from 'react-navigation'; | ||
import { createTypes, completeTypes, withPostSuccess } from 'redux-recompose'; | ||
import * as AuthService from '../../services/AuthService'; | ||
import { stringArrayToObject } from '../../utils/arrayUtils'; | ||
import * as Routes from '../../constants/routes'; | ||
export const actions = stringArrayToObject( | ||
['LOGIN', 'LOGIN_SUCCESS', 'LOGIN_FAILURE', 'LOGOUT', 'AUTH_INIT'], | ||
'@@AUTH' | ||
); | ||
export const actions = createTypes(completeTypes(['LOGIN'], ['AUTH_INIT', 'LOGOUT']), '@@AUTH'); | ||
const privateActionCreators = { | ||
loginSuccess(authData) { | ||
return { | ||
type: actions.LOGIN_SUCCESS, | ||
payload: { authData } | ||
}; | ||
}, | ||
loginFailure(err) { | ||
return { | ||
type: actions.LOGIN_FAILURE, | ||
payload: { err } | ||
}; | ||
} | ||
}; | ||
const loginTarget = 'currentUser'; | ||
export const actionCreators = { | ||
init(user) { | ||
return { | ||
type: actions.AUTH_INIT, | ||
payload: { user } | ||
}; | ||
}, | ||
login(authData) { | ||
return async dispatch => { | ||
dispatch({ type: actions.LOGIN }); | ||
try { | ||
const response = await AuthService.login(authData); | ||
if (response.ok) { | ||
await AuthService.setCurrentUser(response.data); | ||
dispatch(privateActionCreators.loginSuccess(response.data)); | ||
dispatch( | ||
NavigationActions.reset({ | ||
index: 0, | ||
actions: [NavigationActions.navigate({ routeName: 'Home' })] | ||
}) | ||
); | ||
} else { | ||
throw new Error('Invalid credentials'); | ||
} | ||
} catch (e) { | ||
dispatch(privateActionCreators.loginFailure(e)); | ||
} | ||
}; | ||
}, | ||
logout() { | ||
return async dispatch => { | ||
await AuthService.removeCurrentUser(); | ||
dispatch({ type: actions.LOGOUT }); | ||
dispatch( | ||
NavigationActions.reset({ | ||
index: 0, | ||
actions: [NavigationActions.navigate({ routeName: 'Login' })] | ||
}) | ||
); | ||
}; | ||
init: user => ({ type: actions.AUTH_INIT, target: loginTarget, payload: user }), | ||
login: authData => ({ | ||
type: actions.LOGIN, | ||
target: loginTarget, | ||
service: AuthService.login, | ||
payload: authData, | ||
injections: [ | ||
withPostSuccess(async (dispatch, response) => { | ||
await AuthService.setCurrentUser(response.data); | ||
dispatch( | ||
StackActions.reset({ | ||
index: 0, | ||
actions: [NavigationActions.navigate({ routeName: Routes.Home })] | ||
}) | ||
); | ||
}) | ||
] | ||
}), | ||
logout: () => async dispatch => { | ||
await AuthService.removeCurrentUser(); | ||
dispatch({ type: actions.LOGOUT, target: loginTarget }); | ||
dispatch( | ||
StackActions.reset({ | ||
index: 0, | ||
actions: [NavigationActions.navigate({ routeName: Routes.Login })] | ||
}) | ||
); | ||
} | ||
}; |
@@ -0,1 +1,2 @@ | ||
import { createReducer, completeReducer, completeState, onSuccess } from 'redux-recompose'; | ||
import Immutable from 'seamless-immutable'; | ||
@@ -6,36 +7,21 @@ import PropTypes from 'prop-types'; | ||
const defaultState = { | ||
const stateDescription = { | ||
currentUser: null, | ||
loading: false, | ||
initialLoading: true | ||
}; | ||
/* eslint-disable complexity */ | ||
export default function reducer(state = Immutable(defaultState), action) { | ||
switch (action.type) { | ||
case actions.AUTH_INIT: { | ||
return state.merge({ initialLoading: false, currentUser: action.payload.user }); | ||
} | ||
case actions.LOGIN: { | ||
return state.merge({ loading: true }); | ||
} | ||
case actions.LOGIN_SUCCESS: { | ||
return state.merge({ loading: false, currentUser: action.payload.authData }); | ||
} | ||
case actions.LOGIN_FAILURE: { | ||
return state.merge({ loading: false, currentUser: null, err: action.payload.err }); | ||
} | ||
case actions.LOGOUT: { | ||
return state.merge({ loading: false, currentUser: null }); | ||
} | ||
default: { | ||
return state; | ||
} | ||
const initialState = completeState(stateDescription, ['initialLoading']); | ||
const reducerDescription = { | ||
primaryActions: [actions.LOGIN], | ||
override: { | ||
[actions.AUTH_INIT]: (state, action) => | ||
state.merge({ initialLoading: false, [action.target]: action.payload }), | ||
[actions.LOGOUT]: onSuccess() | ||
} | ||
} | ||
/* eslint-enable complexity */ | ||
}; | ||
export default createReducer(Immutable(initialState), completeReducer(reducerDescription)); | ||
export const propTypes = { | ||
loading: PropTypes.bool.isRequired, | ||
initialLoading: PropTypes.bool.isRequired, | ||
currentUser: PropTypes.shape({ | ||
@@ -42,0 +28,0 @@ email: PropTypes.string.isRequired |
@@ -1,12 +0,11 @@ | ||
import { stringArrayToObject } from '../../utils/arrayUtils'; | ||
import { createTypes } from 'redux-recompose'; | ||
export const actions = stringArrayToObject(['DRAWER_TOGGLED'], '@@DRAWER'); | ||
export const actions = createTypes(['DRAWER_TOGGLED'], '@@DRAWER'); | ||
export const actionCreators = { | ||
drawerToggled(present) { | ||
return { | ||
type: actions.DRAWER_TOGGLED, | ||
payload: { present } | ||
}; | ||
} | ||
drawerToggled: isPresent => ({ | ||
type: actions.DRAWER_TOGGLED, | ||
target: 'present', | ||
payload: isPresent | ||
}) | ||
}; |
import Immutable from 'seamless-immutable'; | ||
import PropTypes from 'prop-types'; | ||
import { createReducer, onToggle } from 'redux-recompose'; | ||
import { actions } from './actions'; | ||
export default function reducer(state = Immutable({ present: false }), action) { | ||
switch (action.type) { | ||
case actions.DRAWER_TOGGLED: { | ||
const present = | ||
!action.payload || action.payload.present === undefined ? !state.present : action.payload.present; | ||
return state.merge({ present }); | ||
} | ||
default: { | ||
return state; | ||
} | ||
} | ||
} | ||
const initialState = { | ||
present: false | ||
}; | ||
const reducerDescription = { | ||
[actions.DRAWER_TOGGLED]: onToggle() | ||
}; | ||
export default createReducer(Immutable(initialState), reducerDescription); | ||
export const propTypes = { | ||
present: PropTypes.bool.isRequired | ||
}; |
@@ -1,58 +0,46 @@ | ||
import { stringArrayToObject } from '../../utils/arrayUtils'; | ||
import { createTypes } from 'redux-recompose'; | ||
import { isAndroid } from '../../constants/platform'; | ||
import PushNotificationsService from '../../services/PushNotificationsService'; | ||
export const actions = stringArrayToObject( | ||
['REGISTER', 'UPDATE_TOKEN', 'NOTIFICATION_RECEIVED'], | ||
'@@PUSH_NOTIFICATIONS' | ||
); | ||
export const actions = createTypes(['REGISTER', 'NOTIFICATION_RECEIVED'], '@@PUSH_NOTIFICATIONS'); | ||
export const actionCreators = { | ||
register(token) { | ||
return { | ||
type: actions.REGISTER, | ||
payload: { token } | ||
}; | ||
}, | ||
updateToken() { | ||
return { | ||
type: actions.UPDATE_TOKEN | ||
}; | ||
}, | ||
notificationReceived(notification) { | ||
return dispatch => { | ||
/** | ||
* if the push was tapped by the user (userInteraction flag) trigger the push action | ||
* if the push was not tapped by the user: | ||
* a- if the push was not received while the app is in foreground it will appear in the notification bar | ||
* b- if the push was received while the app is in foreground it wont appear in the notification bar so | ||
* 1- android: trigger a local notification that will appear in the notification bar | ||
* 2- ios: display an alert | ||
*/ | ||
const handler = PushNotificationsService.getPushNotificationHandler( | ||
isAndroid ? notification.type : notification.data.type | ||
); | ||
register: token => ({ | ||
type: actions.REGISTER, | ||
target: 'token', | ||
payload: token | ||
}), | ||
notificationReceived: notification => dispatch => { | ||
/** | ||
* if the push was tapped by the user (userInteraction flag) trigger the push action | ||
* if the push was not tapped by the user: | ||
* a- if the push was not received while the app is in foreground it will appear in the notification bar | ||
* b- if the push was received while the app is in foreground it wont appear in the notification bar so | ||
* 1- android: trigger a local notification that will appear in the notification bar | ||
* 2- ios: display an alert | ||
*/ | ||
const handler = PushNotificationsService.getPushNotificationHandler( | ||
isAndroid ? notification.type : notification.data.type | ||
); | ||
if (notification.userInteraction) { | ||
handler(dispatch, isAndroid ? notification : notification.data); | ||
} else if (notification.foreground) { | ||
if (isAndroid) { | ||
PushNotificationsService.triggerLocalNotification(notification); | ||
} else { | ||
PushNotificationsService.displayPushNotificationPrompt( | ||
notification.alert | ||
).then(triggerPushAction => { | ||
if (triggerPushAction) { | ||
handler(dispatch, notification.data); | ||
} | ||
}); | ||
} | ||
if (notification.userInteraction) { | ||
handler(dispatch, isAndroid ? notification : notification.data); | ||
} else if (notification.foreground) { | ||
if (isAndroid) { | ||
PushNotificationsService.triggerLocalNotification(notification); | ||
} else { | ||
PushNotificationsService.displayPushNotificationPrompt(notification.alert).then(triggerPushAction => { | ||
if (triggerPushAction) { | ||
handler(dispatch, notification.data); | ||
} | ||
}); | ||
} | ||
} | ||
dispatch({ | ||
type: actions.NOTIFICATION_RECEIVED, | ||
payload: { notification } | ||
}); | ||
}; | ||
dispatch({ | ||
type: actions.NOTIFICATION_RECEIVED, | ||
payload: { notification } | ||
}); | ||
} | ||
}; |
@@ -0,1 +1,2 @@ | ||
import { createReducer, onReadValue } from 'redux-recompose'; | ||
import Immutable from 'seamless-immutable'; | ||
@@ -6,3 +7,3 @@ import PropTypes from 'prop-types'; | ||
const defaultState = { | ||
const initialState = { | ||
unreadNotifications: [], | ||
@@ -13,29 +14,22 @@ readNotifications: [], | ||
/* eslint-disable complexity */ | ||
export default function reducer(state = Immutable(defaultState), action) { | ||
switch (action.type) { | ||
case actions.REGISTER: { | ||
return state.merge({ token: action.payload.token }, { deep: true }); | ||
} | ||
case actions.NOTIFICATION_RECEIVED: { | ||
const push = action.payload.notification; | ||
return state.merge( | ||
{ | ||
unreadNotifications: push.userInteraction | ||
? state.unreadNotifications.filter(unreadPush => push.id !== unreadPush.id) | ||
: state.unreadNotifications.concat([push]), | ||
readNotifications: push.userInteraction | ||
? state.readNotifications.concat([push]) | ||
: state.readNotifications | ||
}, | ||
{ deep: true } | ||
); | ||
} | ||
default: { | ||
return state; | ||
} | ||
const reducerDescription = { | ||
[actions.REGISTER]: onReadValue(), | ||
[actions.NOTIFICATION_RECEIVED]: (state, action) => { | ||
const push = action.payload.notification; | ||
return state.merge( | ||
{ | ||
unreadNotifications: push.userInteraction | ||
? state.unreadNotifications.filter(unreadPush => push.id !== unreadPush.id) | ||
: state.unreadNotifications.concat([push]), | ||
readNotifications: push.userInteraction | ||
? state.readNotifications.concat([push]) | ||
: state.readNotifications | ||
}, | ||
{ deep: true } | ||
); | ||
} | ||
} | ||
/* eslint-enable complexity */ | ||
}; | ||
export default createReducer(Immutable(initialState), reducerDescription); | ||
const notificationPropTypes = PropTypes.shape({ | ||
@@ -42,0 +36,0 @@ id: PropTypes.string.isRequired |
@@ -1,2 +0,1 @@ | ||
import Immutable from 'seamless-immutable'; | ||
import flatten from 'lodash/flatten'; | ||
@@ -6,17 +5,2 @@ import isObject from 'lodash/isObject'; | ||
/** | ||
* Receives an array of strings, and returns an obj with that strings as properties with that string as value. | ||
* E.G: | ||
* stringArrayToObject(['A', 'B', 'C']) // { A: 'A', B: 'B', C: 'C' } | ||
*/ | ||
export function stringArrayToObject(actionsArray, namespace) { | ||
if (actionsArray.some(actionName => !actionName || typeof actionName !== 'string')) { | ||
throw new Error('Action names must be strings and must not be empty'); | ||
} | ||
return Immutable(actionsArray).asObject(actionName => [ | ||
actionName, | ||
namespace ? `${namespace}:${actionName}` : actionName | ||
]); | ||
} | ||
export function mergeObjects(roles) { | ||
@@ -23,0 +7,0 @@ const merger = (a, b) => { |
{ | ||
"name": "generator-wolmo-bootstrap-rn", | ||
"version": "0.3.3", | ||
"version": "0.3.4", | ||
"description": "", | ||
@@ -5,0 +5,0 @@ "files": [ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
158416
108
2278