import { FormModel, AbstractFormField } from '../interfaces' import { SET_FORM_FIELD, DESTROY_FORM, RESET_FORM, SUBMIT_FORM_VALID, SUBMIT_FORM_INVALID, SEARCH_ADDRESS, } from '../constants' import { FormAction, ResetFormAction, DestroyFormAction, SetFormFieldAction, SearchAddressAction, SearchAddressSuccessAction, SearchAddressErrorAction, } from '../actions' export interface FormState { [formName: string]: AbstractFormField | FormModel } export const formReducer = (state: FormState = {}, action: FormAction): FormState => { switch (action.type) { case SET_FORM_FIELD: return setFormField(state, action) case DESTROY_FORM: return destroyForm(state, action) case RESET_FORM: return resetForm(state, action) case SUBMIT_FORM_VALID: case SUBMIT_FORM_INVALID: return submitForm(state, action) default: return state } } const setFormField = (state: FormState, action: SetFormFieldAction): FormState => { if (action.formName) { return { ...state, [action.formName]: { ...state[action.formName], [action.name]: action.field, }, } } else { return { ...state, [action.name]: action.field, } } } const destroyForm = (state: FormState, action: DestroyFormAction): FormState => { const newState = { ...state } delete newState[action.formName] return newState } /** * Clear the form data for a named form * * @param state * @param action */ const resetForm = (state: FormState, action: ResetFormAction): FormState => { const s = { ...state, [action.formName]: { ...state[action.formName]}} Object.keys(s[action.formName]).forEach(field => { (s[action.formName] as any)[field] = { ...(s[action.formName] as any)[field], value: '', } }); return s } /** * When a form is submitted we can immediately * make every field in the form as being submitted * * @param state * @param action */ const submitForm = (state: FormState, action: FormAction): FormState => { const form = state[action.formName] if (!form) { throw new Error(`A form with the name ${action.formName} does not exist`) } const newState: FormState = { ...state, [action.formName]: { ...form, }, } for (const key of Object.keys(form)) { (newState[action.formName] as FormModel)[key] = { ...(newState[action.formName] as FormModel)[key], submitted: true, } } return newState } // TODO - see if these can be generalized for all fields const setAddressLoading = (state: FormState, action: SearchAddressAction) => ({ ...state, [action.args.formName]: { ...state[action.args.formName], [action.args.name]: { ...(state[action.args.formName] as any)[action.args.name], loading: true, }, }, }) const setAddressOptions = (state: FormState, action: SearchAddressSuccessAction) => ({ ...state, [action.args.formName]: { ...state[action.args.formName], [action.args.name]: { ...(state[action.args.formName] as any)[action.args.name], loading: true, }, }, }) const setAddressErrors = (state: FormState, action: SearchAddressErrorAction) => ({ ...state, [action.args.formName]: { ...state[action.args.formName], [action.args.name]: { ...(state[action.args.formName] as any)[action.args.name], loading: true, }, }, })