Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(app): deprecate formik, migrate to react-hook-form #14424

Merged
merged 13 commits into from
Feb 28, 2024
2 changes: 1 addition & 1 deletion app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,14 @@
"date-fns": "2.25.0",
"events": "3.0.0",
"file-saver": "2.0.1",
"formik": "2.1.4",
"history": "4.7.2",
"i18next": "^19.8.3",
"is-ip": "3.1.0",
"jszip": "3.2.2",
"lodash": "4.17.21",
"mixpanel-browser": "2.22.1",
"netmask": "2.0.2",
"react-hook-form": "7.49.3",
jerader marked this conversation as resolved.
Show resolved Hide resolved
"path-to-regexp": "3.0.0",
"react": "18.2.0",
"react-dom": "18.2.0",
Expand Down
86 changes: 53 additions & 33 deletions app/src/organisms/AppSettings/ManualIpHostnameForm.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as React from 'react'
import { useDispatch } from 'react-redux'
import { useTranslation } from 'react-i18next'
import { useFormik } from 'formik'
import { FieldError, Resolver, useForm } from 'react-hook-form'
jerader marked this conversation as resolved.
Show resolved Hide resolved
import styled from 'styled-components'

import {
Expand Down Expand Up @@ -55,8 +55,8 @@ const StyledInput = styled.input`
}
`

interface FormikErrors {
ip?: string
interface FormValues {
ip: string
}
interface ManualIpHostnameFormProps {
setMostRecentAddition: (ip: string) => void
Expand All @@ -71,47 +71,67 @@ export function ManualIpHostnameForm({
dispatch(addManualIp(ip))
dispatch(startDiscovery())
}
const formik = useFormik({
initialValues: {

const validateForm = (
data: FormValues,
errors: Record<string, FieldError>
): Record<string, FieldError> => {
const ip = data.ip.trim()
let message: string | undefined
// ToDo: kj 12/19/2022 for this, the best way is to use the regex because invisible unicode characters
jerader marked this conversation as resolved.
Show resolved Hide resolved
if (!ip) {
message = t('add_ip_error')
}
const updatedErrors =
message != null
? {
...errors,
ip: {
type: 'error',
message: message,
},
}
: errors
return updatedErrors
}

const resolver: Resolver<FormValues> = values => {
let errors = {}
errors = validateForm(values, errors)
return { values, errors }
}

const { formState, handleSubmit, register, reset } = useForm<FormValues>({
jerader marked this conversation as resolved.
Show resolved Hide resolved
defaultValues: {
ip: '',
},
onSubmit: (values, { resetForm }) => {
const ip = values.ip.trim()
const inputForm = document.getElementById('ip')
if (inputForm != null)
inputForm.style.border = `1px solid ${String(COLORS.grey30)}`
addManualIpAndHostname(ip)
resetForm()
setMostRecentAddition(ip)
},
validate: values => {
const errors: FormikErrors = {}
const ip = values.ip.trim()
// ToDo: kj 12/19/2022 for this, the best way is to use the regex because invisible unicode characters
if (!ip) {
errors.ip = t('add_ip_error')
const inputForm = document.getElementById('ip')
if (inputForm != null)
inputForm.style.border = `1px solid ${String(COLORS.red50)}`
}
return errors
},
resolver: resolver,
})

const onSubmit = (data: FormValues): void => {
jerader marked this conversation as resolved.
Show resolved Hide resolved
const trimmedIp = data.ip.trim()
const inputForm = document.getElementById('ip')

if (inputForm !== null) {
inputForm.style.border = `1px solid ${COLORS.grey30}`
}

addManualIpAndHostname(trimmedIp)
reset()
setMostRecentAddition(trimmedIp)
}

return (
<Flex
flexDirection={DIRECTION_COLUMN}
margin={`${SPACING.spacing4} 0`}
height={SPACING.spacing32}
>
<FlexForm onSubmit={formik.handleSubmit}>
<FlexForm onSubmit={handleSubmit(onSubmit)}>
<StyledInput
id="ip"
name="ip"
type="text"
onChange={formik.handleChange}
onBlur={formik.handleBlur}
value={formik.values.ip}
{...register('ip')}
data-testid="manual-ip-hostname-input"
/>
<TertiaryButton
Expand All @@ -124,13 +144,13 @@ export function ManualIpHostnameForm({
{t('add_ip_button')}
</TertiaryButton>
</FlexForm>
{formik.errors.ip != null && (
{formState.errors?.ip != null && (
<StyledText
as="label"
marginTop={SPACING.spacing4}
color={COLORS.red50}
>
{formik.errors.ip}
{formState.errors.ip.message}
</StyledText>
)}
</Flex>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ describe('ConnectRobotSlideout', () => {
it.todo(
'Clicking Add button with an IP address/hostname should display the IP address/hostname and Not Found label'
)
// NOTE: consider mocking formik here?
// NOTE: consider mocking react-hook-form here?
// , async () => {
// mockGetConfig.mockReturnValue({ discovery: { candidates: ['1.1.1.2'] } } as any)
// mockGetViewableRobots.mockReturnValue([] as any[])
Expand Down
Loading
Loading