Skip to content
Gayashan Bombuwala edited this page Jul 29, 2018 · 5 revisions

Welcome to the Bassa-mobile Developer Guide

Configuring the Bassa-backend

Bassa-mobile directly depends on the Bassa-backend and you can't go beyond the Sign-In screen, if you haven't configured it properly.

Go through the following steps to configure it.

  • Navigate to the ./app/constants folder from the root folder and open the API.js file.
  • Replace the values of the following properties according to the configurations of your Bassa-backend.
const APIConstants = {`
  `HOST_URL: 'http://10.0.3.2',`
  `HOST_PORT: 5000,`
  `KEY: '123456789',`
`};

** HOST_URL property can contain one of the following 3 values, depending on your device.**

Genymotion

10.0.3.2

Android Studio Emulator

10.0.2.2

External device

obtain the IP of your computer using the ifconfig command on Unix-like OS or ipconfig command on Windows. (Computer and the device should be on the same network)

Directory structure

  • ./app/actions/ - Redux actions that change the Redux store
  • ./app/components/ - Components that does't get connected with the Redux store (i.e. ActivityLoader component).
  • ./app/constants/ - Reusable constants related to the project (i.e. API constants).
  • ./app/containers/ - Containers/Components that gets connected with the Redux store (i.e. QuotaUsage component).
  • ./app/containers/CustomDrawer.js - Drawer component used in the app.
  • ./app/helpers/ - Helper functions related to the project such as API request interceptors and common utility funtions
  • ./app/images/ - Static image files related to the project (i.e. App logo).
  • ./app/reducers/ - Redux reducers that handle state changes
  • ./app/containers/RootNavigator.js - Navigation routes used in the app.
  • ./app/sagas/ - Redux sagas that perform async actions in the app (i.e. Setting the auth token to the API).
  • ./app/services/ - API calls that return Promises (i.e. signIn).
  • ./app/store/ - Redux store configurations.
  • ./app/styles/ - Common styles used in the app (i.e. Status bar color).
  • ./__tests__/ - Unit testing files.

Example Development Workflow

Let's see how we can use the above mentioned directory structure, in order to develop the Sign-In workflow.

  1. Implement the draft Sign-In container and connect to the Redux store.
...
class SignIn {
...
}
export default connect(mapStateToProps, mapDispatchToProps)(SignIn);
...
  1. Define the navigation routes.
...
const AppNavigator = createStackNavigator({
...
  SignIn: { screen: SignIn },
...
});
...
  1. Define the constants required for action types.
export const userActions = {
  USER_SIGN_IN: 'USER_SIGN_IN',
  AUTHENTICATE_USER_SUCCESS: 'AUTHENTICATE_USER_SUCCESS',
  AUTHENTICATE_USER_FAIL: 'AUTHENTICATE_USER_FAIL',
};
  1. Define the Redux actions.
export const signIn = (username, password) => ({
  type: userActions.USER_SIGN_IN,
  payload: { user_name: username, password },
});
  1. Define the Redux reducer.
...
const initialState = {
  currentUser: {
    username: '',
    isAdmin: false,
    timestamp: null,
  },
};

function userReducer(state = initialState, action) {
  switch (action.type) {
    case userActions.AUTHENTICATE_USER_SUCCESS:
      return {
        ...state,
        currentUser: {
          ...state.currentUser,
          username: action.payload.username,
          isAdmin: action.payload.isAdmin,
          timestamp: action.payload.timestamp ? action.payload.timestamp : Date.now(),
        },
      };
    default:
      return state;
  }
}

export default userReducer;
  1. Define the required API calls as a service.
import APIBuilder from '../helpers/APIBuilder';
import { prepareRequestBody } from '../helpers/utils';

const signIn = credentials => APIBuilder.API.post('/api/login', prepareRequestBody(credentials));
  1. Define a Redux Saga to handle async operations involved in the Sign-In workflow.
...
function* signInUser({ payload }) {
  try {
    const response = yield call(UserService.signIn, payload);
    if (response.status === 200) {
      yield call(KeychainService.setGenericPassword, payload.user_name, payload.password);
      yield put(handleAuthSuccess({
        username: payload.user_name,
        isAdmin: Number(response.data.auth) === 0 ? true : false,
      }));
      yield put(setTokenToHeader(response.headers.token));
      yield put(resetToMainDrawer());
    } 
  } 
...
}
...
export default function* userSaga() {
  yield all([
    takeEvery(userActions.USER_SIGN_IN, signInUser),
  ]);
}
  1. Complete the implementation of the SignIn container (component) with the help of the above defined artifacts.
  2. Write tests to validate the new code (i.e Snapshot testing, Unit testing).
...
describe('User Reducer', () => {
    it('should return the initial state', () => {
        expect(userReducer(undefined, {})).toEqual(
            {
                currentUser: {
                    username: '',
                    isAdmin: false,
                    timestamp: null,
                },
            }
        )
    });
...