Skip to content

Commit

Permalink
feat: implement merging of indicators
Browse files Browse the repository at this point in the history
  • Loading branch information
Chisomchima committed Jan 24, 2025
1 parent a264d6f commit a84ee60
Show file tree
Hide file tree
Showing 4 changed files with 240 additions and 0 deletions.
90 changes: 90 additions & 0 deletions src/pages/indicators/Merge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { useDataEngine } from '@dhis2/app-runtime'
import i18n from '@dhis2/d2-i18n'
import React, { useMemo } from 'react'
import { Form } from 'react-final-form'
import {
DefaultMergeFormContents,
MergeComplete,
StyledMergeForm,
Title,
} from '../../components/merge'
import { getDefaults, useLocationWithState } from '../../lib'
import { createFormError } from '../../lib/form/createFormError'
import { IndicatorMergeFormFields } from './merge/IndicatorMergeFormFields'
import {
IndicatorMergeFormValues,
mergeFormSchema,
validate,
} from './merge/IndicatorMergeSchema'

export const Component = () => {
const location = useLocationWithState<{ selectedModels: Set<string> }>()

const dataEngine = useDataEngine()
const initialValues = useMemo(() => {
const defaults = {
...getDefaults(mergeFormSchema),
target: undefined,
sources: Array.from(location.state?.selectedModels || []).map(
(id) => ({
id,
})
),
}
return defaults
}, [location.state?.selectedModels])

const onSubmit = async (values: IndicatorMergeFormValues) => {
try {
const data = mergeFormSchema.parse(values)
await dataEngine.mutate({
resource: 'indicators/merge',
type: 'create',
data,
})
return undefined
} catch (e) {
console.error(e)
return createFormError(e)
}
}

return (
<Form
initialValues={initialValues}
onSubmit={onSubmit}
validate={validate}
subscription={{
values: false,
submitting: true,
submitSucceeded: true,
}}
>
{({ handleSubmit }) => (
<StyledMergeForm onSubmit={handleSubmit}>
<DefaultMergeFormContents
title={
<Title>{i18n.t('Configure indicator merge')}</Title>
}
mergeCompleteElement={
<MergeComplete>
<p>
{i18n.t(
'The indicator merge operation is complete.'
)}
</p>
<p>
{i18n.t(
'All selected indicators were merged successfully.'
)}
</p>
</MergeComplete>
}
>
<IndicatorMergeFormFields />
</DefaultMergeFormContents>
</StyledMergeForm>
)}
</Form>
)
}
119 changes: 119 additions & 0 deletions src/pages/indicators/merge/IndicatorMergeFormFields.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import i18n from '@dhis2/d2-i18n'
import { NoticeBox } from '@dhis2/ui'
import React from 'react'
import { useFormState } from 'react-final-form'
import { StandardFormSectionTitle } from '../../../components'
import {
BaseSourcesField,
BaseTargetField,
MergeSourcesTargetWrapper,
DeleteSourcesFields,
Description,
FormSection,
FormSections,
ConfirmationField,
} from '../../../components/merge'
import { IndicatorMergeFormValues } from './IndicatorMergeSchema'

export const IndicatorMergeFormFields = () => {
return (
<FormSections>
<FormSection>
<Description>
<p>
{i18n.t(`The merge operation will merge the source indicators into
the target indicator. One or many source indicators
can be specified`)}
</p>
<p>
{i18n.t(`Only one target should be specified. The merge operation will
transfer all of the indicator metadata associations to the
source indicator over to the target indicator.`)}
</p>
</Description>
<MergeSourcesTargetWrapper>
<BaseSourcesField
label={i18n.t('Indicators to be merged (source)')}
placeholder={i18n.t('Select indicators to merge')}
query={{
resource: 'indicators',
params: {
fields: ['id', 'displayName', 'name', 'factor'],
},
}}
/>
<BaseTargetField
label={i18n.t('Indicators to merge into (target)')}
placeholder={i18n.t('Select indicator to merge into')}
query={{
resource: 'indicators',
params: {
fields: ['id', 'displayName', 'name', 'factor'],
},
}}
/>
</MergeSourcesTargetWrapper>
</FormSection>
<FormSection>
<StandardFormSectionTitle>
{i18n.t('Merge settings')}
</StandardFormSectionTitle>

<DeleteSourcesFields
groupLabel={i18n.t(
'What should happen to the source indicators after the merge is complete?'
)}
getKeepLabel={(count) =>
i18n.t('Keep {{ count }} source indicators', {
count,
})
}
getDeleteLabel={(count) =>
i18n.t('Delete {{ count }} source indicators', {
count,
})
}
/>
</FormSection>
<FormSection>
<ConfirmationField />
</FormSection>
<MergeWarnings />
</FormSections>
)
}

const MergeWarnings = () => {
const { values } = useFormState<IndicatorMergeFormValues>({
subscription: { values: true },
})

if (values.sources?.length === 0 || !values.target) {
return null
}

const sourcesWithDifferentFactors =
values.sources?.filter((s) => s.factor !== values.target.factor) || []
if (sourcesWithDifferentFactors.length > 0) {
return (
<div style={{ maxWidth: 640 }}>
<NoticeBox warning title={i18n.t('Conflicting factors')}>
{i18n.t(
'The following source indicator types have different factors than the target indicator type with factor {{ targetFactor }}:',
{ targetFactor: values.target.factor }
)}
<ul>
{sourcesWithDifferentFactors.map((s) => (
<li key={s.id}>{s.displayName ?? s.id}</li>
))}
</ul>
{i18n.t(
'It is not recommended to merge indicator types with different factors.'
)}
</NoticeBox>
</div>
)
}

return null
}
29 changes: 29 additions & 0 deletions src/pages/indicators/merge/IndicatorMergeSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import i18n from '@dhis2/d2-i18n'
import { z } from 'zod'
import { mergeFormSchemaBase } from '../../../components/merge'
import { createFormValidate } from '../../../lib'

const indicatorSchema = z.object({
id: z.string(),
displayName: z.string(),
name: z.string(),
factor: z.number().optional(),
})

export const mergeFormSchema = mergeFormSchemaBase
.extend({
sources: z
.array(indicatorSchema)
.min(1, i18n.t('At least one source is required'))
.default([]),
target: indicatorSchema,
})
.transform((data) => ({
...data,
sources: data.sources.map((source) => source.id),
target: data.target.id,
}))

export type IndicatorMergeFormValues = z.input<typeof mergeFormSchema>

export const validate = createFormValidate(mergeFormSchema)
2 changes: 2 additions & 0 deletions src/pages/indicators/merge/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './IndicatorMergeFormFields'
export * from './IndicatorMergeSchema'

0 comments on commit a84ee60

Please # to comment.