Skip to content

Commit

Permalink
migrate some more compontns
Browse files Browse the repository at this point in the history
  • Loading branch information
jerader committed Feb 5, 2024
1 parent 3cbd62c commit d1bb534
Show file tree
Hide file tree
Showing 10 changed files with 466 additions and 295 deletions.
37 changes: 22 additions & 15 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 { useForm } from 'react-hook-form'
import { FieldError, Resolver, useForm } from 'react-hook-form'
import styled from 'styled-components'

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

interface FormErrors {
ip?: {
type: string
message: string
}
}
interface FormValues {
ip: string
}
Expand All @@ -78,23 +72,36 @@ export function ManualIpHostnameForm({
dispatch(startDiscovery())
}

const validateForm = (data: FormValues): any => {
const errors: FormErrors = {}
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
if (!ip) {
errors.ip = { type: 'required', message: t('add_ip_error') }
message = t('add_ip_error')
}
return {
...errors,
['ip']: {

Check failure on line 87 in app/src/organisms/AppSettings/ManualIpHostnameForm.tsx

View workflow job for this annotation

GitHub Actions / js checks

Unnecessarily computed property ['ip'] found
type: 'error',
message: message,
},
}
return errors
}

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

const { formState, handleSubmit, register, reset } = useForm<FormValues>({
defaultValues: {
ip: '',
},
resolver: data => {
return validateForm(data)
},
resolver: resolver,
})

const onSubmit = (data: FormValues): void => {
Expand Down Expand Up @@ -139,7 +146,7 @@ export function ManualIpHostnameForm({
marginTop={SPACING.spacing4}
color={COLORS.red50}
>
{formState.errors.ip}
{formState.errors.ip.message}
</StyledText>
)}
</Flex>
Expand Down
212 changes: 115 additions & 97 deletions app/src/organisms/ConfigurePipette/ConfigForm.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import * as React from 'react'
import { Formik, Form } from 'formik'

import startCase from 'lodash/startCase'
import mapValues from 'lodash/mapValues'
Expand All @@ -15,13 +14,13 @@ import {
ConfigQuirkGroup,
} from './ConfigFormGroup'

import type { FormikProps } from 'formik'
import type { FormValues } from './ConfigFormGroup'
import type {
PipetteSettingsField,
PipetteSettingsFieldsMap,
UpdatePipetteSettingsData,
} from '@opentrons/api-client'
import { FieldError, Resolver, useForm } from 'react-hook-form'

export interface DisplayFieldProps extends PipetteSettingsField {
name: string
Expand All @@ -47,11 +46,19 @@ const POWER_KEYS = ['plungerCurrent', 'pickUpCurrent', 'dropTipCurrent']
const TIP_KEYS = ['dropTipSpeed', 'pickUpDistance']
const QUIRK_KEY = 'quirks'

export class ConfigForm extends React.Component<ConfigFormProps> {
getFieldsByKey(
export const ConfigForm = (props: ConfigFormProps): JSX.Element => {
const {
updateInProgress,
formId,
settings,
updateSettings,
groupLabels,
} = props

const getFieldsByKey = (
keys: string[],
fields: PipetteSettingsFieldsMap
): DisplayFieldProps[] {
): DisplayFieldProps[] => {
return keys.map(k => {
const field = fields[k]
const displayName = startCase(k)
Expand All @@ -64,8 +71,8 @@ export class ConfigForm extends React.Component<ConfigFormProps> {
})
}

getKnownQuirks = (): DisplayQuirkFieldProps[] => {
const quirks = this.props.settings[QUIRK_KEY]
const getKnownQuirks = (): DisplayQuirkFieldProps[] => {
const quirks = settings[QUIRK_KEY]
if (!quirks) return []
const quirkKeys = Object.keys(quirks)
return quirkKeys.map<DisplayQuirkFieldProps>((name: string) => {
Expand All @@ -79,22 +86,17 @@ export class ConfigForm extends React.Component<ConfigFormProps> {
})
}

getVisibleFields: () => PipetteSettingsFieldsMap = () => {
return omit(this.props.settings, [QUIRK_KEY])
const getVisibleFields = (): PipetteSettingsFieldsMap => {
return omit(settings, [QUIRK_KEY])
}

getUnknownKeys: () => string[] = () => {
const getUnknownKeys = (): string[] => {
return keys(
omit(this.props.settings, [
...PLUNGER_KEYS,
...POWER_KEYS,
...TIP_KEYS,
QUIRK_KEY,
])
omit(settings, [...PLUNGER_KEYS, ...POWER_KEYS, ...TIP_KEYS, QUIRK_KEY])
)
}

handleSubmit: (values: FormValues) => void = values => {
const onSubmit: (values: FormValues) => void = values => {
const fields = mapValues<
FormValues,
{ value: PipetteSettingsField['value'] } | null
Expand All @@ -104,29 +106,31 @@ export class ConfigForm extends React.Component<ConfigFormProps> {
return { value: Number(v) }
})

this.props.updateSettings({ fields })
updateSettings({ fields })
}

getFieldValue(
const getFieldValue = (
key: string,
fields: DisplayFieldProps[],
values: FormValues
): number {
): number => {
const field = fields.find(f => f.name === key)
const _default = field && field.default
const value = values[key] || _default
return Number(value)
}

validate = (values: FormValues): {} => {
const errors = {}
const fields = this.getVisibleFields()
const plungerFields = this.getFieldsByKey(PLUNGER_KEYS, fields)
const validate = (
values: FormValues,
errors: Record<string, FieldError>
): Record<string, FieldError> => {
const fields = getVisibleFields()
const plungerFields = getFieldsByKey(PLUNGER_KEYS, fields)

// validate all visible fields with min and max
forOwn(fields, (field, name) => {
// @ts-expect-error TODO: value needs to be of type string here, but technically that's not prover
const value = values[name].trim()
const value = values[name]?.trim()
const { min, max } = field
if (value !== '') {
const parsed = Number(value)
Expand All @@ -138,26 +142,38 @@ export class ConfigForm extends React.Component<ConfigFormProps> {
// TODO(bc, 2021-05-18): this should probably be (parsed < min || parsed > max) so we're not accidentally comparing a string to a number
(parsed < min || value > max)
) {
set(errors, name, `Min ${min} / Max ${max}`)
set(errors, name, {
type: 'numberError',
message: `Min ${min} / Max ${max}`,
})
}
}
})

const plungerGroupError =
'Please ensure the following: \n top > bottom > blowout > droptip'
const top = this.getFieldValue('top', plungerFields, values)
const bottom = this.getFieldValue('bottom', plungerFields, values)
const blowout = this.getFieldValue('blowout', plungerFields, values)
const dropTip = this.getFieldValue('dropTip', plungerFields, values)
const top = getFieldValue('top', plungerFields, values)
const bottom = getFieldValue('bottom', plungerFields, values)
const blowout = getFieldValue('blowout', plungerFields, values)
const dropTip = getFieldValue('dropTip', plungerFields, values)
if (top <= bottom || bottom <= blowout || blowout <= dropTip) {
set(errors, 'plungerError', plungerGroupError)
set(errors, 'plungerError', {
type: 'plungerError',
message: plungerGroupError,
})
}

return errors
}

getInitialValues: () => FormValues = () => {
const fields = this.getVisibleFields()
const resolver: Resolver<FormValues> = values => {
let errors = {}
errors = validate(values, errors)
return { values, errors }
}

const getInitialValues: () => FormValues = () => {
const fields = getVisibleFields()
const initialFieldValues = mapValues<
PipetteSettingsFieldsMap,
string | boolean
Expand All @@ -166,7 +182,7 @@ export class ConfigForm extends React.Component<ConfigFormProps> {
// @ts-expect-error(sa, 2021-05-27): avoiding src code change, use optional chain to access f.value
return f.value !== f.default ? f.value.toString() : ''
})
const initialQuirkValues = this.props.settings[QUIRK_KEY]
const initialQuirkValues = settings[QUIRK_KEY]
const initialValues = Object.assign(
{},
initialFieldValues,
Expand All @@ -176,68 +192,70 @@ export class ConfigForm extends React.Component<ConfigFormProps> {
return initialValues
}

render(): JSX.Element {
const { updateInProgress, formId } = this.props
const fields = this.getVisibleFields()
const UNKNOWN_KEYS = this.getUnknownKeys()
const plungerFields = this.getFieldsByKey(PLUNGER_KEYS, fields)
const powerFields = this.getFieldsByKey(POWER_KEYS, fields)
const tipFields = this.getFieldsByKey(TIP_KEYS, fields)
const quirkFields = this.getKnownQuirks()
const quirksPresent = quirkFields.length > 0
const unknownFields = this.getFieldsByKey(UNKNOWN_KEYS, fields)
const initialValues = this.getInitialValues()

return (
<Formik
onSubmit={this.handleSubmit}
initialValues={initialValues}
validate={this.validate}
validateOnChange={false}
>
{(formProps: FormikProps<FormValues>) => {
const { errors, values } = formProps
const handleReset = (): void => {
const newValues = mapValues(values, v => {
if (typeof v === 'boolean') {
// NOTE: checkbox fields don't have defaults from the API b/c they come in from `quirks`
// For now, we'll reset all checkboxes to true
return true
}
return ''
})
formProps.resetForm({ values: newValues })
}
return (
<Box overflowY={OVERFLOW_AUTO}>
<Form id={formId}>
<ConfigFormResetButton
onClick={handleReset}
disabled={updateInProgress}
/>
<FormColumn>
<ConfigFormGroup
groupLabel={this.props.groupLabels[0]}
groupError={errors.plungerError}
formFields={plungerFields}
/>
<ConfigFormGroup
groupLabel={this.props.groupLabels[1]}
formFields={[...tipFields, ...unknownFields]}
/>
{quirksPresent && <ConfigQuirkGroup quirks={quirkFields} />}
</FormColumn>
<FormColumn>
<ConfigFormGroup
groupLabel={this.props.groupLabels[2]}
formFields={powerFields}
/>
</FormColumn>
</Form>
</Box>
)
}}
</Formik>
)
const fields = getVisibleFields()
const UNKNOWN_KEYS = getUnknownKeys()
const plungerFields = getFieldsByKey(PLUNGER_KEYS, fields)
const powerFields = getFieldsByKey(POWER_KEYS, fields)
const tipFields = getFieldsByKey(TIP_KEYS, fields)
const quirkFields = getKnownQuirks()
const quirksPresent = quirkFields.length > 0
const unknownFields = getFieldsByKey(UNKNOWN_KEYS, fields)
const initialValues = getInitialValues()

const {
handleSubmit,
reset,
getValues,
control,
formState: { errors },
} = useForm<FormValues>({
defaultValues: initialValues,
resolver: resolver,
})

const handleReset = (): void => {
const newValues = mapValues(getValues(), v => {
if (typeof v === 'boolean') {
// NOTE: checkbox fields don't have defaults from the API b/c they come in from `quirks`
// For now, we'll reset all checkboxes to true
return true
}
return ''
})
reset(newValues)
}

return (
<form onSubmit={handleSubmit(onSubmit)} id={formId}>
<Box overflowY={OVERFLOW_AUTO}>
<ConfigFormResetButton
onClick={handleReset}
disabled={updateInProgress}
/>
<FormColumn>
<ConfigFormGroup
groupLabel={groupLabels[0]}
groupError={errors.plungerError?.message}
formFields={plungerFields}
control={control}
/>
<ConfigFormGroup
groupLabel={groupLabels[1]}
formFields={[...tipFields, ...unknownFields]}
control={control}
/>
{quirksPresent && (
<ConfigQuirkGroup quirks={quirkFields} control={control} />
)}
</FormColumn>
<FormColumn>
<ConfigFormGroup
groupLabel={groupLabels[2]}
control={control}
formFields={powerFields}
/>
</FormColumn>
</Box>
</form>
)
}
Loading

0 comments on commit d1bb534

Please sign in to comment.