@iapps/ng-dhis2-ui 1.2.104 → 1.2.111

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4095,10 +4095,10 @@ const getTrackedEntityTableData = (response, programId, pager, metaData, searche
4095
4095
  }))
4096
4096
  .filter((col) => searcheableDataElements.includes(col.key)));
4097
4097
  const dataElementColumns = metaData
4098
- .programStages.sort((a, b) => a.sortOrder - b.sortOrder) // Sorts stages by sortOrder
4098
+ .programStages.sort((a, b) => a.sortOrder - b.sortOrder)
4099
4099
  .flatMap((stage) => stage
4100
4100
  .programStageDataElements.filter((psde) => psde.displayInReports)
4101
- .sort((a, b) => a.sortOrder - b.sortOrder) // Sorts data elements within stage
4101
+ .sort((a, b) => a.sortOrder - b.sortOrder)
4102
4102
  .map((psde) => ({
4103
4103
  label: psde.dataElement.name || psde.dataElement.formName || 'default',
4104
4104
  key: psde.dataElement.id,
@@ -4127,94 +4127,204 @@ const getTrackedEntityTableData = (response, programId, pager, metaData, searche
4127
4127
  options: attr.optionSet ?? undefined,
4128
4128
  type: 'attribute',
4129
4129
  }));
4130
- const tableData = teis.map((tei, idx) => {
4130
+ const getOptionColor = (option) => option?.color || option?.style?.color;
4131
+ const formatDate = (value) => {
4132
+ try {
4133
+ return format(parse$1(value, 'yyyy-MM-dd', new Date()), 'dd/MM/yyyy');
4134
+ }
4135
+ catch {
4136
+ return value;
4137
+ }
4138
+ };
4139
+ const trackedEntityAttributeMap = new Map();
4140
+ (metaData.programTrackedEntityAttributes || []).forEach(({ trackedEntityAttribute }) => {
4141
+ if (trackedEntityAttribute?.id) {
4142
+ trackedEntityAttributeMap.set(trackedEntityAttribute.id, trackedEntityAttribute);
4143
+ }
4144
+ });
4145
+ const dataElementOptionMap = new Map();
4146
+ dataElementOptions.forEach((deo) => {
4147
+ if (deo.id) {
4148
+ dataElementOptionMap.set(deo.id, deo);
4149
+ }
4150
+ });
4151
+ const tableData = teis.map((tei, index) => {
4131
4152
  const row = {
4132
4153
  trackedEntityInstance: { value: tei.trackedEntity },
4133
- index: { value: (pager.page - 1) * pager.pageSize + idx + 1 },
4154
+ index: { value: (pager.page - 1) * pager.pageSize + index + 1 },
4134
4155
  };
4135
- const matchingEnrollment = tei.latestEnrollment;
4136
- let attributesData = matchingEnrollment.attributes;
4137
- const dataElementsData = matchingEnrollment.events.flatMap((event) => event.dataValues);
4138
- attributesData = attributesData.map((attr) => {
4139
- if (attr?.valueType?.toLowerCase() === 'date') {
4140
- try {
4141
- return {
4142
- ...attr,
4143
- value: format(parse$1(attr.value, 'yyyy-MM-dd', new Date()), 'dd/MM/yyyy'),
4144
- };
4145
- }
4146
- catch {
4147
- return { ...attr };
4148
- }
4156
+ const enrollment = tei.latestEnrollment;
4157
+ if (!enrollment)
4158
+ return row;
4159
+ const attributes = (enrollment.attributes || []).map((attr) => {
4160
+ if (attr?.valueType?.toLowerCase() === 'date' &&
4161
+ typeof attr.value === 'string') {
4162
+ return { ...attr, value: formatDate(attr.value) };
4149
4163
  }
4150
4164
  return attr;
4151
4165
  });
4152
- // attributesData.forEach((attr: any) => {
4153
- // const attributeMeta = metaData.programTrackedEntityAttributes?.find(
4154
- // (metadata) => metadata.trackedEntityAttribute.id === attr.attribute
4155
- // );
4156
- // if (attributeMeta?.trackedEntityAttribute.optionSetValue) {
4157
- // const optionSet = attributeMeta?.trackedEntityAttribute?.optionSet;
4158
- // const option = optionSet?.options?.find(
4159
- // (option) => option.code === attr.value
4160
- // );
4161
- // row[attr.attribute] = option
4162
- // ? { value: option?.name }
4163
- // : { value: attr.value };
4164
- // } else {
4165
- // row[attr.attribute] = { value: attr.value };
4166
- // }
4167
- // });
4168
- attributesData.forEach((attr) => {
4169
- const attributeMeta = metaData.programTrackedEntityAttributes?.find((metadata) => metadata.trackedEntityAttribute.id === attr.attribute);
4170
- const valueType = attributeMeta?.trackedEntityAttribute?.valueType;
4166
+ attributes.forEach((attr) => {
4167
+ const attributeId = attr?.attribute;
4168
+ const value = attr?.value;
4169
+ if (!attributeId || value == null)
4170
+ return;
4171
+ const attributeMeta = trackedEntityAttributeMap.get(attributeId);
4172
+ const valueType = attributeMeta?.valueType;
4171
4173
  if (valueType === 'ORGANISATION_UNIT') {
4172
- const orgUnitName = orgUnitMap?.get(attr.value);
4173
- row[attr.attribute] = { value: orgUnitName || attr.value };
4174
- }
4175
- else if (attributeMeta?.trackedEntityAttribute.optionSetValue) {
4176
- const optionSet = attributeMeta?.trackedEntityAttribute?.optionSet;
4177
- const option = optionSet?.options?.find((option) => option.code === attr.value);
4178
- row[attr.attribute] = option
4179
- ? { value: option?.name }
4180
- : { value: attr.value };
4181
- }
4182
- else {
4183
- row[attr.attribute] = { value: attr.value };
4174
+ const name = orgUnitMap?.get(value);
4175
+ row[attributeId] = { value: name || value };
4184
4176
  }
4185
- });
4186
- dataElementsData.forEach((element) => {
4187
- // Finds the matching data element in dataElementOptions by ID
4188
- const dataElementOption = dataElementOptions.find((deo) => deo.id === element.dataElement);
4189
- // finds a matching option within that data element's options
4190
- const matchingOption = dataElementOption?.options?.find((opt) => opt.name === element.value);
4191
- // Builds the row entry with value and optional style
4192
- if (matchingOption) {
4193
- row[element.dataElement] = {
4194
- value: element.value,
4195
- style: matchingOption.color,
4177
+ else if (attributeMeta?.optionSetValue &&
4178
+ attributeMeta?.optionSet?.options) {
4179
+ const matchedOption = attributeMeta.optionSet.options.find((opt) => opt.code === value);
4180
+ row[attributeId] = {
4181
+ value: matchedOption?.name || value,
4182
+ ...(getOptionColor(matchedOption) && {
4183
+ style: getOptionColor(matchedOption),
4184
+ }),
4196
4185
  };
4197
4186
  }
4198
4187
  else {
4199
- row[element.dataElement] = {
4200
- value: element.value,
4201
- };
4188
+ row[attributeId] = { value };
4202
4189
  }
4203
4190
  });
4204
- // Includes orgUnit in the row for id access with style
4205
- row['orgUnitId'] = { value: matchingEnrollment.orgUnit };
4206
- row['orgUnit'] = {
4207
- value: orgUnitMap?.get(matchingEnrollment.orgUnit) || '-',
4191
+ const dataValues = enrollment.events?.flatMap((event) => event.dataValues || []) || [];
4192
+ dataValues.forEach((dataValue) => {
4193
+ const dataElementId = dataValue.dataElement;
4194
+ const value = dataValue.value;
4195
+ if (!dataElementId || value == null)
4196
+ return;
4197
+ const dataElementOption = dataElementOptionMap.get(dataElementId);
4198
+ const matchedOption = dataElementOption?.options?.find((opt) => opt.name === value);
4199
+ row[dataElementId] = {
4200
+ value,
4201
+ ...(getOptionColor(matchedOption) && {
4202
+ style: getOptionColor(matchedOption),
4203
+ }),
4204
+ };
4205
+ });
4206
+ const orgUnitId = enrollment.orgUnit;
4207
+ const orgUnitName = orgUnitMap?.get(orgUnitId) || '-';
4208
+ row['orgUnitId'] = { value: orgUnitId || '-' };
4209
+ row['orgUnit'] = { value: orgUnitName };
4210
+ const teiObject = typeof tei.toObject === 'function' ? tei.toObject() : null;
4211
+ row['responseData'] = {
4212
+ value: teiObject || null,
4208
4213
  };
4209
- row['responseData'] = { value: tei.toObject() };
4210
4214
  return row;
4211
4215
  });
4212
4216
  return {
4213
4217
  columns: tableColumns,
4214
4218
  data: tableData,
4215
4219
  filteredEntityColumns: [...tableFilters, ...tableSearcheableDataElements],
4216
- orgUnitLabel: orgUnitLabel,
4220
+ orgUnitLabel,
4217
4221
  };
4222
+ // const tableData = teis.map((tei: TrackedEntityInstance, idx: number) => {
4223
+ // const row: TableRow = {
4224
+ // trackedEntityInstance: { value: tei.trackedEntity },
4225
+ // index: { value: (pager.page - 1) * pager.pageSize + idx + 1 },
4226
+ // };
4227
+ // const matchingEnrollment = tei.latestEnrollment;
4228
+ // let attributesData = matchingEnrollment.attributes;
4229
+ // const dataElementsData = matchingEnrollment!.events.flatMap(
4230
+ // (event) => event.dataValues
4231
+ // );
4232
+ // attributesData = attributesData!.map((attr: any) => {
4233
+ // if (attr?.valueType?.toLowerCase() === 'date') {
4234
+ // try {
4235
+ // return {
4236
+ // ...attr,
4237
+ // value: format(
4238
+ // parse(attr.value, 'yyyy-MM-dd', new Date()),
4239
+ // 'dd/MM/yyyy'
4240
+ // ),
4241
+ // };
4242
+ // } catch {
4243
+ // return { ...attr };
4244
+ // }
4245
+ // }
4246
+ // return attr;
4247
+ // });
4248
+ // // Tracked Entity Instance Attributes
4249
+ // const trackedEntityAttributeMap = new Map<string, any>();
4250
+ // (metaData.programTrackedEntityAttributes || []).forEach(
4251
+ // (programAttribute) => {
4252
+ // const attributeId = programAttribute.trackedEntityAttribute?.id;
4253
+ // if (attributeId) {
4254
+ // trackedEntityAttributeMap.set(
4255
+ // attributeId,
4256
+ // programAttribute.trackedEntityAttribute
4257
+ // );
4258
+ // }
4259
+ // }
4260
+ // );
4261
+ // attributesData.forEach((attributeItem: any) => {
4262
+ // const attributeId = attributeItem?.attribute;
4263
+ // const attributeValue = attributeItem?.value;
4264
+ // if (!attributeId || attributeValue == null) return;
4265
+ // const trackedEntityAttribute = trackedEntityAttributeMap.get(attributeId);
4266
+ // const valueType = trackedEntityAttribute?.valueType;
4267
+ // if (valueType === 'ORGANISATION_UNIT') {
4268
+ // const organisationUnitName = orgUnitMap?.get(attributeValue);
4269
+ // row[attributeId] = {
4270
+ // value: organisationUnitName || attributeValue,
4271
+ // };
4272
+ // } else if (
4273
+ // trackedEntityAttribute?.optionSetValue &&
4274
+ // trackedEntityAttribute?.optionSet?.options
4275
+ // ) {
4276
+ // const matchedOption = trackedEntityAttribute.optionSet.options.find(
4277
+ // (option: any) => option.code === attributeValue
4278
+ // );
4279
+ // const optionColor = matchedOption?.color || matchedOption?.style?.color;
4280
+ // row[attributeId] = {
4281
+ // value: matchedOption?.name || attributeValue,
4282
+ // ...(optionColor && { style: optionColor }),
4283
+ // };
4284
+ // } else {
4285
+ // row[attributeId] = {
4286
+ // value: attributeValue,
4287
+ // };
4288
+ // }
4289
+ // });
4290
+ // // Program Stage Data Elements
4291
+ // const dataElementOptionMap = new Map(
4292
+ // dataElementOptions.map((deo) => [deo.id, deo])
4293
+ // );
4294
+ // dataElementsData.forEach((element: DataValue) => {
4295
+ // if (!element?.dataElement || element.value == null) return;
4296
+ // const dataElementOption = dataElementOptionMap.get(element.dataElement);
4297
+ // const matchingOption: any = dataElementOption?.options?.find(
4298
+ // (opt) => opt.name === element.value
4299
+ // );
4300
+ // const optionColor = matchingOption?.color || matchingOption?.style?.color;
4301
+ // row[element.dataElement] = {
4302
+ // value: element.value,
4303
+ // ...(optionColor && { style: optionColor }),
4304
+ // };
4305
+ // });
4306
+ // const orgUnitId = matchingEnrollment?.orgUnit;
4307
+ // if (orgUnitId) {
4308
+ // row['orgUnitId'] = { value: orgUnitId };
4309
+ // const orgUnitName = orgUnitMap?.get(orgUnitId) || '-';
4310
+ // row['orgUnit'] = { value: orgUnitName };
4311
+ // } else {
4312
+ // row['orgUnitId'] = { value: '-' };
4313
+ // row['orgUnit'] = { value: '-' };
4314
+ // }
4315
+ // const teiObject =
4316
+ // typeof tei?.toObject === 'function' ? tei.toObject() : null;
4317
+ // row['responseData'] = {
4318
+ // value: (teiObject as TrackedEntityInstance) || null,
4319
+ // };
4320
+ // return row;
4321
+ // });
4322
+ // return {
4323
+ // columns: tableColumns,
4324
+ // data: tableData,
4325
+ // filteredEntityColumns: [...tableFilters, ...tableSearcheableDataElements],
4326
+ // orgUnitLabel: orgUnitLabel,
4327
+ // };
4218
4328
  };
4219
4329
  const addActionsColumn = (columns, actionOptions) => {
4220
4330
  return [
@@ -6224,6 +6334,17 @@ class FormValue {
6224
6334
  }
6225
6335
  }
6226
6336
 
6337
+ var OrgUnitLevel;
6338
+ (function (OrgUnitLevel) {
6339
+ OrgUnitLevel["FACILITY"] = "FACILITY";
6340
+ OrgUnitLevel["HAMLET"] = "HAMLET";
6341
+ OrgUnitLevel["STREET"] = "STREET";
6342
+ OrgUnitLevel["WARD"] = "WARD";
6343
+ OrgUnitLevel["COUNCIL"] = "COUNCIL";
6344
+ OrgUnitLevel["REGION"] = "REGION";
6345
+ OrgUnitLevel["NATIONAL"] = "NATIONAL";
6346
+ })(OrgUnitLevel || (OrgUnitLevel = {}));
6347
+
6227
6348
  // Copyright 2025 UDSM DHIS2 Lab. All rights reserved.
6228
6349
  // Use of this source code is governed by a BSD-style
6229
6350
  // license that can be found in the LICENSE file.
@@ -6331,6 +6452,58 @@ const orgUnitFieldStyles = {
6331
6452
  paddingInlineStart: '4px',
6332
6453
  },
6333
6454
  };
6455
+ const FACILITY_KEYWORDS = [
6456
+ 'Hospital',
6457
+ 'Dispensary',
6458
+ 'Health Center',
6459
+ 'Clinic',
6460
+ 'Health Post',
6461
+ 'Medical Center',
6462
+ 'Polyclinic',
6463
+ ];
6464
+ const LOWERCASE_FACILITY_KEYWORDS = FACILITY_KEYWORDS.map((k) => k.toLowerCase());
6465
+ const getFacilityMatch = (name, config) => {
6466
+ if (!name)
6467
+ return null;
6468
+ const cleanedName = name.trim().toLowerCase();
6469
+ if (cleanedName.length < 3)
6470
+ return null;
6471
+ const matchesKeyword = LOWERCASE_FACILITY_KEYWORDS.some((keyword) => cleanedName.includes(keyword));
6472
+ if (!matchesKeyword) {
6473
+ return null;
6474
+ }
6475
+ return {
6476
+ type: config?.level ?? 'UNKNOWN',
6477
+ confidence: config?.confidence ?? 0,
6478
+ };
6479
+ };
6480
+ const flattenChildren = (rootUnits) => {
6481
+ const result = [];
6482
+ const stack = [...rootUnits];
6483
+ while (stack.length > 0) {
6484
+ const current = stack.pop();
6485
+ if (!current)
6486
+ continue;
6487
+ result.push(current);
6488
+ if (Array.isArray(current.children) && current.children.length > 0) {
6489
+ stack.push(...current.children);
6490
+ }
6491
+ }
6492
+ return result;
6493
+ };
6494
+ const buildReadableFullName = (unit) => {
6495
+ const ancestors = (unit.ancestors || [])
6496
+ .map((a) => a.displayName?.trim())
6497
+ .filter(Boolean);
6498
+ const currentName = (unit.displayName || unit.name || '').trim();
6499
+ const pathParts = [];
6500
+ for (const name of [...ancestors, currentName]) {
6501
+ if (name && name !== pathParts[pathParts.length - 1]) {
6502
+ pathParts.push(name);
6503
+ }
6504
+ }
6505
+ return pathParts.join(' / ');
6506
+ };
6334
6507
  const OrgUnitFormField = (props) => {
6335
6508
  // const { onSelectOrgUnit, label, required, selected, disabled, key, customOrgUnitRoots } = props;
6336
6509
  // const d2 = (window as unknown as D2Window)?.d2Web;
@@ -6398,24 +6571,45 @@ const OrgUnitFormField = (props) => {
6398
6571
  if (matchList.length > 0) {
6399
6572
  setUseCustomRoots(true);
6400
6573
  setConfiguredRootsLoading(true);
6401
- Promise.all(matchList.map((entry) => d2.httpInstance
6402
- .get(`organisationUnits/${entry.orgUnit}.json?fields=id,displayName,name,code,path,level`)
6403
- .then((res) => {
6404
- const orgUnitPayload = res.data;
6405
- return {
6406
- id: orgUnitPayload?.id,
6407
- name: orgUnitPayload?.displayName || orgUnitPayload?.name,
6408
- code: orgUnitPayload?.code,
6409
- path: orgUnitPayload?.path,
6410
- level: orgUnitPayload.level,
6411
- };
6412
- })))
6413
- .then((result) => {
6414
- setConfiguredRootInfo(result);
6574
+ Promise.allSettled(matchList.map(async (orgUnitConfig) => {
6575
+ try {
6576
+ const orgUnitResponse = await d2.httpInstance.get(`organisationUnits/${orgUnitConfig.orgUnit}.json?fields=id,displayName,name,code,path,level,ancestors[displayName],children[id,displayName,name,code,path,level,ancestors[displayName],children[id,displayName,name,code,path,level,ancestors[displayName]]]&paging=false`);
6577
+ const rootOrgUnitData = orgUnitResponse.data;
6578
+ const allDescendantOrgUnits = flattenChildren([rootOrgUnitData]);
6579
+ const matchingConfig = customOrgUnitRoots?.find((config) => config.orgUnit === orgUnitConfig.orgUnit);
6580
+ const facilityResults = allDescendantOrgUnits
6581
+ .map((orgUnit) => {
6582
+ const orgUnitName = orgUnit.displayName || orgUnit.name || '';
6583
+ const facilityMatch = getFacilityMatch(orgUnitName, matchingConfig);
6584
+ if (!facilityMatch)
6585
+ return null;
6586
+ return {
6587
+ id: orgUnit.id,
6588
+ name: buildReadableFullName(orgUnit),
6589
+ code: orgUnit.code,
6590
+ path: orgUnit.path,
6591
+ level: orgUnit.level,
6592
+ type: facilityMatch.type,
6593
+ confidence: facilityMatch.confidence,
6594
+ };
6595
+ })
6596
+ .filter((facility) => facility !== null);
6597
+ return facilityResults;
6598
+ }
6599
+ catch (fetchError) {
6600
+ console.warn(`[OrgUnitFormField] Failed to fetch orgUnit ${orgUnitConfig.orgUnit}:`, fetchError);
6601
+ return [];
6602
+ }
6603
+ }))
6604
+ .then((settledResults) => {
6605
+ const allFacilities = settledResults
6606
+ .filter((result) => result.status === 'fulfilled')
6607
+ .flatMap((result) => result.value);
6608
+ setConfiguredRootInfo(allFacilities);
6415
6609
  setConfiguredRootsLoading(false);
6416
6610
  })
6417
- .catch((err) => {
6418
- console.warn(`[OrgUnitFormField] Failed to fetch customOrgUnitRoots:`, err);
6611
+ .catch((unexpectedError) => {
6612
+ console.warn(`[OrgUnitFormField] Unexpected error:`, unexpectedError);
6419
6613
  setConfiguredRootsLoading(false);
6420
6614
  });
6421
6615
  }
@@ -8659,5 +8853,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImpor
8659
8853
  * Generated bundle index. Do not edit.
8660
8854
  */
8661
8855
 
8662
- export { Boolean$1 as Boolean, BreadcrumbComponent, BreadcrumbModule, ButtonComponent, ButtonModule, CheckBox, D2FormModule, DataTableUIComponent, DataTableUIModule, DateField, DateRangeValue, Dropdown, EventFormComponent, EventFormModule, FieldConfig, FieldControlTypeUtil, FieldDropdown, FieldType, FieldUtil, FlatFormComponent, FormComponent, FormConfig, FormField, FormFieldComponent, FormFieldGroup, FormFieldTypeUtil, FormMetaData, FormMetadataSection, FormUtil, FormValue, FormValueUtil, HeaderBarComponent, HeaderBarModule, LineListModule, LineListTableComponent, MetadataRule, MetadataRuleAction, OrganisationUnitSelectionConfig, OrganisationUnitSelectorComponent, OrganisationUnitSelectorModalComponent, OrganisationUnitSelectorModule, PeriodSelectorComponent, PeriodSelectorModalComponent, PeriodSelectorModule, ProgramEntryFormConfig, ProgramEntryFormMetaData, ProgramEntryFormModule, ProgramEntryFormSection, ReactWrapperModule, RepeatableFormComponent, SectionFormComponent, SelectionFiltersComponent, SelectionFiltersUiModule, TrackerFormComponent, TrackerFormModule, TranslationUtil };
8856
+ export { Boolean$1 as Boolean, BreadcrumbComponent, BreadcrumbModule, ButtonComponent, ButtonModule, CheckBox, D2FormModule, DataTableUIComponent, DataTableUIModule, DateField, DateRangeValue, Dropdown, EventFormComponent, EventFormModule, FieldConfig, FieldControlTypeUtil, FieldDropdown, FieldType, FieldUtil, FlatFormComponent, FormComponent, FormConfig, FormField, FormFieldComponent, FormFieldGroup, FormFieldTypeUtil, FormMetaData, FormMetadataSection, FormUtil, FormValue, FormValueUtil, HeaderBarComponent, HeaderBarModule, LineListModule, LineListTableComponent, MetadataRule, MetadataRuleAction, OrgUnitLevel, OrganisationUnitSelectionConfig, OrganisationUnitSelectorComponent, OrganisationUnitSelectorModalComponent, OrganisationUnitSelectorModule, PeriodSelectorComponent, PeriodSelectorModalComponent, PeriodSelectorModule, ProgramEntryFormConfig, ProgramEntryFormMetaData, ProgramEntryFormModule, ProgramEntryFormSection, ReactWrapperModule, RepeatableFormComponent, SectionFormComponent, SelectionFiltersComponent, SelectionFiltersUiModule, TrackerFormComponent, TrackerFormModule, TranslationUtil };
8663
8857
  //# sourceMappingURL=iapps-ng-dhis2-ui.mjs.map