Skip to content

Commit

Permalink
feat(de edit and new): handle loading and error states correctly
Browse files Browse the repository at this point in the history
  • Loading branch information
Mohammer5 committed Oct 25, 2023
1 parent 402de21 commit 32f7e20
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 88 deletions.
10 changes: 5 additions & 5 deletions i18n/en.pot
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ msgstr ""
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"POT-Creation-Date: 2023-10-25T11:41:05.785Z\n"
"PO-Revision-Date: 2023-10-25T11:41:05.785Z\n"
"POT-Creation-Date: 2023-10-25T11:43:32.223Z\n"
"PO-Revision-Date: 2023-10-25T11:43:32.223Z\n"

msgid "schemas"
msgstr "schemas"
Expand Down Expand Up @@ -606,6 +606,9 @@ msgstr "Owner"
msgid "Zero is significant"
msgstr "Zero is significant"

msgid "Custom attributes"
msgstr "Custom attributes"

msgid "Something went wrong when submitting the form"
msgstr "Something went wrong when submitting the form"

Expand Down Expand Up @@ -682,9 +685,6 @@ msgstr ""
msgid "Aggregation levels"
msgstr "Aggregation levels"

msgid "Custom attributes"
msgstr "Custom attributes"

msgid "Custom fields for your DHIS2 instance"
msgstr "Custom fields for your DHIS2 instance"

Expand Down
100 changes: 64 additions & 36 deletions src/pages/dataElements/Edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ import { FORM_ERROR, FormApi } from 'final-form'
import React, { useEffect, useRef } from 'react'
import { withTypes } from 'react-final-form'
import { useNavigate, useParams } from 'react-router-dom'
import { StandardFormActions, StandardFormSection } from '../../components'
import {
Loader,
StandardFormActions,
StandardFormSection,
} from '../../components'
import { SCHEMA_SECTIONS, getSectionPath } from '../../lib'
import { JsonPatchOperation } from '../../types'
import { Attribute, DataElement } from '../../types/generated'
Expand Down Expand Up @@ -40,12 +44,18 @@ function useDataElementQuery(id: string) {
}

function computeInitialValues({
dataElementId,
dataElement,
customAttributes,
}: {
dataElementId: string
dataElement: DataElement
customAttributes: Attribute[]
}) {
if (!dataElement) {
return {}
}

// We want to have an array in the state with all attributes, not just the
// ones that have a value which is what the endpoint responds with
const attributeValues = customAttributes.map((attribute) => {
Expand All @@ -62,6 +72,7 @@ function computeInitialValues({
})

return {
id: dataElementId,
name: dataElement.name,
shortName: dataElement.shortName,
code: dataElement.code,
Expand All @@ -86,42 +97,30 @@ function computeInitialValues({
}
}

export const Component = () => {
function usePatchDirtyFields() {
const dataEngine = useDataEngine()
const navigate = useNavigate()
const params = useParams()

const dataElementId = params.id as string
const dataElementQuery = useDataElementQuery(dataElementId)
const customAttributesQuery = useCustomAttributesQuery()

const loading = dataElementQuery.loading || customAttributesQuery.loading
const error = dataElementQuery.error || customAttributesQuery.error

if (error && !loading) {
// @TODO(Edit): Implement error screen
return `Error: ${error.toString()}`
}

if (loading) {
// @TODO(Edit): Implement loading screen
return 'Loading...'
}

async function onSubmit(values: FormValues, form: FinalFormFormApi) {
const dirtyFields = form.getState().dirtyFields
return async ({
values,
dirtyFields,
dataElement,
}: {
values: FormValues
dirtyFields: { [name: string]: boolean }
dataElement: DataElement
}) => {
const jsonPatchPayload = createJsonPatchOperations({
values,
dirtyFields,
dataElement: dataElementQuery.data?.dataElement as DataElement,
dataElement,
})

// We want the promise so we know when submitting is done. The promise
// returned by the mutation function of useDataMutation will never
// resolve
const ADD_NEW_DATA_ELEMENT_MUTATION = {
resource: 'dataElements',
id: dataElementId,
id: values.id,
type: 'json-patch',
data: ({ operations }: { operations: JsonPatchOperation[] }) =>
operations,
Expand All @@ -134,26 +133,55 @@ export const Component = () => {
} catch (e) {
return { [FORM_ERROR]: (e as Error | string).toString() }
}
}
}

export const Component = () => {
const navigate = useNavigate()
const params = useParams()
const dataElementId = params.id as string
const dataElementQuery = useDataElementQuery(dataElementId)
const customAttributesQuery = useCustomAttributesQuery()
const patchDirtyFields = usePatchDirtyFields()

async function onSubmit(values: FormValues, form: FinalFormFormApi) {
const errors = await patchDirtyFields({
values,
dirtyFields: form.getState().dirtyFields,
dataElement: dataElementQuery.data?.dataElement as DataElement,
})

if (errors) {
return errors
}

navigate(listPath)
}

const initialValues = computeInitialValues({
dataElementId,
dataElement: dataElementQuery.data?.dataElement as DataElement,
customAttributes: customAttributesQuery.data,
customAttributes: customAttributesQuery.data || [],
})

return (
<Form onSubmit={onSubmit} initialValues={initialValues}>
{({ handleSubmit, submitting, submitError }) => (
<form onSubmit={handleSubmit}>
<FormContents
submitError={submitError}
submitting={submitting}
/>
</form>
)}
</Form>
<Loader queryResponse={dataElementQuery} label={i18n.t('Data element')}>
<Loader
queryResponse={customAttributesQuery}
label={i18n.t('Custom attributes')}
>
<Form onSubmit={onSubmit} initialValues={initialValues}>
{({ handleSubmit, submitting, submitError }) => (
<form onSubmit={handleSubmit}>
<FormContents
submitError={submitError}
submitting={submitting}
/>
</form>
)}
</Form>
</Loader>
</Loader>
)
}

Expand Down
49 changes: 21 additions & 28 deletions src/pages/dataElements/New.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ import { FORM_ERROR } from 'final-form'
import React, { useEffect, useRef } from 'react'
import { Form } from 'react-final-form'
import { useNavigate } from 'react-router-dom'
import { StandardFormActions, StandardFormSection } from '../../components'
import {
Loader,
StandardFormActions,
StandardFormSection,
} from '../../components'
import { SCHEMA_SECTIONS, getSectionPath } from '../../lib'
import { Attribute } from '../../types/generated'
import { DataElementFormFields, useCustomAttributesQuery } from './form'
Expand Down Expand Up @@ -80,27 +84,11 @@ function formatFormValues({ values }: { values: FormValues }) {
}
}

// @TODO(DataElements/new): values dynamic or static?
export const Component = () => {
const dataEngine = useDataEngine()

const navigate = useNavigate()
const customAttributesQuery = useCustomAttributesQuery()

const loading = customAttributesQuery.loading
const error = customAttributesQuery.error

if (error && !loading) {
// @TODO(Edit): Implement error screen
return <>Error: {error.toString()}</>
}

if (loading) {
// @TODO(Edit): Implement loading screen
return <>Loading...</>
}

const initialValues = computeInitialValues(customAttributesQuery.data)
const initialValues = computeInitialValues(customAttributesQuery.data || [])

async function onSubmit(values: FormValues) {
const payload = formatFormValues({ values })
Expand All @@ -120,16 +108,21 @@ export const Component = () => {
}

return (
<Form onSubmit={onSubmit} initialValues={initialValues}>
{({ handleSubmit, submitting, submitError }) => (
<form onSubmit={handleSubmit}>
<FormContents
submitError={submitError}
submitting={submitting}
/>
</form>
)}
</Form>
<Loader
queryResponse={customAttributesQuery}
label={i18n.t('Custom attributes')}
>
<Form onSubmit={onSubmit} initialValues={initialValues}>
{({ handleSubmit, submitting, submitError }) => (
<form onSubmit={handleSubmit}>
<FormContents
submitError={submitError}
submitting={submitting}
/>
</form>
)}
</Form>
</Loader>
)
}

Expand Down
25 changes: 6 additions & 19 deletions src/pages/dataElements/form/DataElementFormFields.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { CheckboxFieldFF, InputFieldFF, TextAreaFieldFF } from '@dhis2/ui'
import React from 'react'
import { Field as FieldRFF } from 'react-final-form'
import {
Loader,
StandardFormSection,
StandardFormSectionTitle,
StandardFormSectionDescription,
Expand All @@ -25,25 +26,11 @@ import { useCustomAttributesQuery } from './useCustomAttributesQuery'
export function DataElementFormFields() {
const customAttributes = useCustomAttributesQuery()

const loading = customAttributes.loading
const error = customAttributes.error

if (loading) {
return <>@TODO(DataElementForm): Loading</>
}

if (error) {
return (
<>
@TODO(DataElementForm): Error
<br />
{error.toString()}
</>
)
}

return (
<>
<Loader
queryResponse={customAttributes}
label={i18n.t('Custom attributes')}
>
<StandardFormSection>
<StandardFormSectionTitle>
{i18n.t('Basic information')}
Expand Down Expand Up @@ -246,6 +233,6 @@ export function DataElementFormFields() {
/>
</StandardFormSection>
)}
</>
</Loader>
)
}

0 comments on commit 32f7e20

Please sign in to comment.