Source: store/actions/action.js

/**
 * @module ReduxActions
 */

import axios from 'axios';
import * as SecureStore from 'expo-secure-store';

export const SET_SESSION = 'SET_SESSION';
export const SET_PUSHNOTIFICATION = 'SET_PUSHNOTIFICATION';
export const SET_DEVICETOKEN = 'SET_DEVICETOKEN';
export const SET_JWT = 'SET_JWT';
export const SET_LOADED = 'SET_LOADED';
export const SET_BIOMETRIC = 'SET_BIOMETRIC';
export const SET_PROMPT = 'SET_PROMPT';
export const SET_AUTH = 'SET_AUTH';
export const SET_REAUTH = 'SET_REAUTH';
export const LOG_OUT = 'LOG_OUT';
export const GET_PUSHSETTINGS = 'GET_PUSHSETTINGS';
export const SET_PUSHSETTINGS = 'SET_PUSHSETTINGS';
export const CHANGE_ORG_TYPE = 'CHANGE_ORG_TYPE';

/**
 * Store the users unique JWT in store.
 * The JWT is used to show content that require login on web.
 * @method
 * @param {String} jwt JWT retrieved from fixrate's api after bankID-login.
 */
export const setJWT = jwt => {
  console.log('[action.js] --> setJWT()');
  return {
    type: SET_JWT,
    payload: {
      jwt: jwt
    }
  };
};

/**
 * Sets the redux store back to default.
 * If the user chooses to do a hard logout he can log in as another user.
 * The database also gets altered so next time he logs in it will be like the first time.
 * @method
 * @param {String} expoToken Users unique device expoToken.
 * @param {Boolean} hardLogout Hardlogout resets some settings in the database.
 */
export const logOut = (expoToken, hardLogout) => {
  console.log('[action.js] --> logOut()');
  if (hardLogout) {
    SecureStore.deleteItemAsync('userJWTs');
    return async dispatch => {
      await axios
        .put('http://138.68.67.250:3000/biometric/prompt', {
          option: false,
          tokenId: expoToken
        })
        .then(() => {
          axios.put('http://138.68.67.250:3000/biometric', {
            option: false,
            tokenId: expoToken
          });
        })
        .catch(function(error) {
          console.log(error);
        });
      dispatch({
        type: LOG_OUT
      });
    };
  }
  return dispatch => {
    dispatch({ type: LOG_OUT });
  };
};

/**
 * Store the user in the database.
 * @method
 * @param {String} expoToken The users unique device expoToken.
 * @param {String} userId The users unique userId.
 * @param {Array} associations The users association
 */
const storeUser = (expoToken, userId, associations) => {
  console.log('[action.js] --> storeUser()');
  associations.forEach(element => {
    axios
      .put('http://138.68.67.250:3000/user', {
        userId: userId,
        expoToken: expoToken,
        orgType: element.organisation.type,
        orgId: element.organisation.id,
        orgName: element.organisation.name
      })
      .catch(error => console.log('storeUser() error: ', error));
  });
};

export const GET_DASHBOARD = 'GET_DASHBOARD';
export const getDashboard = () => {
  return async dispatch => {
    const response = await fetch(
      'https://market.test.fixrate.org/api/marketplace-data/rest/dashboard',
      {
        credentials: 'include'
      }
    );
    const resData = await response.json();
    dispatch({
      type: GET_DASHBOARD,
      payload: resData
    });
  };
};

/**
 * Get the users session-object from fixrates api/session.
 * @method
 * @param {String} expoToken The users unique device expoToken
 */
export const fetchSession = expoToken => {
  console.log('[action.js] --> fetchSession()');

  let userId;
  let associations;

  return async dispatch => {
    const response = await fetch('https://market.test.fixrate.org/api/session', {
      credentials: 'include'
    });
    const resData = await response.json();
    userId = resData.id;
    associations = resData.associations;
    const associationType = resData.organisationType;

    dispatch({
      type: SET_SESSION,
      sessionData: resData
    });

    dispatch(getOrders(associationType));

    dispatch(getPushSettings(expoToken, associationType));
    // Store userId etc in userTable here...?
    storeUser(expoToken, userId, associations);
  };
};

export const GET_ORG_USERS = 'GET_ORG_USERS';
export const getOrganisationUsers = () => {
  console.log('[action.js] --> getOrganisationUsers()');
  return async dispatch => {
    const res = await fetch(
      'https://market.test.fixrate.org/api/marketplace-data/rest/depositors',
      {
        credentials: 'include'
      }
    );

    const resData = await res.json();
    const keepThis = [];
    resData.forEach(organisation => {
      keepThis.push({
        id: organisation.id,
        users: organisation.users
      });
    });
    dispatch({
      type: GET_ORG_USERS,
      payload: keepThis
    });
  };
};

export const GET_ORDERS = 'GET_ORDERS';
/**
 * Get all the orders available for the user.
 * @method
 * @param {String} userRole The users role e.g "BANK".
 */
export const getOrders = userRole => {
  console.log('[actions.js] --> getOrders()');
  return async dispatch => {
    const res = await fetch('https://market.test.fixrate.org/api/marketplace-data/rest/orders', {
      credentials: 'include'
    });
    const interstRateRes = await fetch(
      'https://market.test.fixrate.org/api/marketplace-data/rest/interestRateChange',
      { credentials: 'include' }
    );
    const depositRes = await fetch(
      'https://market.test.fixrate.org/api/marketplace-data/rest/deposits',
      { credentials: 'include' }
    );

    const ordersData = await res.json();
    const rateData = await interstRateRes.json();
    const depositData = await depositRes.json();

    let result = [];
    if (userRole === 'BANK') {
      ordersData.forEach(element => {
        if (
          element.orderState === 'INITIAL_PROCESSING' ||
          element.orderState === 'READY_FOR_APPROVAL' ||
          element.orderState === 'READY_FOR_TRANSACTION_CONFIRMATION'
        ) {
          result.push(element);
        }
      });
    } else {
      ordersData.forEach((element, i) => {
        let date = new Date();
        if (
          element.orderState === 'READY_FOR_SIGNING' ||
          element.orderState === 'READY_FOR_TRANSACTION' ||
          (element.orderState === 'CANCELED' && dateCheckForOrder(date, element.lastModified))
        ) {
          result.push(element);
        }
      });
    }

    /**
     * henter depositId fra /interestRateChange
     * sammenligner depositId mot /deposit og henter ordreId
     * sammenligner ordreId mot /orderså henter en ordre der orderState === 'COMPLETED'
     */
    let interestRateChangeId = [];
    let interestRateChange = [];
    if (userRole === 'DEPOSITOR') {
      let depositIds = [];
      let orderIds = [];

      rateData.forEach(e => {
        if (e.sentToDepositor !== null && isDateAfterToday(e.changeDate)) {
          depositIds.push(e.depositId);
          interestRateChangeId.push(e.id);
        }
      });

      rateData.forEach(element => {
        interestRateChangeId.forEach(e => {
          if (element.id === e && element.sentToDepositor) interestRateChange.push(element);
        });
      });

      depositData.forEach(e => {
        depositIds.forEach(el => {
          if (e.id === el) orderIds.push(e.orderId);
        });
      });

      ordersData.forEach(e => {
        orderIds.forEach(el => {
          if (e.orderState === 'COMPLETED' && e.id === el) result.push(e);
        });
      });
    }

    dispatch({
      type: GET_ORDERS,
      payload: result
    });

    dispatch({
      type: GET_INTEREST_RATE_CHANGE,
      payload: interestRateChange
    });
    dispatch(getOrganisationUsers());
  };
};

function dateCheckForOrder(currentDate, orderDate) {
  let date2 = new Date(orderDate);
  let diff = currentDate.getTime() - date2.getTime();
  if (diff / (1000 * 3600 * 24) < 1) return true;
}

function isDateAfterToday(changeDate) {
  let givenDate = changeDate;
  let currentDate = new Date().toLocaleDateString();
  givenDate = new Date(givenDate).toLocaleDateString();
  if (givenDate >= currentDate) {
    return true;
  }
}

function dateCheckForAd(date, adDate) {
  let newAdDate = new Date(adDate);
  let diff = date.getTime() - newAdDate.getTime();
  if (diff / (1000 * 3600 * 24) < 7) return true;
}

export const GET_ADS = 'GET_ADS';
/**
 * @method
 * Get all new orders thats been published on the marketplace the last 7 days.
 */
export const getAds = () => {
  console.log('[actions.js] --> getAds()');
  let thisDate = new Date();
  return async dispatch => {
    const response = await fetch('https://market.test.fixrate.org/api/marketplace-data/rest/ads', {
      credentials: 'include'
    });
    const resData = await response.json();
    const newAds = [];
    resData.forEach(element => {
      if (dateCheckForAd(thisDate, element.published)) {
        if (element.remaining >= element.min) {
          if (element.remaining !== 0) {
            newAds.push(element);
          }
        }
      }
    });
    dispatch({
      type: GET_ADS,
      payload: newAds
    });
  };
};

export const GET_INTEREST_RATE_CHANGE = 'GET_INTEREST_RATE_CHANGE';
export const getInterestRateChange = id => {
  console.log('[actions.js] --> getInterestRateChange()');

  return async dispatch => {
    const response = await fetch(
      'https://market.test.fixrate.org/api/marketplace-data/rest/interestRateChange',
      {
        credentials: 'include'
      }
    );

    const resData = await response.json();
    let interestRateChange = [];

    resData.forEach(element => {
      id.forEach(e => {
        if (element.id === e && element.sentToDepositor) {
          interestRateChange.push(element);
          console.log('[interestRateChangeDispatch]', element);
        }
      });
    });

    dispatch({
      type: GET_INTEREST_RATE_CHANGE,
      payload: interestRateChange
    });
  };
};

export const GET_BANKS = 'GET_BANKS';
export const getBanks = () => {
  console.log('[actions.js] --> getBanks()');
  return async dispatch => {
    const response = await fetch(
      'https://market.test.fixrate.org/api/marketplace-data/rest/banks',
      {
        credentials: 'include'
      }
    );
    const resData = await response.json();
    dispatch({
      type: GET_BANKS,
      payload: resData
    });
  };
};

/**
 * See if the user has used the app before on startup.
 * @method
 * @param {String} token The users unique device expoToken
 * @param {boolean} hasBiometricHardware Whether or not the users device has biometric hardware.
 */
export const loadingPhase = (token, hasBiometricHardware) => {
  let result;
  return async dispatch => {
    try {
      const response = await axios.get('http://138.68.67.250:3000/biometric/' + token);
      result = await response.data[0];
      console.log('[action.js] --> loadingPhase(): ', result);
    } catch (error) {
      console.log(error);
    }
    dispatch({
      type: SET_LOADED,
      payload: {
        result,
        hasBiometricHardware
      }
    });
  };
};

/**
 * Set the users promptanswer in the database.
 * @method
 * @param {boolean} bioAnswer If the user wants to use biometric login in the future.
 * @param {boolean} promptAnswer The user has answered the biometric login question
 * @param {String} expoToken The users unique device expoToken
 */
export const setPrompt = (bioAnswer, promptAnswer, expoToken) => {
  console.log('[action.js] --> setPrompt()');
  return async dispatch => {
    await axios
      .put('http://138.68.67.250:3000/biometric/prompt', {
        option: promptAnswer,
        tokenId: expoToken
      })
      .then(() => {
        axios.put('http://138.68.67.250:3000/biometric', {
          option: bioAnswer,
          tokenId: expoToken
        });
      })
      .catch(function(error) {
        console.log(error);
      });
    dispatch({
      type: SET_PROMPT,
      payload: {
        promptReceived: promptAnswer,
        bioAnswer: bioAnswer
      }
    });
  };
};

export const setAuth = value => {
  return {
    type: SET_AUTH,
    payload: {
      newValue: value
    }
  };
};

export const setReAuth = value => {
  return {
    type: SET_REAUTH,
    payload: {
      newValue: value
    }
  };
};

/**
 * Get the users pushnotificationsettings from database and set them in the redux store.
 * @method
 * @param {String} expoToken The users unique device expoToken
 * @param {String} associationType The users associationType e.g "BANK"
 */
export const getPushSettings = (expoToken, associationType) => {
  let result;
  console.log('[action.js] --> getPushSettings');
  return async dispatch => {
    try {
      const response = await axios.put('http://138.68.67.250:3000/notification/settings', {
        expoToken: expoToken,
        associationType: associationType
      });
      result = await response.data;
    } catch (error) {
      console.log(error);
    }
    dispatch({
      type: GET_PUSHSETTINGS,
      payload: {
        result
      }
    });
  };
};

/**
 * Used to change the value and subscription to the apps differen pushnotificationsettings.
 * @method
 * @param {String} expoToken The users unique device expoToken
 * @param {boolean} newValue e.g true/false.
 * @param {String} notificationType Changed notificationType.
 * @param {String} associationType The users associationType
 */
export const setPushSettings = (expoToken, newValue, notificationType, associationType) => {
  console.log('[action.js] --> setPushSettings()');
  return async dispatch => {
    try {
      await axios.put('http://138.68.67.250:3000/notification', {
        newValue: newValue,
        expoToken: expoToken,
        notificationType: notificationType,
        associationType: associationType
      });
    } catch (error) {
      console.log('[actions.js] --> setPushSettings() error: ', error);
    }
    const value = newValue ? 1 : 0;
    dispatch({
      type: SET_PUSHSETTINGS,
      payload: {
        newValue: value,
        notificationType: notificationType
      }
    });
  };
};

export const GET_DASHBOARD_DATA = 'GET_DASHBOARD_DATA';
export const getDashboardData = () => {
  console.log('[action.js] --> getDashboardData()');
  return async dispatch => {
    let result = [];
    const response = await fetch(
      'https://market.test.fixrate.org/api/marketplace-data/rest/deposits',
      {
        credentials: 'include'
      }
    );
    const resData = await response.json();
    resData.forEach(deposit => {
      if (deposit.expires !== null && !deposit.expires.expired) {
        result.push({
          volume: deposit.volume,
          productId: deposit.product.id,
          type: deposit.product.type,
          expire: deposit.expires !== null ? new Date(deposit.expires.date) : null
        });
      }
    });
    result.sort((a, b) => a.expire - b.expire);
    dispatch({
      type: GET_DASHBOARD_DATA,
      payload: result
    });
  };
};

export const changeOrgType = newOrgType => {
  return {
    type: CHANGE_ORG_TYPE,
    payload: {
      newOrgType: newOrgType
    }
  };
};

export default SET_SESSION;