cosmo-ui
Version:
Common React components
140 lines (130 loc) • 3.75 kB
text/typescript
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<any> | 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,
},
},
})