import { useReducer } from 'react'
interface FormState {
values: Record<string, any>
errors: Record<string, string>
touched: Record<string, boolean>
isSubmitting: boolean
}
type FormAction =
| { type: 'CHANGE_FIELD'; field: string; value: any }
| { type: 'TOUCH_FIELD'; field: string }
| { type: 'SET_ERRORS'; errors: Record<string, string> }
| { type: 'SET_SUBMITTING'; isSubmitting: boolean }
| { type: 'RESET' }
function formReducer(state: FormState, action: FormAction): FormState {
switch (action.type) {
case 'CHANGE_FIELD':
return {
...state,
values: {
...state.values,
[action.field]: action.value,
},
errors: {
...state.errors,
[action.field]: '', // Clear error on change
},
}
case 'TOUCH_FIELD':
return {
...state,
touched: {
...state.touched,
[action.field]: true,
},
}
case 'SET_ERRORS':
return {
...state,
errors: action.errors,
}
case 'SET_SUBMITTING':
return {
...state,
isSubmitting: action.isSubmitting,
}
case 'RESET':
return initialState
default:
return state
}
}
const initialState: FormState = {
values: {},
errors: {},
touched: {},
isSubmitting: false,
}
export function useFormReducer() {
const [state, dispatch] = useReducer(formReducer, initialState)
return {
state,
changeField: (field: string, value: any) =>
dispatch({ type: 'CHANGE_FIELD', field, value }),
touchField: (field: string) =>
dispatch({ type: 'TOUCH_FIELD', field }),
setErrors: (errors: Record<string, string>) =>
dispatch({ type: 'SET_ERRORS', errors }),
setSubmitting: (isSubmitting: boolean) =>
dispatch({ type: 'SET_SUBMITTING', isSubmitting }),
reset: () => dispatch({ type: 'RESET' }),
}
}