mirror of
https://github.com/coder/coder.git
synced 2025-07-12 00:14:10 +00:00
refactor: curry GetFormHelpers (#1156)
This commit is contained in:
@ -49,13 +49,14 @@ export const AccountForm: React.FC<AccountFormProps> = ({
|
|||||||
validationSchema,
|
validationSchema,
|
||||||
onSubmit,
|
onSubmit,
|
||||||
})
|
})
|
||||||
|
const getFieldHelpers = getFormHelpers<AccountFormValues>(form, formErrors)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<form onSubmit={form.handleSubmit}>
|
<form onSubmit={form.handleSubmit}>
|
||||||
<Stack>
|
<Stack>
|
||||||
<TextField
|
<TextField
|
||||||
{...getFormHelpers<AccountFormValues>(form, "name")}
|
{...getFieldHelpers("name")}
|
||||||
autoFocus
|
autoFocus
|
||||||
autoComplete="name"
|
autoComplete="name"
|
||||||
fullWidth
|
fullWidth
|
||||||
@ -63,7 +64,7 @@ export const AccountForm: React.FC<AccountFormProps> = ({
|
|||||||
variant="outlined"
|
variant="outlined"
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
{...getFormHelpers<AccountFormValues>(form, "email", formErrors.email)}
|
{...getFieldHelpers("email")}
|
||||||
onChange={onChangeTrimmed(form)}
|
onChange={onChangeTrimmed(form)}
|
||||||
autoComplete="email"
|
autoComplete="email"
|
||||||
fullWidth
|
fullWidth
|
||||||
@ -71,7 +72,7 @@ export const AccountForm: React.FC<AccountFormProps> = ({
|
|||||||
variant="outlined"
|
variant="outlined"
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
{...getFormHelpers<AccountFormValues>(form, "username", formErrors.username)}
|
{...getFieldHelpers("username")}
|
||||||
onChange={onChangeTrimmed(form)}
|
onChange={onChangeTrimmed(form)}
|
||||||
autoComplete="username"
|
autoComplete="username"
|
||||||
fullWidth
|
fullWidth
|
||||||
|
@ -76,13 +76,14 @@ export const SignInForm: React.FC<SignInFormProps> = ({
|
|||||||
validationSchema,
|
validationSchema,
|
||||||
onSubmit,
|
onSubmit,
|
||||||
})
|
})
|
||||||
|
const getFieldHelpers = getFormHelpers<BuiltInAuthFormValues>(form)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Welcome />
|
<Welcome />
|
||||||
<form onSubmit={form.handleSubmit}>
|
<form onSubmit={form.handleSubmit}>
|
||||||
<TextField
|
<TextField
|
||||||
{...getFormHelpers<BuiltInAuthFormValues>(form, "email")}
|
{...getFieldHelpers("email")}
|
||||||
onChange={onChangeTrimmed(form)}
|
onChange={onChangeTrimmed(form)}
|
||||||
autoFocus
|
autoFocus
|
||||||
autoComplete="email"
|
autoComplete="email"
|
||||||
@ -93,7 +94,7 @@ export const SignInForm: React.FC<SignInFormProps> = ({
|
|||||||
variant="outlined"
|
variant="outlined"
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
{...getFormHelpers<BuiltInAuthFormValues>(form, "password")}
|
{...getFieldHelpers("password")}
|
||||||
autoComplete="current-password"
|
autoComplete="current-password"
|
||||||
className={styles.loginTextField}
|
className={styles.loginTextField}
|
||||||
fullWidth
|
fullWidth
|
||||||
|
@ -37,10 +37,12 @@ const form = {
|
|||||||
|
|
||||||
describe("form util functions", () => {
|
describe("form util functions", () => {
|
||||||
describe("getFormHelpers", () => {
|
describe("getFormHelpers", () => {
|
||||||
const untouchedGoodResult = getFormHelpers<TestType>(form, "untouchedGoodField")
|
describe("without API errors", () => {
|
||||||
const untouchedBadResult = getFormHelpers<TestType>(form, "untouchedBadField")
|
const getFieldHelpers = getFormHelpers<TestType>(form)
|
||||||
const touchedGoodResult = getFormHelpers<TestType>(form, "touchedGoodField")
|
const untouchedGoodResult = getFieldHelpers("untouchedGoodField")
|
||||||
const touchedBadResult = getFormHelpers<TestType>(form, "touchedBadField")
|
const untouchedBadResult = getFieldHelpers("untouchedBadField")
|
||||||
|
const touchedGoodResult = getFieldHelpers("touchedGoodField")
|
||||||
|
const touchedBadResult = getFieldHelpers("touchedBadField")
|
||||||
it("populates the 'field props'", () => {
|
it("populates the 'field props'", () => {
|
||||||
expect(untouchedGoodResult.name).toEqual("untouchedGoodField")
|
expect(untouchedGoodResult.name).toEqual("untouchedGoodField")
|
||||||
expect(untouchedGoodResult.onBlur).toBeDefined()
|
expect(untouchedGoodResult.onBlur).toBeDefined()
|
||||||
@ -63,6 +65,27 @@ describe("form util functions", () => {
|
|||||||
expect(touchedBadResult.helperText).toEqual("oops!")
|
expect(touchedBadResult.helperText).toEqual("oops!")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
describe("with API errors", () => {
|
||||||
|
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.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.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.helperText).toEqual("API error!")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe("onChangeTrimmed", () => {
|
describe("onChangeTrimmed", () => {
|
||||||
it("calls handleChange with trimmed value", () => {
|
it("calls handleChange with trimmed value", () => {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { FormikContextType, getIn } from "formik"
|
import { FormikContextType, FormikErrors, getIn } from "formik"
|
||||||
import { ChangeEvent, ChangeEventHandler, FocusEventHandler } from "react"
|
import { ChangeEvent, ChangeEventHandler, FocusEventHandler } from "react"
|
||||||
|
|
||||||
interface FormHelpers {
|
interface FormHelpers {
|
||||||
@ -11,7 +11,9 @@ interface FormHelpers {
|
|||||||
helperText?: string
|
helperText?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getFormHelpers = <T>(form: FormikContextType<T>, name: keyof T, error?: string): FormHelpers => {
|
export const getFormHelpers =
|
||||||
|
<T>(form: FormikContextType<T>, formErrors?: FormikErrors<T>) =>
|
||||||
|
(name: keyof T): FormHelpers => {
|
||||||
if (typeof name !== "string") {
|
if (typeof name !== "string") {
|
||||||
throw new Error(`name must be type of string, instead received '${typeof name}'`)
|
throw new Error(`name must be type of string, instead received '${typeof name}'`)
|
||||||
}
|
}
|
||||||
@ -19,14 +21,16 @@ export const getFormHelpers = <T>(form: FormikContextType<T>, name: keyof T, err
|
|||||||
// getIn is a util function from Formik that gets at any depth of nesting
|
// getIn is a util function from Formik that gets at any depth of nesting
|
||||||
// and is necessary for the types to work
|
// and is necessary for the types to work
|
||||||
const touched = getIn(form.touched, name)
|
const touched = getIn(form.touched, name)
|
||||||
const errors = error ?? getIn(form.errors, name)
|
const apiError = getIn(formErrors, name)
|
||||||
|
const validationError = getIn(form.errors, name)
|
||||||
|
const error = apiError ?? validationError
|
||||||
return {
|
return {
|
||||||
...form.getFieldProps(name),
|
...form.getFieldProps(name),
|
||||||
id: name,
|
id: name,
|
||||||
error: touched && Boolean(errors),
|
error: touched && Boolean(error),
|
||||||
helperText: touched && errors,
|
helperText: touched && error,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
export const onChangeTrimmed =
|
export const onChangeTrimmed =
|
||||||
<T>(form: FormikContextType<T>) =>
|
<T>(form: FormikContextType<T>) =>
|
||||||
|
Reference in New Issue
Block a user