diff --git a/src/lib/utils/formik.ts b/src/lib/utils/formik.ts new file mode 100644 index 00000000..e474c8c6 --- /dev/null +++ b/src/lib/utils/formik.ts @@ -0,0 +1,48 @@ +import { FormikContextType, getIn, setIn } from 'formik'; + +function spliceArray(arr: T[] | undefined, index: number) { + const a = Array.isArray(arr) ? arr.slice() : []; + if (index >= 0 && index < a.length) a.splice(index, 1); + return a; +} + +/** + * Remove one item from an array field and also trim Formik's errors & touched + * at the SAME index to keep everything aligned. + * + * @param formik - your useFormik instance + * @param arrayPath - path to the array field, e.g. "kandangExpenses[0].expenses" + * @param index - the index to remove + * @param validateAfter - optional: revalidate after removal (default false) + */ +export async function removeArrayItemAndSync( + formik: FormikContextType, + arrayPath: string, + index: number, + validateAfter: boolean = false +) { + // 1) VALUES: remove at index + const currValues = getIn(formik.values, arrayPath); + const nextValues = spliceArray(currValues, index); + formik.setFieldValue(arrayPath, nextValues, false); + + // 2) ERRORS: remove the same index (if array exists) + const currErrors = getIn(formik.errors, arrayPath); + if (Array.isArray(currErrors)) { + const nextErrors = spliceArray(currErrors, index); + formik.setErrors(setIn(formik.errors, arrayPath, nextErrors)); + } + + // 3) TOUCHED: remove the same index (if array exists) + const currTouched = getIn(formik.touched, arrayPath); + if (Array.isArray(currTouched)) { + const nextTouched = spliceArray(currTouched, index); + formik.setTouched(setIn(formik.touched, arrayPath, nextTouched), false); + } + + // 4) (optional) revalidate to rebuild a perfectly clean error tree + if (validateAfter) { + const newErrors = await formik.validateForm(); + formik.setErrors(newErrors); + } +}