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.50.1",
"path-to-regexp": "3.0.0",
"react": "18.2.0",
"react-dom": "18.2.0",
Expand Down
85 changes: 52 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 { useForm } from 'react-hook-form'
import styled from 'styled-components'

import {
Expand All @@ -19,6 +19,7 @@ import { StyledText } from '../../atoms/text'
import { addManualIp } from '../../redux/config'
import { startDiscovery } from '../../redux/discovery'

import type { FieldError, Resolver } from 'react-hook-form'
import type { Dispatch } from '../../redux/types'

const FlexForm = styled.form`
Expand Down Expand Up @@ -55,8 +56,8 @@ const StyledInput = styled.input`
}
`

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

const resolver: Resolver<FormValues> = values => {
let errors = {}
errors = validateForm(values, errors)
return { values, errors }
}
const { formState, handleSubmit, register, reset } = useForm<FormValues>({
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 validateForm = (
data: FormValues,
errors: Record<string, FieldError>
): Record<string, FieldError> => {
const ip = data.ip.trim()
let message: string | undefined
if (!ip) {
message = t('add_ip_error')
}
const updatedErrors =
message != null
? {
...errors,
ip: {
type: 'error',
message: message,
},
}
: errors
return updatedErrors
}

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 +143,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