diff --git a/src/actions/index.js b/src/actions/index.js
index 01354ba..e46c7cb 100644
--- a/src/actions/index.js
+++ b/src/actions/index.js
@@ -3,6 +3,7 @@ import {
CHANGE_USER_REQUESTED,
CLEAR_USER_DATA_REQUESTED,
CLEAR_USER_DATA_SUCCEEDED,
+ FETCH_CURRENT_USER_REQUESTED,
LAST_USER_LOGGED_REQUESTED,
USER_LOGIN_FAILED,
USER_LOGIN_REQUESTED,
@@ -19,6 +20,7 @@ export {ERROR_OCCURRED};
export {CHANGE_USER_REQUESTED};
export {CLEAR_USER_DATA_REQUESTED};
export {CLEAR_USER_DATA_SUCCEEDED};
+export {FETCH_CURRENT_USER_REQUESTED};
export {LAST_USER_LOGGED_REQUESTED};
export {USER_LOGIN_REQUESTED};
export {USER_LOGIN_SUCCEEDED};
diff --git a/src/actions/session.js b/src/actions/session.js
index e5429b2..360fb2e 100755
--- a/src/actions/session.js
+++ b/src/actions/session.js
@@ -10,25 +10,16 @@ export const requestLogin = (user, authEndpoint, redirectUri, clientCredentials)
clientCredentials
});
-export const notifyLoginFail = () => ({
- type: USER_LOGIN_FAILED
-});
+export const notifyLoginFail = () => ({type: USER_LOGIN_FAILED});
-export const notifyLoginSucceeded = () => ({
- type: USER_LOGIN_SUCCEEDED
-});
+export const notifyLoginSucceeded = () => ({type: USER_LOGIN_SUCCEEDED});
export const USER_FETCH_TOKEN_REQUESTED = 'USER_FETCH_TOKEN_REQUESTED';
export const USER_FETCH_TOKEN_SUCCEEDED = 'USER_TOKEN_SUCCEEDED';
-export const requestFetchToken = () => ({
- type: USER_FETCH_TOKEN_REQUESTED
-});
+export const requestFetchToken = () => ({type: USER_FETCH_TOKEN_REQUESTED});
-export const notifyFetchTokenSucceeded = token => ({
- type: USER_FETCH_TOKEN_SUCCEEDED,
- token
-});
+export const notifyFetchTokenSucceeded = token => ({type: USER_FETCH_TOKEN_SUCCEEDED, token});
export const USER_FETCH_REFRESH_TOKEN_REQUESTED = 'USER_FETCH_REFRESH_TOKEN_REQUESTED';
export const USER_FETCH_REFRESH_TOKEN_SUCCEEDED = 'USER_FETCH_REFRESH_TOKEN_SUCCEEDED';
@@ -40,9 +31,7 @@ export const requestFetchRefreshToken = (authEndpoint, clientId, clientSecret) =
clientSecret
});
-export const notifyFetchRefreshTokenSucceeded = () => ({
- type: USER_FETCH_REFRESH_TOKEN_SUCCEEDED
-});
+export const notifyFetchRefreshTokenSucceeded = () => ({type: USER_FETCH_REFRESH_TOKEN_SUCCEEDED});
export const USER_REFRESH_ACCESS_TOKEN_REQUESTED = 'USER_REFRESH_ACCESS_TOKEN_REQUESTED';
export const USER_REFRESH_ACCESS_TOKEN_SUCCEEDED = 'USER_REFRESH_ACCESS_TOKEN_SUCCEEDED';
@@ -54,40 +43,26 @@ export const requestFetchRefreshAccessToken = (authEndpoint, clientId, clientSec
clientSecret
});
-export const notifyRefreshAccessToken = () => ({
- type: USER_REFRESH_ACCESS_TOKEN_SUCCEEDED
-});
+export const notifyRefreshAccessToken = () => ({type: USER_REFRESH_ACCESS_TOKEN_SUCCEEDED});
export const LAST_USER_LOGGED_REQUESTED = 'LAST_USER_LOGGED_REQUESTED';
export const LAST_USER_LOGGED_SUCCEEDED = 'LAST_USER_LOGGED_SUCCEEDED';
-export const requestLastUserLogged = () => ({
- type: LAST_USER_LOGGED_REQUESTED
-});
+export const requestLastUserLogged = () => ({type: LAST_USER_LOGGED_REQUESTED});
-export const receiveLastUserLogged = lastUserLogged => ({
- type: LAST_USER_LOGGED_SUCCEEDED,
- lastUserLogged
-});
+export const receiveLastUserLogged = lastUserLogged => ({type: LAST_USER_LOGGED_SUCCEEDED, lastUserLogged});
export const CLEAR_USER_DATA_REQUESTED = 'CLEAR_USER_DATA_REQUESTED';
export const CLEAR_USER_DATA_SUCCEEDED = 'CLEAR_USER_DATA_SUCCEEDED';
-export const requestClearUserData = () => ({
- type: CLEAR_USER_DATA_REQUESTED
-});
+export const requestClearUserData = () => ({type: CLEAR_USER_DATA_REQUESTED});
-export const notifyDataCleared = () => ({
- type: CLEAR_USER_DATA_SUCCEEDED
-});
+export const notifyDataCleared = () => ({type: CLEAR_USER_DATA_SUCCEEDED});
export const CHANGE_USER_REQUESTED = 'CHANGE_USER_REQUESTED';
export const CHANGE_USER_SUCCEEDED = 'CHANGE_USER_SUCCEEDED';
-export const requestChangeUser = userProfile => ({
- type: CHANGE_USER_REQUESTED,
- userProfile
-});
+export const requestChangeUser = userProfile => ({type: CHANGE_USER_REQUESTED, userProfile});
export const userChanged = () => ({
type: CHANGE_USER_SUCCEEDED
@@ -107,3 +82,10 @@ export const CLEAN_USER_VALIDATIONS = 'CLEAN_USER_VALIDATIONS';
export const cleanUserValidations = () => ({
type: CLEAN_USER_VALIDATIONS
});
+
+export const FETCH_CURRENT_USER_REQUESTED = 'FETCH_CURRENT_USER_REQUESTED';
+export const FETCH_CURRENT_USER_SUCCEEDED = 'FETCH_CURRENT_USER_SUCCEEDED';
+
+export const requestFetchCurrentUser = () => ({type: FETCH_CURRENT_USER_REQUESTED});
+
+export const receiveCurrentUser = user => ({type: FETCH_CURRENT_USER_SUCCEEDED, user});
diff --git a/src/components/DrawerLayout/Drawer.js b/src/components/DrawerLayout/Drawer.js
new file mode 100644
index 0000000..143bc16
--- /dev/null
+++ b/src/components/DrawerLayout/Drawer.js
@@ -0,0 +1,61 @@
+import React, {Fragment} from 'react';
+import PropTypes from 'prop-types';
+import {Divider} from 'react-native-elements';
+import {isEmpty} from 'lodash';
+
+import stylePropType from '../../util/stylePropType';
+import routePropType from '../../util/routePropType';
+
+import DrawerImage from './DrawerImage';
+import Routes from './Routes';
+import User from './User';
+import Version from './Version';
+import styles from './styles';
+
+const brandImageDefault = require('../../images/brand.png');
+
+const Drawer = ({
+ routes, text, brandImage, style, rightImage, version, user
+}) => (
+
+
+ {user && }
+
+ {!isEmpty(routes) && }
+
+ {version && (
+
+ )}
+
+);
+
+Drawer.propTypes = {
+ brandImage: PropTypes.oneOfType([
+ PropTypes.number,
+ PropTypes.string
+ ]),
+ rightImage: PropTypes.oneOfType([
+ PropTypes.number,
+ PropTypes.string
+ ]),
+ style: stylePropType,
+ text: PropTypes.string,
+ version: PropTypes.string,
+ routes: PropTypes.arrayOf(routePropType),
+ user: PropTypes.shape({})
+};
+
+Drawer.defaultProps = {
+ brandImage: brandImageDefault,
+ style: {},
+ text: null,
+ rightImage: null,
+ version: null,
+ user: null,
+ routes: []
+};
+
+export default Drawer;
diff --git a/src/components/DrawerLayout/DrawerImage.js b/src/components/DrawerLayout/DrawerImage.js
new file mode 100644
index 0000000..4c6a30b
--- /dev/null
+++ b/src/components/DrawerLayout/DrawerImage.js
@@ -0,0 +1,51 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import {Image, Text, View} from 'react-native';
+
+import styles from './styles';
+
+import stylePropType from '../../util/stylePropType';
+
+const brandImageDefault = require('../../images/brand.png');
+
+const DrawerImage = ({
+ brandImage, rightImage, text, style
+}) => (
+
+
+
+
+ {text && (
+
+ {text}
+
+ )}
+ {rightImage && (
+
+
+
+ )}
+
+);
+
+DrawerImage.propTypes = {
+ brandImage: PropTypes.oneOfType([
+ PropTypes.number,
+ PropTypes.string
+ ]),
+ rightImage: PropTypes.oneOfType([
+ PropTypes.number,
+ PropTypes.string
+ ]),
+ style: stylePropType,
+ text: PropTypes.string
+};
+
+DrawerImage.defaultProps = {
+ brandImage: brandImageDefault,
+ style: {},
+ text: null,
+ rightImage: null
+};
+
+export default DrawerImage;
diff --git a/src/components/DrawerLayout/NavItem.js b/src/components/DrawerLayout/NavItem.js
new file mode 100644
index 0000000..af7bcd4
--- /dev/null
+++ b/src/components/DrawerLayout/NavItem.js
@@ -0,0 +1,43 @@
+import React, {PureComponent} from 'react';
+import PropTypes from 'prop-types';
+import {connect} from 'react-redux';
+import {Text, View} from 'react-native';
+import {Icon} from 'react-native-elements';
+import {Link} from 'react-router-native';
+
+import {requestFetchToken} from '../../actions/session';
+import getFontAwesome from '../../util/getFontAwesome';
+import routePropType from '../../util/routePropType';
+import SessionService from '../../services/session';
+
+import styles from './styles';
+
+class NavItem extends PureComponent {
+ static propTypes = {
+ requestFetchToken: PropTypes.func.isRequired,
+ route: routePropType.isRequired
+ };
+
+ async signOut(closeSession) {
+ if (closeSession) {
+ await SessionService.clearSession();
+ this.props.requestFetchToken();
+ }
+ }
+
+ render() {
+ const {route} = this.props;
+ return (
+
+
+ this.signOut(route.closeSession)}>
+
+ {route.text}
+
+
+
+ );
+ }
+}
+
+export default NavItem;
diff --git a/src/components/DrawerLayout/Routes.js b/src/components/DrawerLayout/Routes.js
new file mode 100644
index 0000000..af414f7
--- /dev/null
+++ b/src/components/DrawerLayout/Routes.js
@@ -0,0 +1,28 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import {View} from 'react-native';
+
+import routePropType from '../../util/routePropType';
+import stylePropType from '../../util/stylePropType';
+
+import NavItem from './NavItem';
+import styles from './styles';
+
+const Routes = ({routes, style}) => (
+
+ {routes.map(route => (
+
+ ))}
+
+);
+
+Routes.propTypes = {
+ routes: PropTypes.arrayOf(routePropType).isRequired,
+ style: stylePropType
+};
+
+Routes.defaultProps = {
+ style: {}
+};
+
+export default Routes;
diff --git a/src/components/DrawerLayout/User.js b/src/components/DrawerLayout/User.js
new file mode 100644
index 0000000..c4ab154
--- /dev/null
+++ b/src/components/DrawerLayout/User.js
@@ -0,0 +1,27 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import {Text, View} from 'react-native';
+
+import stylePropType from '../../util/stylePropType';
+
+import styles from './styles';
+
+const User = ({user, style}) => (
+
+
+ {`${user.name}, ${user.surname} (${user.username})`}
+
+
+);
+
+User.propTypes = {
+ user: PropTypes.shape({}),
+ style: stylePropType
+};
+
+User.defaultProps = {
+ user: {},
+ style: {}
+};
+
+export default User;
diff --git a/src/components/DrawerLayout/Version.js b/src/components/DrawerLayout/Version.js
new file mode 100644
index 0000000..a1c736e
--- /dev/null
+++ b/src/components/DrawerLayout/Version.js
@@ -0,0 +1,27 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import {Text, View} from 'react-native';
+
+import stylePropType from '../../util/stylePropType';
+
+import styles from './styles';
+
+const Version = ({version, style}) => (
+
+
+ {version}
+
+
+);
+
+Version.propTypes = {
+ version: PropTypes.string,
+ style: stylePropType
+};
+
+Version.defaultProps = {
+ version: null,
+ style: {}
+};
+
+export default Version;
diff --git a/src/components/DrawerLayout/index.js b/src/components/DrawerLayout/index.js
new file mode 100755
index 0000000..2a3271e
--- /dev/null
+++ b/src/components/DrawerLayout/index.js
@@ -0,0 +1,75 @@
+import React, {PureComponent} from 'react';
+import PropTypes from 'prop-types';
+import {connect} from 'react-redux';
+import {DrawerLayoutAndroid} from 'react-native';
+
+import {requestFetchCurrentUser} from '../../actions/session';
+import stylePropType from '../../util/stylePropType';
+import routePropType from '../../util/routePropType';
+
+import Drawer from './Drawer';
+
+const brandImageDefault = require('../../images/brand.png');
+
+class DrawerLayout extends PureComponent {
+ static propTypes = {
+ requestFetchCurrentUser: PropTypes.func.isRequired,
+ brandImage: PropTypes.oneOfType([
+ PropTypes.number,
+ PropTypes.string
+ ]),
+ rightImage: PropTypes.oneOfType([
+ PropTypes.number,
+ PropTypes.string
+ ]),
+ style: stylePropType,
+ text: PropTypes.string,
+ version: PropTypes.string,
+ routes: PropTypes.arrayOf(routePropType).isRequired,
+ token: PropTypes.string,
+ user: PropTypes.shape({}),
+ children: PropTypes.shape({}),
+ drawerRef: PropTypes.func
+ };
+
+ static defaultProps = {
+ brandImage: brandImageDefault,
+ style: {},
+ user: {},
+ token: null,
+ text: null,
+ rightImage: null,
+ version: null,
+ children: null,
+ drawerRef: null
+ };
+
+ componentDidMount() {
+ this.props.requestFetchCurrentUser();
+ }
+
+ render() {
+ const {children, drawerRef} = this.props;
+ return (
+ }
+ ref={ref => drawerRef(ref)}
+ {...this.props}
+ >
+ {children}
+
+ );
+ }
+}
+
+export default connect(
+ state => ({
+ token: state.session.token,
+ user: state.session.user
+ }),
+ dispatch => ({
+ requestFetchCurrentUser: () => dispatch(requestFetchCurrentUser())
+ })
+)(DrawerLayout);
diff --git a/src/components/DrawerLayout/index.web.js b/src/components/DrawerLayout/index.web.js
new file mode 100644
index 0000000..93b6c77
--- /dev/null
+++ b/src/components/DrawerLayout/index.web.js
@@ -0,0 +1,55 @@
+import React, {Fragment} from 'react';
+import PropTypes from 'prop-types';
+
+import stylePropType from '../../util/stylePropType';
+import routePropType from '../../util/routePropType';
+import Drawer from './Drawer';
+
+const brandImageDefault = require('../../images/brand.png');
+
+const DrawerLayout = ({
+ routes, text, brandImage, style, rightImage, version, children
+}) => (
+
+
+ {children}
+
+);
+
+DrawerLayout.propTypes = {
+ brandImage: PropTypes.oneOfType([
+ PropTypes.number,
+ PropTypes.string
+ ]),
+ rightImage: PropTypes.oneOfType([
+ PropTypes.number,
+ PropTypes.string
+ ]),
+ style: stylePropType,
+ text: PropTypes.string,
+ routes: PropTypes.arrayOf(routePropType).isRequired,
+ version: PropTypes.string,
+ children: PropTypes.shape({})
+};
+
+DrawerLayout.defaultProps = {
+ brandImage: brandImageDefault,
+ style: {
+ routesContainer: {
+ flexDirection: 'row',
+ justifyContent: 'center',
+ alignItems: 'flex-start',
+ flex: 1,
+ backgroundColor: 'grey'
+ }
+ },
+ text: null,
+ rightImage: null,
+ version: null,
+ children: {}
+};
+
+export default DrawerLayout;
diff --git a/src/components/Header/styles.js b/src/components/DrawerLayout/styles.js
similarity index 69%
rename from src/components/Header/styles.js
rename to src/components/DrawerLayout/styles.js
index 13829bd..d8c42f9 100755
--- a/src/components/Header/styles.js
+++ b/src/components/DrawerLayout/styles.js
@@ -24,13 +24,7 @@ export default StyleSheet.create({
color: '#fff'
},
navContainer: {
- height: 45,
- paddingRight: 10,
- paddingLeft: 10,
- flexDirection: 'row',
- justifyContent: 'space-around',
- alignItems: 'center',
- backgroundColor: '#dee2e3'
+ flexDirection: 'row'
},
navItem: {
alignItems: 'center'
@@ -51,5 +45,29 @@ export default StyleSheet.create({
flex: 1,
flexDirection: 'column',
alignItems: 'flex-end'
+ },
+ userContainer: {
+ flex: 1,
+ justifyContent: 'center',
+ padding: 10
+ },
+ userText: {
+ fontSize: 16
+ },
+ versionContainer: {
+ flex: 1,
+ alignItems: 'center',
+ justifyContent: 'flex-end'
+ },
+ versionText: {
+ fontSize: 16
+ },
+ routesContainer: {
+ flex: 1,
+ padding: 10,
+ justifyContent: 'space-around'
+ },
+ dividerStyle: {
+ backgroundColor: '#dee2e3'
}
});
diff --git a/src/components/Header/NavItem.js b/src/components/Header/NavItem.js
deleted file mode 100644
index 1664bf6..0000000
--- a/src/components/Header/NavItem.js
+++ /dev/null
@@ -1,34 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import {Text} from 'react-native';
-import {Icon} from 'react-native-elements';
-import {Link} from 'react-router-native';
-
-import getFontAwesome from '../../util/getFontAwesome';
-import routePropType from '../../util/routePropType';
-import Col from '../Col';
-import Row from '../Row';
-import styles from './styles';
-
-const NavItem = ({onLogout, route}) => (
-
-
-
- onLogout(route)}>
-
- {route.text}
-
-
-
-
-);
-
-NavItem.propTypes = {
- onLogout: PropTypes.func.isRequired,
- route: routePropType.isRequired
-};
-
-export default NavItem;
diff --git a/src/index.js b/src/index.js
index 84bd45b..0d49a9d 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,8 +1,8 @@
import Alert from './components/Alert';
import Button from './components/Button';
import Col from './components/Col';
+import DrawerLayout from './components/DrawerLayout';
import Grid from './components/Grid';
-import Header from './components/Header';
import LoadingIndicator from './components/LoadingIndicator';
import Row from './components/Row';
import SectionTitle from './components/SectionTitle';
@@ -15,8 +15,8 @@ import SignIn from './components/SignIn';
export {Alert};
export {Button};
export {Col};
+export {DrawerLayout};
export {Grid};
-export {Header};
export {LoadingIndicator};
export {Row};
export {SectionTitle};
diff --git a/src/reducers/session.js b/src/reducers/session.js
index 6c6dcae..525a475 100755
--- a/src/reducers/session.js
+++ b/src/reducers/session.js
@@ -1,5 +1,6 @@
import {
CLEAN_USER_VALIDATIONS,
+ FETCH_CURRENT_USER_SUCCEEDED,
LAST_USER_LOGGED_REQUESTED,
LAST_USER_LOGGED_SUCCEEDED,
USER_LOGIN_FAILED,
@@ -21,6 +22,8 @@ export default function (state = initialState, action) {
switch (action.type) {
case CLEAN_USER_VALIDATIONS:
return {...state, ...initialState};
+ case FETCH_CURRENT_USER_SUCCEEDED:
+ return {...state, user: action.user};
case LAST_USER_LOGGED_REQUESTED:
return {...state, lastUserLogged: null};
case LAST_USER_LOGGED_SUCCEEDED:
diff --git a/src/sagas/index.js b/src/sagas/index.js
index b3f7491..8d2ac74 100644
--- a/src/sagas/index.js
+++ b/src/sagas/index.js
@@ -1,8 +1,9 @@
import {handleError} from './common';
import {
- getLastUserLogged, getToken, fetchRefreshToken, refreshAccessToken, signIn
+ fetchCurrentUser, getLastUserLogged, getToken, fetchRefreshToken, refreshAccessToken, signIn
} from './session';
+export {fetchCurrentUser};
export {fetchRefreshToken};
export {getLastUserLogged};
export {getToken};
diff --git a/src/sagas/session.js b/src/sagas/session.js
index 9b3a2f8..913ca2d 100755
--- a/src/sagas/session.js
+++ b/src/sagas/session.js
@@ -7,6 +7,7 @@ import {
notifyLoginSucceeded,
notifyRefreshAccessToken,
notifyFetchRefreshTokenSucceeded,
+ receiveCurrentUser,
receiveLastUserLogged,
requestClearUserData,
requestFetchToken,
@@ -91,3 +92,12 @@ export function* refreshAccessToken({authEndpoint, clientId, clientSecret}) {
yield put(handleError(err));
}
}
+
+export function* fetchCurrentUser() {
+ try {
+ const user = yield call(SessionService.fetchCurrentUser);
+ yield put(receiveCurrentUser(user));
+ } catch (err) {
+ yield put(handleError(err));
+ }
+}
diff --git a/src/services/session.js b/src/services/session.js
index 551c200..d485233 100755
--- a/src/services/session.js
+++ b/src/services/session.js
@@ -69,4 +69,8 @@ export default class SessionService {
isUserValid: true
};
}
+
+ static async fetchCurrentUser() {
+ return decode(await TokenService.getToken());
+ }
}