Skip to content

Commit

Permalink
uncommit me
Browse files Browse the repository at this point in the history
  • Loading branch information
Mohammer5 committed Oct 12, 2023
1 parent 783d7ff commit 7c149aa
Show file tree
Hide file tree
Showing 11 changed files with 87 additions and 21 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
8 changes: 6 additions & 2 deletions src/pages/dataElements/Edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ 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 +145,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
11 changes: 8 additions & 3 deletions src/pages/dataElements/New.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ 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 +30,8 @@ function computeInitialValues(customAttributes: Attribute[]) {
color: '',
icon: '',
fieldMask: '',
domainType: 'AGGREGATE',
domainType: '',
// domainType: 'AGGREGATE',
formName: '',
valueType: '',
aggregationType: '',
Expand Down Expand Up @@ -120,7 +121,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
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
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
import i18n from '@dhis2/d2-i18n'
import { z } from 'zod'

const requiredMessage = i18n.t('Required')

export const dataElementSchema = z.object({
name: z.string(),
shortName: z.string(),
name: z.string().min(1, { message: requiredMessage }),
shortName: z.string().min(1, { message: requiredMessage }),
code: z.string().optional(),
description: z.string().optional(),
url: z.string().optional(),
color: z.string().optional(),
style: z.object({
color: z.string().optional(),
icon: z.string().optional(),
}),
icon: z.string().optional(),
fieldMask: z.string().optional(),
domainType: z.union([
Expand Down Expand Up @@ -68,15 +74,17 @@ export const dataElementSchema = z.object({
z.literal('DEFAULT'),
]).optional(),
categoryCombo: z.object({
id: z.string(),
id: z.string().min(1, { message: requiredMessage }),
}),
optionSet: z.object({
id: z.string().optional(),
}),
commentOptionSet: z.object({
id: z.string().optional(),
}),
legendSets: z.array(z.string()),
legendSets: z.array(z.object({
id: z.string(),
})),
aggregationLevels: z.array(z.number()),
attributeValues: z.array(z.object({
value: z.string(),
Expand Down
3 changes: 2 additions & 1 deletion src/pages/dataElements/form/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { DataElementFormFields } from './DataElementFormFields'
export { computeInitialValues } from './computeInitialValues'
export { useCustomAttributesQuery } from './useCustomAttributesQuery'
export { FormValues } from './types'
export type { FormValues } from './types'
export { validate } from './validate'
28 changes: 28 additions & 0 deletions src/pages/dataElements/form/validate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { setIn } from 'final-form'
import { dataElementSchema } from './dataElementSchema'
import type { FormValues } from './types'

// @TODO: Figure out if there's a utility for this? I couldn't find one
function segmentsToPath(segments: Array<string | number>) {
return segments.reduce((path, segment) => {
return typeof segment === 'number'
? `${path}[${segment}]`
: `${path}.${segment}`
}) as string
}

export function validate(values: FormValues) {
const zodResult = dataElementSchema.safeParse(values)

if (zodResult.success !== false) {
console.log('> no validation issues');
return undefined
}

const allFormErrors = zodResult.error.issues.reduce((formErrors, error) => {
const errorPath = segmentsToPath(error.path)
return setIn(formErrors, errorPath, error.message)
}, {})

return allFormErrors
}

0 comments on commit 7c149aa

Please sign in to comment.