modules-pack
Version:
JavaScript Modules for Modern Frontend & Backend Projects
124 lines (104 loc) • 4.34 kB
JavaScript
import { apiAction, subscribeToApiResults } from 'modules-pack/api'
import { stateAction, stateActionType } from 'modules-pack/redux'
import { all, call, delay, put, spawn, takeLatest } from 'modules-pack/saga/utils'
import { ROUTE, URL } from 'modules-pack/variables'
import { Active, CREATE, LOGIN, RESET, sanitizeResponse, SET, SUCCESS } from 'utils-pack'
import { SELF, USER_LOGIN } from '../constants'
import * as m from '../mutations' // setup Active.UserMutation
import * as q from '../queries' // setup Active.UserQuery
const sideEffects = {m, q}
/**
* ASYNC TASKS =================================================================
* Actions Orchestration - for subscribing, managing and dispatching actions.
* =============================================================================
*/
/**
* All Tasks in this module get initiated here
*/
export default function * init () {
yield spawn(watch)
}
/**
* WATCH TASKS (Action Subscriptions) ------------------------------------------
* -----------------------------------------------------------------------------
*/
function * watch () {
yield all([
// List task subscriptions here
takeLatest(stateActionType(LOGIN), loginOpen),
takeLatest(stateActionType(SELF, SET), userUpdate),
takeLatest(stateActionType(LOGIN, SUCCESS), loginSuccessFlow),
])
}
/**
* PERPETUAL TASKS (Action Initialisations) ------------------------------------
* -----------------------------------------------------------------------------
*/
/**
* FLOW TASKS (Action Management) ----------------------------------------------
* -----------------------------------------------------------------------------
*/
/**
* Close Login Modal, Get Required Info and Refresh Requested Route
*/
function * loginSuccessFlow ({meta: {form} = {}}) {
if ((form && form !== USER_LOGIN) || ROUTE.LOGIN !== Active.history.location.pathname) return
const {history} = Active
let routeToRefresh = ROUTE.HOME
// Close Login Modal
// @note: history.goBack() will reload browser if no previous page exists (i.e. Login page entered directly),
// causing the entire redux store to reset as if loading the app initially,
// thus, below code will be canceled.
// However, history.length always return 2, even if Login page was entered directly.
// Thus, we need to check if Login was opened by loginOpen() using state identifier `isModal`,
// and only fire history.goBack() if it was opened as Modal.
const {state: {isModal} = {}} = history.location
if (isModal) {
// the standard uses history.back() while `react-router` uses history.goBack
(history.back || history.goBack)()
yield delay(10)
routeToRefresh = Active.history.location.pathname
// Refresh Requested Route
// Because react-router has no refresh function any more
// we have to manually force Component re-mount by first pushing Loading route
history.push(ROUTE.LOADING)
}
// Get Required Info
yield all([
call(infoGqlFlow),
delay(10),
])
history.push(routeToRefresh)
}
/**
* Get User Profile Data from GraphQl Server
*/
export function * infoGqlFlow () {
/* API Request and Wait for Response */
const body = {query: Active.UserQuery}
yield put(apiAction(URL.API_GQL, CREATE, {body}, {...body, headers}))
const {payload = {}, meta: {result} = {}} = yield call(subscribeToApiResults, URL.API_GQL, CREATE, body)
if (result !== SUCCESS) return
/* Update State */
const {user} = payload.data || {}
if (user) yield put(stateAction(SELF, RESET, sanitizeResponse(user)))
}
// Sync User Data with Backend
function * userUpdate ({payload, meta}) {
const {sync} = meta || {}
if (!sync) return
yield call(userMutate, {payload, meta})
}
/**
* HELPER TASKS (Action Dispatches) --------------------------------------------
* -----------------------------------------------------------------------------
*/
function * loginOpen () {
if (ROUTE.LOGIN === Active.history.location.pathname) return
Active.history.push({pathname: ROUTE.LOGIN, state: {isModal: true, canCloseModal: false}})
}
function * userMutate ({payload}) {
const body = {query: Active.UserMutation, variables: {user: payload}}
yield put(apiAction(URL.API_GQL, CREATE, {body}, {...body, headers}))
}
const headers = {'Content-Type': 'application/json'}