From e63b5b8c60865fbab2f93988bbcb73aa8c7829a5 Mon Sep 17 00:00:00 2001 From: Flaminia Cavallo Date: Mon, 28 Oct 2024 15:50:26 +0100 Subject: [PATCH] feat: add org unit edit form --- i18n/en.pot | 77 +++++++++-------- src/pages/organisationUnits/Edit.tsx | 84 +++++++++++++++++++ src/pages/organisationUnits/New.tsx | 16 +--- .../organisationUnits/form/GeometryFields.tsx | 75 +++++++++++++++++ .../form/OrganisationUnitFormFields.tsx | 22 +---- .../form/OrganisationUnitSelector.tsx | 11 ++- 6 files changed, 214 insertions(+), 71 deletions(-) create mode 100644 src/pages/organisationUnits/Edit.tsx create mode 100644 src/pages/organisationUnits/form/GeometryFields.tsx diff --git a/i18n/en.pot b/i18n/en.pot index 9866e147..b151bf35 100644 --- a/i18n/en.pot +++ b/i18n/en.pot @@ -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: 2024-10-23T11:07:53.225Z\n" -"PO-Revision-Date: 2024-10-23T11:07:53.225Z\n" +"POT-Creation-Date: 2024-10-28T13:53:29.437Z\n" +"PO-Revision-Date: 2024-10-28T13:53:29.437Z\n" msgid "schemas" msgstr "schemas" @@ -123,21 +123,6 @@ msgstr "Failed to load {{label}}" msgid "Failed to load" msgstr "Failed to load" -msgid "Download" -msgstr "Download" - -msgid "Merge" -msgstr "Merge" - -msgid "Delete source data element values" -msgstr "Delete source data element values" - -msgid "Last updated" -msgstr "Last updated" - -msgid "Discard" -msgstr "Discard" - msgid "Aggregation level(s)" msgstr "Aggregation level(s)" @@ -237,6 +222,9 @@ msgstr "Created" msgid "Last updated by" msgstr "Last updated by" +msgid "Last updated" +msgstr "Last updated" + msgid "Id" msgstr "Id" @@ -258,6 +246,9 @@ msgstr "Details" msgid "Failed to load details" msgstr "Failed to load details" +msgid "Download" +msgstr "Download" + msgid "Download {{section}}" msgstr "Download {{section}}" @@ -858,6 +849,9 @@ msgstr "Data dimension type" msgid "This field requires a unique value, please choose another one" msgstr "This field requires a unique value, please choose another one" +msgid "{{label}} (required)" +msgstr "{{label}} (required)" + msgid "No changes to be saved" msgstr "No changes to be saved" @@ -879,23 +873,27 @@ msgstr "Basic information" msgid "Set up the basic information for this category." msgstr "Set up the basic information for this category." -msgid "Explain the purpose of this category." -msgstr "Explain the purpose of this category." +msgid "Explain the purpose of this category option group." +msgstr "Explain the purpose of this category option group." msgid "Data configuration" msgstr "Data configuration" -msgid "Choose how this category will be used to capture and analyze" -msgstr "Choose how this category will be used to capture and analyze" +msgid "Choose how this category option group will be used to capture and analyze" +msgstr "Choose how this category option group will be used to capture and analyze" msgid "Use as data dimension" msgstr "Use as data dimension" -msgid "Category will be available to the analytics as another dimension" -msgstr "Category will be available to the analytics as another dimension" +msgid "" +"Category option group will be available to the analytics as another " +"dimension" +msgstr "" +"Category option group will be available to the analytics as another " +"dimension" -msgid "Choose the category options to include in this category." -msgstr "Choose the category options to include in this category." +msgid "Choose the category options to include in this category option group." +msgstr "Choose the category options to include in this category option group." msgid "Available category options" msgstr "Available category options" @@ -933,6 +931,15 @@ msgstr "Filter selected categories" msgid "At least one category is required" msgstr "At least one category is required" +msgid "Set up the basic information for this category option group." +msgstr "Set up the basic information for this category option group." + +msgid "Choose how this category option will be used to capture and analyze" +msgstr "Choose how this category option will be used to capture and analyze" + +msgid "Choose the category options to include in this category." +msgstr "Choose the category options to include in this category." + msgid "Set up the basic information for this category option." msgstr "Set up the basic information for this category option." @@ -1081,6 +1088,12 @@ msgstr "" "included. PHU will still be available for the PHU level, but not included " "in the aggregations to the levels above." +msgid "Longitude" +msgstr "Longitude" + +msgid "{{type}} coordinates are not editable" +msgstr "{{type}} coordinates are not editable" + msgid "Upload an image" msgstr "Upload an image" @@ -1130,17 +1143,11 @@ msgstr "Location" msgid "Set up the organisation unit location." msgstr "Set up the organisation unit location." -msgid "Latitude" -msgstr "Latitude" - -msgid "Longitude" -msgstr "Longitude" - -msgid "Reference assignments" -msgstr "Reference assignments" +msgid "Reference assignment" +msgstr "Reference assignment" -msgid "Assign the organisation unit to related models." -msgstr "Assign the organisation unit to related models." +msgid "Assign the organisation unit to related objects." +msgstr "Assign the organisation unit to related objects." msgid "Available data sets" msgstr "Available data sets" diff --git a/src/pages/organisationUnits/Edit.tsx b/src/pages/organisationUnits/Edit.tsx new file mode 100644 index 00000000..e2dd61b8 --- /dev/null +++ b/src/pages/organisationUnits/Edit.tsx @@ -0,0 +1,84 @@ +import React from 'react' +import { useQuery } from 'react-query' +import { useParams } from 'react-router-dom' +import { DefaultEditFormContents, FormBase } from '../../components' +import { + ATTRIBUTE_VALUES_FIELD_FILTERS, + DEFAULT_FIELD_FILTERS, + SECTIONS_MAP, + useOnSubmitEdit, + validate, +} from '../../lib' +import { useBoundResourceQueryFn } from '../../lib/query/useBoundQueryFn' +import { OrganisationUnit, PickWithFieldFilters } from '../../types/generated' +import { + FormValues, + OrganisationUnitFormField, + organisationUnitSchema, +} from './form' + +const fieldFilters = [ + ...DEFAULT_FIELD_FILTERS, + ...ATTRIBUTE_VALUES_FIELD_FILTERS, + 'name', + 'code', + 'shortName', + 'openingDate', + 'closedDate', + 'comment', + 'image', + 'description', + 'contactPerson', + 'address', + 'email', + 'phoneNumber', + 'url', + 'geometry', + 'dataSets', + 'programs', + 'level', + 'path', + 'parent[id,path, displayName]', +] as const + +export type OrgUnitFormValues = PickWithFieldFilters< + OrganisationUnit, + typeof fieldFilters +> + +const section = SECTIONS_MAP.organisationUnit + +export const Component = () => { + const queryFn = useBoundResourceQueryFn() + const modelId = useParams().id as string + + const query = { + resource: 'organisationUnits', + id: modelId, + params: { + fields: fieldFilters.concat(), + }, + } + const orgUnit = useQuery({ + queryKey: [query], + queryFn: queryFn, + }) + + return ( + { + return validate(organisationUnitSchema, values) + }} + > + + + + + ) +} diff --git a/src/pages/organisationUnits/New.tsx b/src/pages/organisationUnits/New.tsx index d50a541a..94b5216d 100644 --- a/src/pages/organisationUnits/New.tsx +++ b/src/pages/organisationUnits/New.tsx @@ -9,21 +9,11 @@ import { organisationUnitSchema, } from './form' -const formatFormValues: (values: FormValues) => Record = ( - values -) => { +export const formatFormValues: ( + values: FormValues +) => Record = (values) => { return { ...values, - geometry: - values.geometry?.longitude && values.geometry?.latitude - ? { - type: 'Point', - coordinates: [ - values.geometry?.longitude, - values.geometry?.latitude, - ], - } - : undefined, attributeValues: values.attributeValues.filter(({ value }) => !!value), } } diff --git a/src/pages/organisationUnits/form/GeometryFields.tsx b/src/pages/organisationUnits/form/GeometryFields.tsx new file mode 100644 index 00000000..143d5626 --- /dev/null +++ b/src/pages/organisationUnits/form/GeometryFields.tsx @@ -0,0 +1,75 @@ +import i18n from '@dhis2/d2-i18n' +import { Field, InputField } from '@dhis2/ui' +import React from 'react' +import { useField } from 'react-final-form' + +export function GeometryFields() { + const fieldName = 'geometry' + const { input, meta } = useField(fieldName) + + const handleChange = ({ + longitude, + latitude, + }: { + longitude?: string + latitude?: string + }) => { + const geometry = { + type: 'Point', + coordinates: [longitude || undefined, latitude || undefined], + } + + input.onChange(geometry) + } + + return !input.value || input.value?.type === 'Point' ? ( + <> + + + handleChange({ + longitude: e.value, + latitude: input.value.coordinates?.[1], + }) + } + label={i18n.t('Longitude')} + inputWidth="400px" + name="longitude" + type="number" + value={input.value.coordinates?.[0].toString()} + min="-90" + max="90" + step="any" + /> + + handleChange({ + longitude: input.value.coordinates?.[0], + latitude: e.value, + }) + } + inputWidth="400px" + label={i18n.t('Longitude')} + name="latitude" + type="number" + value={input.value.coordinates?.[1].toString()} + min="-180" + max="180" + step="any" + /> + + + ) : ( + + ) +} diff --git a/src/pages/organisationUnits/form/OrganisationUnitFormFields.tsx b/src/pages/organisationUnits/form/OrganisationUnitFormFields.tsx index 8a660411..097ff914 100644 --- a/src/pages/organisationUnits/form/OrganisationUnitFormFields.tsx +++ b/src/pages/organisationUnits/form/OrganisationUnitFormFields.tsx @@ -18,6 +18,7 @@ import { DateField } from '../../../components/form/fields/DateField' import { SCHEMA_SECTIONS, useSystemSetting } from '../../../lib' import { ImageField } from './ImageField' import { OrganisationUnitSelector } from './OrganisationUnitSelector' +import { GeometryFields } from './GeometryFields' const schemaSection = SCHEMA_SECTIONS.organisationUnit @@ -126,26 +127,7 @@ export function OrganisationUnitFormField() { {i18n.t('Set up the organisation unit location.')} - - - component={InputFieldFF} - inputWidth="400px" - label={i18n.t('Latitude')} - name="geometry.latitude" - type="number" - min="-90" - max="90" - /> - - - component={InputFieldFF} - inputWidth="400px" - label={i18n.t('Longitude')} - name="geometry.longitude" - type="number" - min="-180" - max="180" - /> + {allowReferenceAssignments && ( diff --git a/src/pages/organisationUnits/form/OrganisationUnitSelector.tsx b/src/pages/organisationUnits/form/OrganisationUnitSelector.tsx index 16ba244a..4d84e746 100644 --- a/src/pages/organisationUnits/form/OrganisationUnitSelector.tsx +++ b/src/pages/organisationUnits/form/OrganisationUnitSelector.tsx @@ -1,7 +1,7 @@ import i18n from '@dhis2/d2-i18n' import { Field, NoticeBox, OrganisationUnitTree } from '@dhis2/ui' import { IconInfo16 } from '@dhis2/ui-icons' -import React, { useState } from 'react' +import React, { useEffect, useState } from 'react' import { useField } from 'react-final-form' import { useCurrentUserRootOrgUnits } from '../../../lib/user/currentUserStore' import classes from './OrganisationUnitSelector.module.css' @@ -11,7 +11,9 @@ export function OrganisationUnitSelector() { const { input, meta } = useField(fieldName, { format: (value) => value }) const userRootOrgUnits = useCurrentUserRootOrgUnits() const userRootOrgUnitsIds = userRootOrgUnits.map((unit) => `/${unit.id}`) - const [selected, setSelected] = useState<[string] | []>([]) + const [selected, setSelected] = useState<[string] | []>( + input.value?.path ? [input.value.path] : [] + ) const handleChange = (orgUnit: { displayName: string @@ -40,7 +42,10 @@ export function OrganisationUnitSelector() { singleSelection roots={userRootOrgUnitsIds} selected={selected} - initiallyExpanded={userRootOrgUnitsIds} + initiallyExpanded={[ + ...userRootOrgUnitsIds, + ...selected, + ]} /> {input.value?.displayName && (