Skip to content

Commit

Permalink
feat(de forms): implement validation with zod
Browse files Browse the repository at this point in the history
  • Loading branch information
Mohammer5 committed Oct 12, 2023
1 parent 783d7ff commit 69a6081
Show file tree
Hide file tree
Showing 12 changed files with 182 additions and 103 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,15 @@ interface SearchableSingleSelectPropTypes {
showEndLoader: boolean
loading: boolean
selected?: string
invalid?: boolean
error?: string
showAllOption?: boolean
onBlur?: () => void
onFocus?: () => void
}

export const SearchableSingleSelect = ({
invalid,
error,
loading,
placeholder,
Expand Down Expand Up @@ -121,6 +123,7 @@ export const SearchableSingleSelect = ({
// fetched the corresponding label yet. Therefore we don't want to pass in
// any value to the "selected" prop, as otherwise an error will be thrown
selected={hasSelectedInOptionList ? selected : ''}
error={invalid}
onChange={onChange}
placeholder={placeholder}
onBlur={onBlur}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ interface AggregationLevelMultiSelectProps {
onChange: ({ selected }: { selected: string[] }) => void
onRetryClick: () => void
inputWidth?: string
invalid?: boolean
placeholder?: string
selected?: string[]
showAllOption?: boolean
Expand All @@ -43,6 +44,7 @@ export const AggregationLevelMultiSelect = forwardRef(
{
onChange,
inputWidth,
invalid,
selected,
showAllOption,
placeholder = i18n.t('Aggregation level(s)'),
Expand All @@ -67,7 +69,7 @@ export const AggregationLevelMultiSelect = forwardRef(
onChange={({ selected }: { selected: string[] }) => {
onChange({ selected })
}}
error={!!optionsQuery.error}
error={!!optionsQuery.error || invalid}
selected={loading ? [] : selected}
loading={loading}
onBlur={onBlur}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { useOptionsQuery } from './useOptionsQuery'

interface CategoryComboSelectProps {
onChange: ({ selected }: { selected: string }) => void
invalid?: boolean
placeholder?: string
selected?: string
showAllOption?: boolean
Expand All @@ -16,6 +17,7 @@ interface CategoryComboSelectProps {
export const CategoryComboSelect = forwardRef(function CategoryComboSelect(
{
onChange,
invalid,
placeholder = i18n.t('Category combo'),
selected,
showAllOption,
Expand All @@ -27,6 +29,7 @@ export const CategoryComboSelect = forwardRef(function CategoryComboSelect(
return (
<ModelSingleSelect
ref={ref}
invalid={invalid}
useInitialOptionQuery={useInitialOptionQuery}
useOptionsQuery={useOptionsQuery}
placeholder={placeholder}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ type UseInitialOptionQuery = ({

interface ModelSingleSelectProps {
onChange: ({ selected }: { selected: string }) => void
invalid?: boolean
placeholder?: string
selected?: string
showAllOption?: boolean
Expand All @@ -62,6 +63,7 @@ export interface ModelSingleSelectHandle {
export const ModelSingleSelect = forwardRef(function ModelSingleSelect(
{
onChange,
invalid,
placeholder = '',
selected,
showAllOption,
Expand Down Expand Up @@ -139,6 +141,7 @@ export const ModelSingleSelect = forwardRef(function ModelSingleSelect(

return (
<SearchableSingleSelect
invalid={invalid}
placeholder={placeholder}
showAllOption={showAllOption}
onChange={({ selected }) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { useOptionsQuery } from './useOptionsQuery'

interface OptionSetSelectProps {
onChange: ({ selected }: { selected: string }) => void
invalid?: boolean
placeholder?: string
selected?: string
showAllOption?: boolean
Expand All @@ -16,6 +17,7 @@ interface OptionSetSelectProps {
export const OptionSetSelect = forwardRef(function OptionSetSelect(
{
onChange,
invalid,
placeholder = i18n.t('Option set'),
selected,
showAllOption,
Expand All @@ -27,6 +29,7 @@ export const OptionSetSelect = forwardRef(function OptionSetSelect(
return (
<ModelSingleSelect
ref={ref}
invalid={invalid}
useInitialOptionQuery={useInitialOptionQuery}
useOptionsQuery={useOptionsQuery}
placeholder={placeholder}
Expand Down
12 changes: 10 additions & 2 deletions src/pages/dataElements/Edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ import { JsonPatchOperation } from '../../types'
import { Attribute, DataElement } from '../../types/generated'
import { createJsonPatchOperations } from './edit'
import classes from './Edit.module.css'
import { DataElementFormFields, useCustomAttributesQuery } from './form'
import {
DataElementFormFields,
useCustomAttributesQuery,
validate,
} from './form'
import type { FormValues } from './form'

type FinalFormFormApi = FormApi<FormValues>
Expand Down Expand Up @@ -145,7 +149,11 @@ export const Component = () => {
})

return (
<Form onSubmit={onSubmit} initialValues={initialValues}>
<Form
onSubmit={onSubmit}
validate={validate}
initialValues={initialValues}
>
{({ handleSubmit, submitting, submitError }) => (
<form onSubmit={handleSubmit}>
<FormContents
Expand Down
15 changes: 12 additions & 3 deletions src/pages/dataElements/New.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ import { StandardFormActions, StandardFormSection } from '../../components'
import { SCHEMA_SECTIONS } from '../../constants'
import { getSectionPath } from '../../lib'
import { Attribute } from '../../types/generated'
import { DataElementFormFields, useCustomAttributesQuery } from './form'
import {
DataElementFormFields,
useCustomAttributesQuery,
validate,
} from './form'
import type { FormValues } from './form'
import classes from './New.module.css'

Expand All @@ -30,7 +34,8 @@ function computeInitialValues(customAttributes: Attribute[]) {
color: '',
icon: '',
fieldMask: '',
domainType: 'AGGREGATE',
domainType: '',
// domainType: 'AGGREGATE',
formName: '',
valueType: '',
aggregationType: '',
Expand Down Expand Up @@ -120,7 +125,11 @@ export const Component = () => {
}

return (
<Form onSubmit={onSubmit} initialValues={initialValues}>
<Form
onSubmit={onSubmit}
initialValues={initialValues}
validate={validate}
>
{({ handleSubmit, submitting, submitError }) => (
<form onSubmit={handleSubmit}>
<FormContents
Expand Down
87 changes: 0 additions & 87 deletions src/pages/dataElements/edit/dataElementSchema.ts

This file was deleted.

24 changes: 15 additions & 9 deletions src/pages/dataElements/form/customFields.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export function DomainField() {
value: 'TRACKER',
validate,
})
const touched = aggregateInput.meta.touched || trackerInput.meta.touched
const error = aggregateInput.meta.error || trackerInput.meta.error

return (
Expand All @@ -73,8 +74,8 @@ export function DomainField() {
helpText={i18n.t(
'A data element can either be aggregated or tracked data.'
)}
error={!!error}
validationText={error}
error={touched && !!error}
validationText={touched ? error : undefined}
>
<div>
<Radio
Expand Down Expand Up @@ -234,20 +235,19 @@ export function CategoryComboField() {
<div className={classes.categoryComboSelect}>
<Field
required
validate={(value: string) =>
!value ? 'Required' : undefined
}
name="categoryCombo.id"
label={i18n.t('{{fieldLabel}} (required)', {
fieldLabel: i18n.t('Category combination'),
})}
helpText={i18n.t(
'Choose how this data element is disaggregated'
)}
validationText={meta.error}
error={meta.touched && !!meta.error}
validationText={meta.touched ? meta.error : undefined}
>
<CategoryComboSelect
placeholder=""
invalid={meta.touched && !!meta.error}
ref={categoryComboHandle}
selected={input.value}
onChange={({ selected }) => input.onChange(selected)}
Expand Down Expand Up @@ -282,10 +282,12 @@ export function OptionSetField() {
helpText={i18n.t(
'Choose a set of predefined options for data entry'
)}
validationText={meta.error}
validationText={meta.touched ? meta.error : undefined}
error={meta.touched && !!meta.error}
>
<OptionSetSelect
placeholder=""
invalid={meta.touched && !!meta.error}
ref={optionSetHandle}
selected={input.value}
onChange={({ selected }) => input.onChange(selected)}
Expand Down Expand Up @@ -320,10 +322,12 @@ export function OptionSetCommentField() {
helpText={i18n.t(
'Choose a set of predefined comment for data entry'
)}
validationText={meta.error}
validationText={meta.touched ? meta.error : undefined}
error={meta.touched && !!meta.error}
>
<OptionSetSelect
ref={optionSetHandle}
invalid={meta.touched && !!meta.error}
placeholder=""
selected={input.value}
onChange={({ selected }) => input.onChange(selected)}
Expand Down Expand Up @@ -362,10 +366,12 @@ export function AggregationLevelsField() {
helpText={i18n.t(
'Choose how this data element is disaggregated'
)}
validationText={meta.error}
validationText={meta.touched ? meta.error : undefined}
error={meta.touched && !!meta.error}
>
<AggregationLevelMultiSelect
ref={aggregationLevelHandle}
invalid={meta.touched && !!meta.error}
inputWidth="400px"
placeholder=""
selected={input.value}
Expand Down
Loading

0 comments on commit 69a6081

Please sign in to comment.