/**
 * Standardize type of action using in project
 */

import { messageSymbol } from '../constants/Misc';


function ReduxMessage(type, payload, dispatch) {
  this.msg = { type, payload };
  this.dispatch = dispatch;

  this.submit = () => {
    this.dispatch({
      type: messageSymbol.submit(this.msg.type),
      payload: this.msg.payload
    });
  };

  this.success = (newPayload) => {
    const mergedPayload = { ...this.msg.payload, ...newPayload };

    this.dispatch({
      type: messageSymbol.success(this.msg.type),
      payload: mergedPayload
    });
  };

  this.error = (errorMessage) => {
    this.dispatch({
      type: messageSymbol.error(this.msg.type),
      payload: errorMessage
    });
  };
}

function ReduxPromise(action, message) {
  this.action = action;
  this.message = message;
  this.prev = null;
  this.next = null;
  this.fulfilled = false; // fulfilled flag

  this.createPromise = () => {
    typeof this.prev === 'function' && this.prev(); // Calling prev function

    return new Promise((resolve, reject) => {
      const result = this.action();
      this.message.submit(); // Dispatch submit message

      // Check if action is promise
      const isPromise = result && typeof result.then === 'function';

      if (isPromise) { // If promise, resolve when promise's done
        result.then((res, err) => {
          if (err) {
            // Set promise status as fulfilled state
            this.fulfilled = true;

            this.message.error(err); // Dispatch error message

            typeof this.next === 'function' && this.next(null, err); // Calling next function

            reject(err);
          }

          // Set promise status as fulfilled state
          this.fulfilled = true;

          this.message.success(res.body); // Dispatch success message

          typeof this.next === 'function' && this.next(res.body, null); // Calling next function

          resolve(res.body);
        });
      } else { // If not promise, return result
        // Set promise status as fulfilled state
        this.fulfilled = true;

        this.message.success(result); // Dispatch success message

        typeof this.next === 'function' && this.next(result, null); // Calling next function

        resolve(result, null);
      }
    });
  };

  this.then = (next) => {
    if (typeof next === 'function') this.next = next;
  };

  this.before = (prev) => {
    if (typeof prev === 'function') this.prev = prev;
  };
}

export const ReduxAction =
  (type, payload) => action => (...args) => (dispatch) => {
    const promise = new ReduxPromise(
      () => action(...args),
      new ReduxMessage(type, payload, dispatch)
    );

    const execPromise = () => {
      promise.createPromise();

      return promise;
    };

    execPromise.promise = promise;

    execPromise.prev = (prev) => {
      typeof prev === 'function' && promise.before(prev);

      return execPromise;
    };

    execPromise.next = (next) => {
      typeof next === 'function' && promise.then(next);

      return execPromise;
    };

    execPromise.all = () => {
      let lastPromise = promise;

      // Find last promise in chain
      while (lastPromise.next && lastPromise.next.promise) {
        lastPromise = lastPromise.next.promise;
      }

      // Exec current promise before return last promise
      execPromise();
      return lastPromise;
    };

    return execPromise;
  };

@@ -1076,18 +1076,55 @@
 s.action
-()
+ ? this.action() : this.message.payload
 ;%0A      
@@ -2522,16 +2522,21 @@
 t ReduxA
+syncA
 ction =%0A
@@ -3457,12 +3457,930 @@
 omise;%0A  %7D;%0A
+%0Aexport const ReduxSyncAction =%0A  type =%3E payload =%3E (dispatch) =%3E %7B%0A    const promise = new ReduxPromise(%0A      null,%0A      new ReduxMessage(type, payload, dispatch)%0A    );%0A%0A    const execPromise = () =%3E %7B%0A      promise.createPromise();%0A%0A      return promise;%0A    %7D;%0A%0A    execPromise.promise = promise;%0A%0A    execPromise.prev = (prev) =%3E %7B%0A      typeof prev === 'function' && promise.before(prev);%0A%0A      return execPromise;%0A    %7D;%0A%0A    execPromise.next = (next) =%3E %7B%0A      typeof next === 'function' && promise.then(next);%0A%0A      return execPromise;%0A    %7D;%0A%0A    execPromise.all = () =%3E %7B%0A      let lastPromise = promise;%0A%0A      // Find last promise in chain%0A      while (lastPromise.next && lastPromise.next.promise) %7B%0A        lastPromise = lastPromise.next.promise;%0A      %7D%0A%0A      // Exec current promise before return last promise%0A      execPromise();%0A      return lastPromise;%0A    %7D;%0A%0A    return execPromise;%0A  %7D;%0A

Update redux action logic, seperate Sync & Async action type