src/sagas/form.js
/* eslint import/no-cycle: 0 */
import {
select, call, put, all, takeEvery, takeLatest,
} from 'redux-saga/effects'
import {
HANDLE_SUBSECTION_UPDATE,
VALIDATE_FORM,
} from 'constants/actionTypes'
import {
updateSubsection,
updateSubsectionData,
validateForm,
} from 'actions/FormActions'
import { updateApplication } from 'actions/ApplicationActions'
import { validateSection } from 'helpers/validation'
import sectionKeys from 'helpers/sectionKeys'
import { unschema } from 'schema'
import { env } from 'config'
import { selectApplicantBirthdate, selectMaritalStatus } from 'selectors/data'
import { selectValidUSPassport } from 'selectors/misc'
import { selectForm, selectSubsection, formTypeSelector } from './selectors'
/** LEGACY ACTIONS - store.application */
/** Setting form data on login (this might be replaced) */
export function* updateSectionDataLegacy(name, data) {
try {
yield all(Object.keys(data).map((subsection) => {
const sectionKey = sectionKeys[`${name}.${subsection}`]
const sectionData = unschema(data[subsection])
const updateActions = [put(updateApplication(name, subsection, sectionData))]
if (sectionKey) {
// This sets form data but does not validate
updateActions.push(put(updateSubsectionData(sectionKey, undefined, sectionData)))
}
return all(updateActions)
}))
} catch (e) {
console.warn('failed to update section', name, e)
yield call(env.History().push, '/error')
}
}
export function* setFormData(data) {
try {
const { Metadata = {} } = data
const formType = Metadata.form_type
const formVersion = Metadata.form_version
yield put(updateApplication('Settings', 'formType', formType))
yield put(updateApplication('Settings', 'formVersion', formVersion))
yield all(Object.keys(data)
.map(section => call(updateSectionDataLegacy, section, data[section])))
yield put(validateForm())
} catch (e) {
console.warn('failed to set form data', e)
yield call(env.History().push, '/error')
}
}
/** NEW ACTIONS - store.form */
// This fn currently unused. Will be useful if form starts field-level updates.
export const updateSectionData = (prevData, field, data) => ({
...prevData,
[field]: {
...(prevData && prevData[field]),
...data,
},
})
// Loop through all form sections and re-validate with the existing data
export function* handleValidateForm() {
const formType = yield select(formTypeSelector)
const applicantBirthdate = yield select(selectApplicantBirthdate)
const maritalStatus = yield select(selectMaritalStatus)
const hasValidUSPassport = yield select(selectValidUSPassport)
// pass any x-section form data required to validate here
const validationOptions = {
applicantBirthdate,
maritalStatus,
...hasValidUSPassport,
}
const formData = yield select(selectForm)
yield all(Object.keys(formData)
.map((key) => {
const sectionData = formData[key].data
const errors = validateSection({
key,
data: sectionData,
options: validationOptions,
}, formType)
const newFormSection = {
data: sectionData,
errors: errors === true ? [] : errors,
complete: errors.length === 0 || errors === true,
}
return put(updateSubsection(key, newFormSection))
}))
}
export function* handleSubsectionUpdate({ key, data }) {
const formType = yield select(formTypeSelector)
const applicantBirthdate = yield select(selectApplicantBirthdate)
const maritalStatus = yield select(selectMaritalStatus)
const hasValidUSPassport = yield select(selectValidUSPassport)
const formSection = yield select(selectSubsection, key)
// This because currently, data is updated a whole subsection at a time
// Consider changing to updateSectionData for field-level updates in the future
const newData = { ...formSection.data, ...data }
const errors = yield call(validateSection, {
key,
data: newData,
options: { // pass any x-section form data required to validate here
applicantBirthdate,
maritalStatus,
...hasValidUSPassport,
},
}, formType)
const newFormSection = {
data: newData,
errors: errors === true ? [] : errors,
complete: errors.length === 0 || errors === true,
}
yield put(updateSubsection(key, newFormSection))
}
export function* formWatcher() {
yield all([
takeEvery(HANDLE_SUBSECTION_UPDATE, handleSubsectionUpdate),
takeLatest(VALIDATE_FORM, handleValidateForm),
])
}