@@ -82,6 +82,29 @@ type D2DataElementNewType = Omit<D2DataElement, "valueType"> & {
8282 valueType : D2DataElementTypes ;
8383} ;
8484
85+ function normalizeCategoryCombo ( categoryCombo : D2DataElement [ "categoryCombo" ] ) : D2DataElement [ "categoryCombo" ] {
86+ const trimCategoryOption = (
87+ co : D2DataElement [ "categoryCombo" ] [ "categories" ] [ number ] [ "categoryOptions" ] [ number ]
88+ ) => ( {
89+ ...co ,
90+ code : co . code . trim ( ) ,
91+ name : co . name . trim ( ) ,
92+ } ) ;
93+
94+ return {
95+ ...categoryCombo ,
96+ categories : categoryCombo . categories . map ( category => ( {
97+ ...category ,
98+ categoryOptions : category . categoryOptions . map ( trimCategoryOption ) ,
99+ } ) ) ,
100+ categoryOptionCombos : categoryCombo . categoryOptionCombos . map ( coc => ( {
101+ ...coc ,
102+ name : coc . name . trim ( ) ,
103+ categoryOptions : coc . categoryOptions . map ( trimCategoryOption ) ,
104+ } ) ) ,
105+ } ;
106+ }
107+
85108export function makeCocOrderArray ( namesArray : string [ ] [ ] ) : string [ ] {
86109 return namesArray . reduce ( ( prev , current ) => {
87110 return prev
@@ -96,9 +119,22 @@ export function makeCocOrderArray(namesArray: string[][]): string[] {
96119 } ) ;
97120}
98121
122+ // Builds a lookup `category-option code → sortOrder` from the parent
123+ // `Category.categoryOptions` arrays. DHIS2 returns these arrays in their
124+ // canonical sort order (set in the maintenance app), so the array index is
125+ // the sortOrder. Used to populate `CategoryOption.sortOrder` independently of
126+ // the (translated) display label.
127+ function buildSortOrderByCode ( categories : D2DataElement [ "categoryCombo" ] [ "categories" ] ) : Record < string , number > {
128+ return _ ( categories )
129+ . flatMap ( cat => cat . categoryOptions . map ( ( co , index ) => [ co . code , index ] as const ) )
130+ . fromPairs ( )
131+ . value ( ) ;
132+ }
133+
99134function getCocOrdered (
100135 categoryCombo : D2DataElement [ "categoryCombo" ] ,
101- config : Dhis2DataStoreDataForm
136+ config : Dhis2DataStoreDataForm ,
137+ sortOrderByCode : Record < string , number >
102138) : CategoryOptionCombo [ ] {
103139 const keyName = config . categoryCombinationsConfig [ categoryCombo . code ] ?. viewType || "formName" ;
104140 const allCategoryOptions = categoryCombo . categories . flatMap ( c =>
@@ -165,7 +201,11 @@ function getCocOrdered(
165201 ...x ,
166202 originalName : x . name ,
167203 name : x [ keyName ] || x . name || "" ,
168- categoryOptions : x . categoryOptions . map ( co => ( { ...co , originalName : co . name } ) ) ,
204+ categoryOptions : x . categoryOptions . map ( co => ( {
205+ ...co ,
206+ originalName : co . name ,
207+ sortOrder : sortOrderByCode [ co . code ] ?? Number . POSITIVE_INFINITY ,
208+ } ) ) ,
169209 } ) ) ;
170210}
171211
@@ -175,7 +215,8 @@ function isCategoryOptionHidden(code: string, config: Dhis2DataStoreDataForm) {
175215
176216function getVisibleCategoryOptionCombos (
177217 categoryOptionCombos : D2DataElement [ "categoryCombo" ] [ "categoryOptionCombos" ] ,
178- config : Dhis2DataStoreDataForm
218+ config : Dhis2DataStoreDataForm ,
219+ sortOrderByCode : Record < string , number >
179220) : CategoryOptionCombo [ ] {
180221 const hiddenCategoryOptions = _ ( config . categoryOptionsConfig )
181222 . pickBy ( value => value . visible === false )
@@ -191,13 +232,15 @@ function getVisibleCategoryOptionCombos(
191232 categoryOptions : item . categoryOptions . map ( co => ( {
192233 ...co ,
193234 originalName : co . name ,
235+ sortOrder : sortOrderByCode [ co . code ] ?? Number . POSITIVE_INFINITY ,
194236 } ) ) ,
195237 } ;
196238 } ) ;
197239}
198240
199241function getDataElement ( dataElement : D2DataElementNewType , config : Dhis2DataStoreDataForm ) : DataElement | null {
200242 const { valueType } = dataElement ;
243+ const categoryCombo = normalizeCategoryCombo ( dataElement . categoryCombo ) ;
201244 const deConfig = config . dataElementsConfig [ dataElement . code ] ;
202245 const optionSetFromDataElement = dataElement . optionSet
203246 ? {
@@ -210,14 +253,15 @@ function getDataElement(dataElement: D2DataElementNewType, config: Dhis2DataStor
210253 : null ;
211254 const optionSetFromCustomConfig = deConfig ?. selection ?. optionSet ;
212255 const optionSet = optionSetFromCustomConfig || optionSetFromDataElement ;
256+ const sortOrderByCode = buildSortOrderByCode ( categoryCombo . categories ) ;
213257 const categoryCombination = {
214- id : dataElement . categoryCombo ?. id ,
215- name : dataElement . categoryCombo ?. name ,
216- categories : dataElement . categoryCombo ?. categories . map ( cat => {
217- const keyName = config . categoryCombinationsConfig [ dataElement . categoryCombo . code ] ?. viewType || "formName" ;
258+ id : categoryCombo ?. id ,
259+ name : categoryCombo ?. name ,
260+ categories : categoryCombo ?. categories . map ( cat => {
261+ const keyName = config . categoryCombinationsConfig [ categoryCombo . code ] ?. viewType || "formName" ;
218262 return {
219263 ...cat ,
220- categoryOptions : cat . categoryOptions . map ( co => {
264+ categoryOptions : cat . categoryOptions . map ( ( co , index ) => {
221265 const record = {
222266 id : co . id ,
223267 name : co . displayName ,
@@ -231,13 +275,18 @@ function getDataElement(dataElement: D2DataElementNewType, config: Dhis2DataStor
231275 code : co . code ,
232276 name : record [ keyName ] ?? record . name ,
233277 displayFormName : record . formName ,
278+ sortOrder : index ,
234279 } ;
235280 } ) ,
236281 } ;
237282 } ) ,
238- categoryOptionCombos : getCocOrdered ( dataElement . categoryCombo , config ) ,
283+ categoryOptionCombos : getCocOrdered ( categoryCombo , config , sortOrderByCode ) ,
239284 } ;
240- const categoryOptionCombos = getVisibleCategoryOptionCombos ( dataElement . categoryCombo . categoryOptionCombos , config ) ;
285+ const categoryOptionCombos = getVisibleCategoryOptionCombos (
286+ categoryCombo . categoryOptionCombos ,
287+ config ,
288+ sortOrderByCode
289+ ) ;
241290
242291 const base = {
243292 id : dataElement . id ,
0 commit comments