fix: Replace getFormHelpers (#4181)

Fixes #3209.
This commit is contained in:
Kyle Carberry
2022-09-23 16:37:44 -05:00
committed by GitHub
parent f9075cab0e
commit 266a3b24e7
8 changed files with 23 additions and 36 deletions
@@ -3,7 +3,7 @@ import { ErrorSummary } from "components/ErrorSummary/ErrorSummary"
import { FormikContextType, FormikTouched, useFormik } from "formik"
import { FC } from "react"
import * as Yup from "yup"
import { getFormHelpersWithError, nameValidator, onChangeTrimmed } from "../../util/formUtils"
import { getFormHelpers, nameValidator, onChangeTrimmed } from "../../util/formUtils"
import { LoadingButton } from "../LoadingButton/LoadingButton"
import { Stack } from "../Stack/Stack"
@@ -47,7 +47,7 @@ export const AccountForm: FC<React.PropsWithChildren<AccountFormProps>> = ({
onSubmit,
initialTouched,
})
const getFieldHelpers = getFormHelpersWithError<AccountFormValues>(form, updateProfileError)
const getFieldHelpers = getFormHelpers<AccountFormValues>(form, updateProfileError)
return (
<>
@@ -3,7 +3,7 @@ import { ErrorSummary } from "components/ErrorSummary/ErrorSummary"
import { FormikContextType, FormikTouched, useFormik } from "formik"
import React from "react"
import * as Yup from "yup"
import { getFormHelpersWithError, onChangeTrimmed } from "../../util/formUtils"
import { getFormHelpers, onChangeTrimmed } from "../../util/formUtils"
import { LoadingButton } from "../LoadingButton/LoadingButton"
import { Stack } from "../Stack/Stack"
@@ -62,7 +62,7 @@ export const SecurityForm: React.FC<SecurityFormProps> = ({
onSubmit,
initialTouched,
})
const getFieldHelpers = getFormHelpersWithError<SecurityFormValues>(form, updateSecurityError)
const getFieldHelpers = getFormHelpers<SecurityFormValues>(form, updateSecurityError)
return (
<>
@@ -11,7 +11,7 @@ import { FormikContextType, FormikTouched, useFormik } from "formik"
import { FC } from "react"
import * as Yup from "yup"
import { AuthMethods } from "../../api/typesGenerated"
import { getFormHelpersWithError, onChangeTrimmed } from "../../util/formUtils"
import { getFormHelpers, onChangeTrimmed } from "../../util/formUtils"
import { Welcome } from "../Welcome/Welcome"
import { LoadingButton } from "./../LoadingButton/LoadingButton"
@@ -113,10 +113,7 @@ export const SignInForm: FC<React.PropsWithChildren<SignInFormProps>> = ({
onSubmit,
initialTouched,
})
const getFieldHelpers = getFormHelpersWithError<BuiltInAuthFormValues>(
form,
loginErrors.authError,
)
const getFieldHelpers = getFormHelpers<BuiltInAuthFormValues>(form, loginErrors.authError)
return (
<>
@@ -21,7 +21,7 @@ import { defaultSchedule, emptySchedule } from "pages/WorkspaceSchedulePage/sche
import { defaultTTL } from "pages/WorkspaceSchedulePage/ttl"
import { ChangeEvent, FC } from "react"
import * as Yup from "yup"
import { getFormHelpersWithError } from "../../util/formUtils"
import { getFormHelpers } from "../../util/formUtils"
import { FormFooter } from "../FormFooter/FormFooter"
import { FullPageForm } from "../FullPageForm/FullPageForm"
import { Stack } from "../Stack/Stack"
@@ -189,10 +189,7 @@ export const WorkspaceScheduleForm: FC<React.PropsWithChildren<WorkspaceSchedule
validationSchema,
initialTouched,
})
const formHelpers = getFormHelpersWithError<WorkspaceScheduleFormValues>(
form,
submitScheduleError,
)
const formHelpers = getFormHelpers<WorkspaceScheduleFormValues>(form, submitScheduleError)
const checkboxes: Array<{ value: boolean; name: string; label: string }> = [
{ value: form.values.sunday, name: "sunday", label: Language.daySundayLabel },
@@ -10,7 +10,7 @@ import { FullPageForm } from "../../components/FullPageForm/FullPageForm"
import { Loader } from "../../components/Loader/Loader"
import { ParameterInput } from "../../components/ParameterInput/ParameterInput"
import { Stack } from "../../components/Stack/Stack"
import { getFormHelpersWithError, nameValidator, onChangeTrimmed } from "../../util/formUtils"
import { getFormHelpers, nameValidator, onChangeTrimmed } from "../../util/formUtils"
export const Language = {
templateLabel: "Template",
@@ -84,7 +84,7 @@ export const CreateWorkspacePageView: FC<React.PropsWithChildren<CreateWorkspace
},
})
const getFieldHelpers = getFormHelpersWithError<TypesGen.CreateWorkspaceRequest>(
const getFieldHelpers = getFormHelpers<TypesGen.CreateWorkspaceRequest>(
form,
props.createWorkspaceErrors[CreateWorkspaceErrors.CREATE_WORKSPACE_ERROR],
)
@@ -13,7 +13,7 @@ import { Stack } from "components/Stack/Stack"
import { FormikContextType, FormikTouched, useFormik } from "formik"
import { FC, useRef, useState } from "react"
import { colors } from "theme/colors"
import { getFormHelpersWithError, nameValidator, onChangeTrimmed } from "util/formUtils"
import { getFormHelpers, nameValidator, onChangeTrimmed } from "util/formUtils"
import * as Yup from "yup"
export const Language = {
@@ -79,7 +79,7 @@ export const TemplateSettingsForm: FC<TemplateSettingsForm> = ({
},
initialTouched,
})
const getFieldHelpers = getFormHelpersWithError<UpdateTemplateMeta>(form, error)
const getFieldHelpers = getFormHelpers<UpdateTemplateMeta>(form, error)
const styles = useStyles()
const hasIcon = form.values.icon && form.values.icon !== ""
const emojiButtonRef = useRef<HTMLButtonElement>(null)
+3 -3
View File
@@ -71,19 +71,19 @@ describe("form util functions", () => {
it("shows an error if there is only an API error", () => {
const getFieldHelpers = getFormHelpers<TestType>(form, { touchedGoodField: "API error!" })
const result = getFieldHelpers("touchedGoodField")
expect(result.error).toBeTruthy
expect(result.error).toBeTruthy()
expect(result.helperText).toEqual("API error!")
})
it("shows an error if there is only a validation error", () => {
const getFieldHelpers = getFormHelpers<TestType>(form, {})
const result = getFieldHelpers("touchedBadField")
expect(result.error).toBeTruthy
expect(result.error).toBeTruthy()
expect(result.helperText).toEqual("oops!")
})
it("shows the API error if both are present", () => {
const getFieldHelpers = getFormHelpers<TestType>(form, { touchedBadField: "API error!" })
const result = getFieldHelpers("touchedBadField")
expect(result.error).toBeTruthy
expect(result.error).toBeTruthy()
expect(result.helperText).toEqual("API error!")
})
})
+8 -15
View File
@@ -27,8 +27,12 @@ interface FormHelpers {
// backendErrorName can be used if the backend names a field differently than the frontend does
export const getFormHelpers =
<T>(form: FormikContextType<T>, apiValidationErrors?: FormikErrors<T>) =>
<T>(form: FormikContextType<T>, error?: Error | unknown) =>
(name: keyof T, HelperText: ReactNode = "", backendErrorName?: string): FormHelpers => {
const apiValidationErrors =
isApiError(error) && hasApiFieldErrors(error)
? (mapApiErrorToFieldErrors(error.response.data) as FormikErrors<T>)
: error
if (typeof name !== "string") {
throw new Error(`name must be type of string, instead received '${typeof name}'`)
}
@@ -39,26 +43,15 @@ export const getFormHelpers =
const touched = getIn(form.touched, name)
const apiError = getIn(apiValidationErrors, apiErrorName)
const frontendError = getIn(form.errors, name)
const error = apiError ?? frontendError
const returnError = apiError ?? frontendError
return {
...form.getFieldProps(name),
id: name,
error: touched && Boolean(error),
helperText: touched ? error || HelperText : HelperText,
error: touched && Boolean(returnError),
helperText: touched ? returnError || HelperText : HelperText,
}
}
export const getFormHelpersWithError = <T>(
form: FormikContextType<T>,
error?: Error | unknown,
): ((name: keyof T, HelperText?: ReactNode, errorName?: string) => FormHelpers) => {
const apiValidationErrors =
isApiError(error) && hasApiFieldErrors(error)
? (mapApiErrorToFieldErrors(error.response.data) as FormikErrors<T>)
: undefined
return getFormHelpers(form, apiValidationErrors)
}
export const onChangeTrimmed =
<T>(form: FormikContextType<T>) =>
(event: ChangeEvent<HTMLInputElement>): void => {