@iapps/ng-dhis2-ui 1.1.80 → 1.2.0

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.
@@ -8,7 +8,7 @@ import { NgxDhis2HttpClientService } from '@iapps/ngx-dhis2-http-client';
8
8
  import * as React from 'react';
9
9
  import React__default, { useState, useCallback, useRef, useEffect, createContext, useContext, useMemo } from 'react';
10
10
  import * as ReactDOM from 'react-dom/client';
11
- import { catchError, of, map, zip, firstValueFrom, take, filter, Subject, takeUntil } from 'rxjs';
11
+ import { catchError, of, map, zip, firstValueFrom, filter, take, Subject, takeUntil } from 'rxjs';
12
12
  import i18n from '@dhis2/d2-i18n';
13
13
  import { colors, theme, spacers } from '@dhis2/ui-constants';
14
14
  import PropTypes from 'prop-types';
@@ -25,16 +25,16 @@ import { Layer } from '@dhis2-ui/layer';
25
25
  import { CircularLoader } from '@dhis2-ui/loader';
26
26
  import { MenuItem, MenuDivider } from '@dhis2-ui/menu';
27
27
  import parse from 'html-react-parser';
28
- import { Button as Button$1, IconDimensionData16, IconClock16, IconDimensionOrgUnit16, spacers as spacers$1, colors as colors$1, IconEdit16, theme as theme$1, Tooltip, IconChevronRight16, SingleSelectField, SingleSelectOption, InputField as InputField$1, TabBar, Tab, Transfer, Modal as Modal$1, ModalTitle as ModalTitle$1, ModalContent as ModalContent$1, ModalActions as ModalActions$1, ButtonStrip as ButtonStrip$1, Checkbox, OrganisationUnitTree, MultiSelect, MultiSelectOption, IconWarningFilled16, Layer as Layer$1, Popper, FlyoutMenu, MenuItem as MenuItem$1, IconMore24, CircularLoader as CircularLoader$1, Chip, DataTableToolbar, CalendarInput, DataTable, TableHead, DataTableRow, DataTableColumnHeader, TableBody, DataTableCell, TableFoot, Pagination, FileInputField, FileListItem, MultiSelectField, TextAreaField } from '@dhis2/ui';
28
+ import { Button as Button$1, IconDimensionData16, IconClock16, IconDimensionOrgUnit16, spacers as spacers$1, colors as colors$1, IconEdit16, theme as theme$1, Tooltip, IconChevronRight16, SingleSelectField, SingleSelectOption, InputField as InputField$1, TabBar, Tab, Transfer, Modal as Modal$1, ModalTitle as ModalTitle$1, ModalContent as ModalContent$1, ModalActions as ModalActions$1, ButtonStrip as ButtonStrip$1, Checkbox, OrganisationUnitTree, MultiSelect, MultiSelectOption, IconWarningFilled16, DataTableToolbar, CalendarInput, TableHead, DataTableRow, DataTableColumnHeader, Layer as Layer$1, Popper, FlyoutMenu, MenuItem as MenuItem$1, IconMore24, DataTableCell, TableBody as TableBody$1, Pagination as Pagination$1, TableFoot, DataTable, CircularLoader as CircularLoader$1, Chip, FileInputField, FileListItem, MultiSelectField, TextAreaField } from '@dhis2/ui';
29
29
  import { isObject, isString, debounce, sortBy, isArray, find, camelCase, flatten, isUndefined, head, isEmpty } from 'lodash';
30
30
  import cx from 'classnames';
31
31
  import { getNowInCalendar, generateFixedPeriods } from '@dhis2/multi-calendar-dates';
32
- import { switchMap, map as map$1 } from 'rxjs/operators';
33
- import { parse as parse$1, format } from 'date-fns';
32
+ import { map as map$1 } from 'rxjs/operators';
33
+ import { format, parse as parse$1 } from 'date-fns';
34
+ import { Pager, DataOrderCriteria, DataQueryFilter, DataFilterCondition, ProgramRuleEngine } from '@iapps/d2-web-sdk';
34
35
  import * as i2 from '@angular/forms';
35
36
  import { Validators, UntypedFormControl, UntypedFormGroup, FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
36
37
  import { toObservable } from '@angular/core/rxjs-interop';
37
- import { DataQueryFilter, DataFilterCondition, ProgramRuleEngine } from '@iapps/d2-web-sdk';
38
38
  import moment from 'moment';
39
39
 
40
40
  class SharedDhis2UiModule {
@@ -3106,6 +3106,196 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImpor
3106
3106
  // Use of this source code is governed by a BSD-style
3107
3107
  // license that can be found in the LICENSE file.
3108
3108
 
3109
+ class LineListService {
3110
+ constructor(httpClient) {
3111
+ this.httpClient = httpClient;
3112
+ }
3113
+ /**
3114
+ * Fetch orgUnit names for given orgUnit IDs
3115
+ */
3116
+ fetchOrgUnits(orgUnitIds) {
3117
+ const idsQuery = `filter=id:in:[${orgUnitIds}]`;
3118
+ return this.httpClient
3119
+ .get(`organisationUnits.json?fields=id,name&paging=false&${idsQuery}`)
3120
+ .pipe(map$1((response) => {
3121
+ const orgUnitsMap = new Map();
3122
+ response.organisationUnits.forEach((orgUnit) => {
3123
+ orgUnitsMap.set(orgUnit.id, orgUnit.name);
3124
+ });
3125
+ return orgUnitsMap;
3126
+ }));
3127
+ }
3128
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: LineListService, deps: [{ token: i1.NgxDhis2HttpClientService }], target: i0.ɵɵFactoryTarget.Injectable }); }
3129
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: LineListService }); }
3130
+ }
3131
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: LineListService, decorators: [{
3132
+ type: Injectable
3133
+ }], ctorParameters: () => [{ type: i1.NgxDhis2HttpClientService }] });
3134
+
3135
+ const getTrackedEntityTableData = (response, programId, pager, metaData) => {
3136
+ let teisRaw = response.data
3137
+ .trackedEntityInstances;
3138
+ const teis = Array.isArray(teisRaw)
3139
+ ? teisRaw
3140
+ : [teisRaw];
3141
+ const programTrackedEntityAttributes = metaData.programTrackedEntityAttributes;
3142
+ const orgUnitLabel = metaData.orgUnitLabel;
3143
+ const orgUnitMap = response.data
3144
+ .orgUnitsMap;
3145
+ const attributeColumns = metaData.displayInListTrackedEntityAttributes
3146
+ .sort((a, b) => a.sortOrder - b.sortOrder)
3147
+ .map((attr) => ({
3148
+ label: attr.name,
3149
+ key: attr.id,
3150
+ }));
3151
+ const dataElementColumns = metaData.displayInListDataElements
3152
+ .sort((a, b) => a.sortOrder - b.sortOrder)
3153
+ .map((element) => ({
3154
+ label: element.name,
3155
+ key: element.id,
3156
+ }));
3157
+ const dataElementOptions = metaData.displayInListDataElements.map((element) => ({
3158
+ id: element.id,
3159
+ options: element.optionSet?.options.map((opt) => ({
3160
+ name: opt.name,
3161
+ color: opt.style?.color,
3162
+ })),
3163
+ }));
3164
+ const tableColumns = [
3165
+ {
3166
+ label: orgUnitLabel || 'registering unit',
3167
+ key: 'orgUnit',
3168
+ },
3169
+ ...attributeColumns,
3170
+ ...dataElementColumns,
3171
+ ];
3172
+ const tableFilters = metaData.searchableTrackedEntityAttributes
3173
+ .sort((a, b) => a.sortOrder - b.sortOrder)
3174
+ .map((attr) => ({
3175
+ label: attr.name,
3176
+ key: attr.id,
3177
+ valueType: attr.valueType,
3178
+ options: attr.optionSet ?? undefined,
3179
+ }));
3180
+ const tableData = teis.map((tei, idx) => {
3181
+ const row = {
3182
+ trackedEntityInstance: { value: tei.trackedEntity },
3183
+ index: { value: (pager.page - 1) * pager.pageSize + idx + 1 },
3184
+ };
3185
+ const matchingEnrollment = tei.latestEnrollment;
3186
+ //let disaplayInListAttributes = metaData.displayInListTrackedEntityAttributes;
3187
+ let attributesData = matchingEnrollment.attributes;
3188
+ let dataElementsData = matchingEnrollment.events.flatMap((event) => event.dataValues);
3189
+ attributesData = attributesData.map((attr) => {
3190
+ if (attr?.valueType?.toLowerCase() === 'date') {
3191
+ try {
3192
+ return {
3193
+ ...attr,
3194
+ value: format(parse$1(attr.value, 'yyyy-MM-dd', new Date()), 'dd-MM-yyyy'),
3195
+ };
3196
+ }
3197
+ catch {
3198
+ return { ...attr }; // Leave value as is on parse failure
3199
+ }
3200
+ }
3201
+ return attr;
3202
+ });
3203
+ attributesData.forEach((attr) => {
3204
+ row[attr.attribute] = { value: attr.value };
3205
+ });
3206
+ dataElementsData.forEach((element) => {
3207
+ // Find the matching data element in dataElementOptions by ID
3208
+ const dataElementOption = dataElementOptions.find((deo) => deo.id === element.dataElement);
3209
+ // find a matching option within that data element's options
3210
+ const matchingOption = dataElementOption?.options?.find((opt) => opt.name === element.value);
3211
+ // Build the row entry with value and optionally style
3212
+ if (matchingOption) {
3213
+ row[element.dataElement] = {
3214
+ value: element.value,
3215
+ style: matchingOption.color,
3216
+ };
3217
+ }
3218
+ else {
3219
+ row[element.dataElement] = {
3220
+ value: element.value,
3221
+ };
3222
+ }
3223
+ });
3224
+ // Include orgUnit in the row for id access with style
3225
+ row['orgUnitId'] = { value: matchingEnrollment.orgUnit };
3226
+ row['orgUnit'] = {
3227
+ value: orgUnitMap?.get(matchingEnrollment.orgUnit) || '-',
3228
+ };
3229
+ return row;
3230
+ });
3231
+ return {
3232
+ columns: tableColumns,
3233
+ data: tableData,
3234
+ filteredEntityColumns: tableFilters,
3235
+ orgUnitLabel: orgUnitLabel,
3236
+ };
3237
+ };
3238
+ const addActionsColumn = (columns, actionOptions) => {
3239
+ return [
3240
+ ...columns,
3241
+ ...(actionOptions && actionOptions.length > 0
3242
+ ? [{ label: 'Actions', key: 'actions' }]
3243
+ : []),
3244
+ ];
3245
+ };
3246
+
3247
+ const FilterToolbar = ({ orgUnitLabel, selectedOrgUnit, setSelectedOrgUnit, setOrgUnitState, defaultOrgUnit, setHide, startDateState, setStartDateState, endDateState, setEndDateState, visibleFilters, dateStates, inputValues, setInputValues, handleInputChange, handleInputChangeForSelectField, handleDateSelect, prevValue, setPrevValue, showAllFilters, setShowAllFilters, }) => (React__default.createElement(DataTableToolbar, { className: "table-top-toolbar" },
3248
+ React__default.createElement("div", { style: {
3249
+ display: 'flex',
3250
+ alignItems: 'center',
3251
+ gap: '10px',
3252
+ flexWrap: 'wrap',
3253
+ } },
3254
+ React__default.createElement(InputField$1, { key: "location", label: orgUnitLabel ? orgUnitLabel : 'registering unit:', value: selectedOrgUnit, onFocus: () => setHide(false), className: "custom-input", clearable: true, onChange: (event) => {
3255
+ setSelectedOrgUnit(event.value);
3256
+ setOrgUnitState(defaultOrgUnit);
3257
+ } }),
3258
+ React__default.createElement(CalendarInput, { label: "Start date:", calendar: "gregory", locale: "en-GB", timeZone: "Africa/Dar_es_Salaam", className: "custom-input", date: startDateState, onDateSelect: (selectedDate) => {
3259
+ setStartDateState(selectedDate.calendarDateString);
3260
+ } }),
3261
+ React__default.createElement(CalendarInput, { label: "End date:", calendar: "gregory", locale: "en-GB", timeZone: "Africa/Dar_es_Salaam", className: "custom-input", date: endDateState, onDateSelect: (selectedDate) => {
3262
+ setEndDateState(selectedDate.calendarDateString);
3263
+ } }),
3264
+ (visibleFilters ?? []).map(({ label, key, valueType, options }) => {
3265
+ if (valueType === 'DATE') {
3266
+ return (React__default.createElement(CalendarInput, { key: key, label: `${label}:`, calendar: "gregory", locale: "en-GB", timeZone: "Africa/Dar_es_Salaam", className: "custom-input", date: dateStates[key] || '', onDateSelect: (selectedDate) => handleDateSelect(key, selectedDate) }));
3267
+ }
3268
+ if (options && options.options.length > 0) {
3269
+ return (React__default.createElement(SingleSelectField, { key: key, label: `${label}:`, selected: inputValues[key] || '', className: "custom-select-input", clearable: true, onChange: ({ selected }) => {
3270
+ setInputValues((prevValues) => ({
3271
+ ...prevValues,
3272
+ [key]: selected ?? '',
3273
+ }));
3274
+ handleInputChangeForSelectField(key, selected ?? '');
3275
+ } }, (options.options ?? []).map((opt) => (React__default.createElement(SingleSelectOption, { key: opt.id, label: opt.name, value: opt.code })))));
3276
+ }
3277
+ return (React__default.createElement(InputField$1, { key: key, label: `${label}:`, className: "custom-input", value: inputValues[key] || '', clearable: true, onChange: (e) => {
3278
+ const currentValue = 'target' in e ? e.target.value : e.value ?? '';
3279
+ setInputValues((prevValues) => ({
3280
+ ...prevValues,
3281
+ [key]: currentValue,
3282
+ }));
3283
+ if (currentValue === '') {
3284
+ handleInputChange(key, '');
3285
+ }
3286
+ }, onBlur: (e) => {
3287
+ const currentValue = 'target' in e ? e.target.value : e.value ?? '';
3288
+ if (currentValue !== '' && currentValue !== prevValue) {
3289
+ handleInputChange(key, currentValue);
3290
+ setPrevValue(currentValue);
3291
+ }
3292
+ } }));
3293
+ }),
3294
+ React__default.createElement(Button$1, { onClick: () => setShowAllFilters(!showAllFilters) }, showAllFilters ? 'Less Filters' : 'More Filters'))));
3295
+
3296
+ const TableHeader = ({ columns }) => (React__default.createElement(TableHead, null,
3297
+ React__default.createElement(DataTableRow, null, columns.map((col) => (React__default.createElement(DataTableColumnHeader, { key: col.key }, col.label))))));
3298
+
3109
3299
  const dropdownStyles$1 = {
3110
3300
  layer: {
3111
3301
  zIndex: '1 !important',
@@ -3242,6 +3432,68 @@ const DataTableActions = (props) => {
3242
3432
  // Use of this source code is governed by a BSD-style
3243
3433
  // license that can be found in the LICENSE file.
3244
3434
 
3435
+ const TableCell = ({ cell, getTextColorFromBackGround, }) => {
3436
+ if (cell?.style && cell?.style !== 'default-value') {
3437
+ return (React__default.createElement(DataTableCell, null,
3438
+ React__default.createElement("div", { style: { display: 'flex', justifyContent: 'center' } },
3439
+ React__default.createElement("span", { style: {
3440
+ backgroundColor: cell.style,
3441
+ display: 'inline-flex',
3442
+ alignItems: 'center',
3443
+ padding: 4,
3444
+ borderRadius: 3,
3445
+ fontSize: 12,
3446
+ color: getTextColorFromBackGround(cell.style),
3447
+ } }, cell.value))));
3448
+ }
3449
+ return (React__default.createElement(DataTableCell, null,
3450
+ React__default.createElement("div", { className: "text-sm text-gray-800" }, cell?.value || '-')));
3451
+ };
3452
+
3453
+ const TableRow = ({ row, columns, getTextColorFromBackGround, actionOptions, actionOptionOrientation, actionSelected, }) => (React__default.createElement(DataTableRow, { key: row.index.value }, columns.map((col) => {
3454
+ if (col.key === 'actions') {
3455
+ return (React__default.createElement(DataTableCell, { key: col.key }, actionOptions && (React__default.createElement(DataTableActions, { actionOptions: actionOptions, actionOptionOrientation: actionOptionOrientation, onClick: (option) => {
3456
+ if (option.onClick)
3457
+ option.onClick(row);
3458
+ actionSelected.emit({ action: option.label, row });
3459
+ } }))));
3460
+ }
3461
+ return (React__default.createElement(TableCell, { key: col.key, cell: row[col.key], getTextColorFromBackGround: getTextColorFromBackGround }));
3462
+ })));
3463
+
3464
+ const TableBody = ({ data, columns, getTextColorFromBackGround, actionOptions, actionOptionOrientation, actionSelected, }) => (React__default.createElement(TableBody$1, null, data.length > 0 ? (data.map((row) => (React__default.createElement(TableRow, { key: row.index.value, row: row, columns: columns, getTextColorFromBackGround: getTextColorFromBackGround, actionOptions: actionOptions, actionOptionOrientation: actionOptionOrientation, actionSelected: actionSelected })))) : (React__default.createElement(DataTableRow, null,
3465
+ React__default.createElement(DataTableCell, { colSpan: columns.length.toString(), style: {
3466
+ textAlign: 'center',
3467
+ fontWeight: 'bold',
3468
+ color: 'grey',
3469
+ padding: '20px',
3470
+ } }, "No data found")))));
3471
+
3472
+ const Pagination = ({ pager, setPager }) => {
3473
+ if (!pager || pager.page === undefined || pager.pageSize === undefined) {
3474
+ return null; //skip rendering until valid
3475
+ }
3476
+ return (React__default.createElement(Pagination$1, { page: pager.page, pageCount: pager.pageCount, pageSize: pager.pageSize, total: pager.total, onPageChange: (page) => setPager((prev) => new Pager({ ...prev, page })), onPageSizeChange: (pageSize) => setPager((prev) => new Pager({
3477
+ ...prev,
3478
+ pageSize: Number(pageSize),
3479
+ page: 1,
3480
+ })), pageSizes: ['10', '20', '50', '100', '500'] }));
3481
+ };
3482
+
3483
+ const TableFooter = ({ pager, setPager, columns }) => {
3484
+ return (React__default.createElement(TableFoot, null,
3485
+ React__default.createElement(DataTableRow, null,
3486
+ React__default.createElement(DataTableCell, { colSpan: columns.length.toString() },
3487
+ React__default.createElement(Pagination, { pager: pager, setPager: setPager })))));
3488
+ };
3489
+
3490
+ const LineListTable = ({ columns, data, pager, setPager, getTextColorFromBackGround, actionOptions, actionOptionOrientation, actionSelected, }) => {
3491
+ return (React__default.createElement(DataTable, null,
3492
+ React__default.createElement(TableHeader, { columns: columns }),
3493
+ React__default.createElement(TableBody, { data: data, columns: columns, getTextColorFromBackGround: getTextColorFromBackGround, actionOptions: actionOptions, actionOptionOrientation: actionOptionOrientation, actionSelected: actionSelected }),
3494
+ React__default.createElement(TableFooter, { columns: columns, pager: pager, setPager: setPager })));
3495
+ };
3496
+
3245
3497
  // Copyright 2025 UDSM DHIS2 Lab. All rights reserved.
3246
3498
  // Use of this source code is governed by a BSD-style
3247
3499
  // license that can be found in the LICENSE file.
@@ -3426,854 +3678,27 @@ const OrgUnitFormField$1 = (props) => {
3426
3678
  React__default.createElement(CircularLoader$1, { small: true }))) : (React__default.createElement("div", { className: classes.orgUnitTreeContainer, style: { maxHeight: '200px', overflowY: 'auto' } }, renderOrgUnitTree()))))))));
3427
3679
  };
3428
3680
 
3429
- // export function buildFilters(filters: AttributeFilter[]): string {
3430
- // return filters
3431
- // .map(({ attribute, operator, value }) => `filter=${attribute}:${operator}:${value}`)
3432
- // .join('&');
3433
- // }
3434
- function buildFilters(filters) {
3435
- return filters
3436
- .map(({ attribute, dataElement, operator, value }) => {
3437
- // Check if attribute is defined, otherwise use dataElement
3438
- const field = attribute || dataElement;
3439
- return field ? `filter=${field}:${operator}:${value}` : '';
3440
- })
3441
- .filter(Boolean) // Remove any empty strings
3442
- .join('&');
3443
- }
3444
- function buildFiltersFromEvents(filters) {
3445
- return filters
3446
- .map((filter) => `filter=${filter.programStage}.${filter.dataElement}:${filter.operator}:${filter.value}`)
3447
- .join('&');
3448
- }
3449
- const matchesCondition = (eventValue, operator, filterValue) => {
3450
- if (typeof eventValue === 'number' && typeof filterValue === 'number') {
3451
- switch (operator) {
3452
- case '=':
3453
- return eventValue === filterValue;
3454
- case '!=':
3455
- return eventValue !== filterValue;
3456
- case '>':
3457
- return eventValue > filterValue;
3458
- case '<':
3459
- return eventValue < filterValue;
3460
- case '>=':
3461
- return eventValue >= filterValue;
3462
- case '<=':
3463
- return eventValue <= filterValue;
3464
- default:
3465
- return false;
3466
- }
3467
- }
3468
- const strEventValue = String(eventValue);
3469
- const strFilterValue = String(filterValue);
3470
- switch (operator) {
3471
- case '=':
3472
- return strEventValue === strFilterValue;
3473
- case '!=':
3474
- return strEventValue !== strFilterValue;
3475
- case 'contains':
3476
- return strEventValue.includes(strFilterValue);
3477
- case 'startsWith':
3478
- return strEventValue.startsWith(strFilterValue);
3479
- case 'endsWith':
3480
- return strEventValue.endsWith(strFilterValue);
3481
- case 'regex':
3482
- return new RegExp(strFilterValue).test(strEventValue);
3483
- default:
3484
- return false;
3485
- }
3486
- };
3487
- // export const getFilteredTrackedEntityInstances = (
3488
- // trackedEntityInstance: TrackedEntityInstance[],
3489
- // filters: FilterConfig[]
3490
- // ): TrackedEntityInstance[] => {
3491
- // return trackedEntityInstance.filter(
3492
- // (trackedEntityInstance: TrackedEntityInstance) =>
3493
- // trackedEntityInstance.enrollments.some((enrollment) =>
3494
- // enrollment.events.some((event) =>
3495
- // filters.every(
3496
- // (filter) =>
3497
- // event.programStage === filter.programStage &&
3498
- // event.dataValues.some(
3499
- // (dataValue) =>
3500
- // dataValue.dataElement === filter.dataElement &&
3501
- // matchesCondition(
3502
- // dataValue.value,
3503
- // filter.operator,
3504
- // filter.value
3505
- // )
3506
- // )
3507
- // )
3508
- // )
3509
- // )
3510
- // );
3511
- // };
3512
- const getFilteredTrackedEntityInstances = (trackedEntityInstances, filters) => {
3513
- if (!filters.length)
3514
- return trackedEntityInstances;
3515
- return trackedEntityInstances.filter((tei) => filters.every((filter) => tei.enrollments?.some((enrollment) => enrollment.events?.some((event) => event.programStage === filter.programStage &&
3516
- event.dataValues?.some((dataValue) => dataValue.dataElement === filter.dataElement &&
3517
- matchesCondition(dataValue.value, filter.operator, filter.value))))));
3518
- };
3519
- const getFilteredTrackedEntites = (trackedEntities, filters) => {
3520
- if (!filters.length)
3521
- return trackedEntities;
3522
- return trackedEntities.filter((tei) => filters.every((filter) => tei.enrollments?.some((enrollment) => enrollment.events?.some((event) => event.programStage === filter.programStage &&
3523
- event.dataValues?.some((dataValue) => dataValue.dataElement === filter.dataElement &&
3524
- matchesCondition(dataValue.value, filter.operator, filter.value))))));
3525
- };
3526
-
3527
- class LineListService {
3528
- constructor(httpClient) {
3529
- this.httpClient = httpClient;
3530
- }
3531
- getProgramMetadata(programId) {
3532
- return this.httpClient.get(`programs/${programId}.json?fields=programType,programStages[id,name,programStageDataElements[dataElement[id,name,shortName,formName,code,optionSetValue,valueType,
3533
- optionSet[id,name,options[id,name,code]]]]],programTrackedEntityAttributes[*,trackedEntityAttribute[id,name,unique,generated,formName,code,optionSetValue
3534
- ,valueType,optionSet[id,name,options[id,name,code]]]],orgUnitLabel`);
3535
- }
3536
- // private getTrackedEntityInstances(
3537
- // programId: string,
3538
- // orgUnit: string,
3539
- // page: number,
3540
- // pageSize: number,
3541
- // filters: AttributeFilter[] = [],
3542
- // startDate?: string,
3543
- // endDate?: string,
3544
- // ouMode?: string,
3545
- // filterRootOrgUnit?: boolean
3546
- // ): Observable<TrackedEntityResponse> {
3547
- // const filterParams = buildFilters(filters);
3548
- // // const dateFilter = startDate || endDate ? `enrollmentEnrolledAfter=${startDate}&enrollmentEnrolledBefore=${endDate}` : '';
3549
- // const dateFilter = [
3550
- // startDate ? `enrollmentEnrolledAfter=${startDate}` : '',
3551
- // endDate ? `enrollmentEnrolledBefore=${endDate}` : '',
3552
- // ].filter(Boolean).join('&');
3553
- // const ouModeIdentifier = ouMode ? `&orgUnitMode=${ouMode}`: ``;
3554
- // return this.httpClient.get(
3555
- // `tracker/trackedEntities.json?program=${programId}&orgUnit=${orgUnit}${ouModeIdentifier}&page=${page}&pageSize=${pageSize}&fields=trackedEntity,orgUnit,attributes[*],enrollments[*]&totalPages=true&${filterParams}${dateFilter}&order=createdAt:desc`
3556
- // ).pipe(
3557
- // map((response: any) => {
3558
- // if (filterRootOrgUnit) {
3559
- // response.trackedEntities = response.trackedEntities.filter(
3560
- // (tei: any) => tei.orgUnit !== orgUnit // Exclude TEIs with the root orgUnit
3561
- // );
3562
- // }
3563
- // return response;
3564
- // })
3565
- // );
3566
- // }
3567
- //tracker/trackedEntities.json?program=${programId}&orgUnit=${orgUnit}${ouModeIdentifier}&page=${page}&pageSize=${pageSize}&fields=trackedEntity,orgUnit,attributes[*],enrollments[*]&totalPages=true&${filterParams}${dateFilter}&order=createdAt:desc&trackedEntities=uid1,uid2,uid3
3568
- getTrackedEntityInstances(programId, orgUnit, page, pageSize, filters = [], startDate, endDate, ouMode, filterRootOrgUnit, useOuModeWithOlderDHIS2Instance, filtersFromEvents = []) {
3569
- const filterParams = buildFilters(filters);
3570
- const filterParamsFromEvents = buildFiltersFromEvents(filtersFromEvents);
3571
- const dateFilter = [
3572
- startDate ? `enrollmentEnrolledAfter=${startDate}` : '',
3573
- endDate ? `enrollmentEnrolledBefore=${endDate}` : '',
3574
- ]
3575
- .filter(Boolean)
3576
- .join('&');
3577
- const ouModeIdentifier = ouMode && useOuModeWithOlderDHIS2Instance
3578
- ? `&ouMode=${ouMode}`
3579
- : `&orgUnitMode=${ouMode}`;
3580
- return this.httpClient
3581
- .get(`tracker/trackedEntities.json?program=${programId}&orgUnit=${orgUnit}${ouModeIdentifier}&page=${page}&pageSize=${pageSize}&fields=trackedEntity,orgUnit,attributes[*],enrollments[*]&totalPages=true&${filterParams}${dateFilter}&order=createdAt:desc`)
3582
- .pipe(switchMap((response) => {
3583
- if (filterRootOrgUnit) {
3584
- response.trackedEntities = response.trackedEntities.filter((tei) => tei.orgUnit !== orgUnit);
3585
- }
3586
- // **Step 1:** Extract unique orgUnits from enrollments
3587
- const uniqueOrgUnitIds = new Set();
3588
- if (response && response.trackedEntities) {
3589
- response.trackedEntities.forEach((tei) => {
3590
- tei.enrollments?.forEach((enrollment) => {
3591
- if (enrollment.program === programId) {
3592
- uniqueOrgUnitIds.add(enrollment.orgUnit);
3593
- }
3594
- });
3595
- });
3596
- }
3597
- else {
3598
- if (response && response.instances) {
3599
- response?.instances?.forEach((tei) => {
3600
- tei.enrollments?.forEach((enrollment) => {
3601
- if (enrollment.program === programId) {
3602
- uniqueOrgUnitIds.add(enrollment?.orgUnit);
3603
- }
3604
- });
3605
- });
3606
- }
3607
- }
3608
- // If no unique orgUnits found, return immediately
3609
- if (uniqueOrgUnitIds.size === 0) {
3610
- return of({ ...response, orgUnitsMap: new Map() });
3611
- }
3612
- // **Step 2:** Fetch orgUnit names in a single request
3613
- return this.fetchOrgUnits(Array.from(uniqueOrgUnitIds)).pipe(map$1((orgUnitsMap) => ({
3614
- ...response,
3615
- orgUnitsMap, // Attach orgUnitId → orgUnitName map
3616
- })));
3617
- }));
3618
- }
3619
- // private getTrackedEntityInstances(
3620
- // programId: string,
3621
- // orgUnit: string,
3622
- // page: number,
3623
- // pageSize: number,
3624
- // filters: AttributeFilter[] = [],
3625
- // startDate?: string,
3626
- // endDate?: string,
3627
- // ouMode?: string,
3628
- // filterRootOrgUnit?: boolean,
3629
- // useOuModeWithOlderDHIS2Instance?: boolean,
3630
- // filtersFromEvents: FilterConfig[] = []
3631
- // ): Observable<TrackedEntityResponse> {
3632
- // const filterParams = buildFilters(filters);
3633
- // const filterParamsFromEvents = buildFiltersFromEvents(filtersFromEvents);
3634
- // const dateFilter = [
3635
- // startDate ? `enrollmentEnrolledAfter=${startDate}` : '',
3636
- // endDate ? `enrollmentEnrolledBefore=${endDate}` : '',
3637
- // ]
3638
- // .filter(Boolean)
3639
- // .join('&');
3640
- // const ouModeIdentifier =
3641
- // ouMode && useOuModeWithOlderDHIS2Instance
3642
- // ? `&ouMode=${ouMode}`
3643
- // : `&orgUnitMode=${ouMode}`;
3644
- // let baseUrl='';
3645
- // if(filtersFromEvents.length === 0) {
3646
- // baseUrl = `tracker/trackedEntities.json?program=${programId}&orgUnit=${orgUnit}${ouModeIdentifier}&page=${page}&pageSize=${pageSize}&fields=trackedEntity,orgUnit,attributes[*],enrollments[*]&totalPages=true&${filterParams}${dateFilter}&order=createdAt:desc`;
3647
- // } else {
3648
- // baseUrl = `tracker/trackedEntities.json?program=${programId}&orgUnit=${orgUnit}${ouModeIdentifier}&fields=trackedEntity,orgUnit,attributes[*],enrollments[*]&${filterParams}${dateFilter}&order=createdAt:desc&paging=false`;
3649
- // }
3650
- // return this.httpClient.get(baseUrl).pipe(
3651
- // switchMap((response: any) => {
3652
- // if (filterRootOrgUnit) {
3653
- // response.trackedEntities = response.trackedEntities.filter(
3654
- // (tei: any) => tei.orgUnit !== orgUnit
3655
- // );
3656
- // }
3657
- // const uniqueOrgUnitIds = new Set<string>();
3658
- // if (response && response.trackedEntities) {
3659
- // response.trackedEntities.forEach((tei: any) => {
3660
- // tei.enrollments?.forEach((enrollment: any) => {
3661
- // if (enrollment.program === programId) {
3662
- // uniqueOrgUnitIds.add(enrollment.orgUnit);
3663
- // }
3664
- // });
3665
- // });
3666
- // } else {
3667
- // response?.instances?.forEach((tei: any) => {
3668
- // tei.enrollments?.forEach((enrollment: any) => {
3669
- // if (enrollment.program === programId) {
3670
- // uniqueOrgUnitIds.add(enrollment.orgUnit);
3671
- // }
3672
- // });
3673
- // });
3674
- // }
3675
- // if (filtersFromEvents.length === 0) {
3676
- // if (uniqueOrgUnitIds.size === 0) {
3677
- // return of({ ...response, orgUnitsMap: new Map<string, string>() });
3678
- // }
3679
- // return this.fetchOrgUnits(Array.from(uniqueOrgUnitIds)).pipe(
3680
- // map((orgUnitsMap: Map<string, string>) => ({
3681
- // ...response,
3682
- // orgUnitsMap,
3683
- // }))
3684
- // );
3685
- // }
3686
- // // NEW LOGIC STARTS HERE if filtersFromEvents is present
3687
- // const filteredTrackedEntities = getFilteredTrackedEntites(
3688
- // response.trackedEntities,
3689
- // filtersFromEvents
3690
- // );
3691
- // const trackedEntityIds = filteredTrackedEntities
3692
- // .map((tei: any) => tei.trackedEntity)
3693
- // .join(',');
3694
- // if (!trackedEntityIds) {
3695
- // return of({
3696
- // trackedEntities: [],
3697
- // orgUnitsMap: new Map<string, string>(),
3698
- // });
3699
- // }
3700
- // const refetchUrl = `tracker/trackedEntities.json?program=${programId}&orgUnit=${orgUnit}${ouModeIdentifier}&page=${page}&pageSize=${pageSize}&fields=trackedEntity,orgUnit,attributes[*],enrollments[*]&totalPages=true&${filterParams}${dateFilter}&order=createdAt:desc&trackedEntities=${trackedEntityIds}`;
3701
- // return this.httpClient.get(refetchUrl).pipe(
3702
- // switchMap((filteredResponse: any) => {
3703
- // const orgUnitIds = new Set<string>();
3704
- // filteredResponse.trackedEntities?.forEach((tei: any) => {
3705
- // tei.enrollments?.forEach((enrollment: any) => {
3706
- // if (enrollment.program === programId) {
3707
- // orgUnitIds.add(enrollment.orgUnit);
3708
- // }
3709
- // });
3710
- // });
3711
- // return this.fetchOrgUnits(Array.from(orgUnitIds)).pipe(
3712
- // map((orgUnitsMap: Map<string, string>) => ({
3713
- // ...filteredResponse,
3714
- // orgUnitsMap,
3715
- // }))
3716
- // );
3717
- // })
3718
- // );
3719
- // })
3720
- // );
3721
- // }
3722
- /**
3723
- * Fetch orgUnit names for given orgUnit IDs
3724
- */
3725
- fetchOrgUnits(orgUnitIds) {
3726
- const idsQuery = `filter=id:in:[${orgUnitIds}]`;
3727
- return this.httpClient
3728
- .get(`organisationUnits.json?fields=id,name&paging=false&${idsQuery}`)
3729
- .pipe(map$1((response) => {
3730
- const orgUnitsMap = new Map();
3731
- response.organisationUnits.forEach((orgUnit) => {
3732
- orgUnitsMap.set(orgUnit.id, orgUnit.name);
3733
- });
3734
- return orgUnitsMap;
3735
- }));
3736
- }
3737
- getEvents(programId, orgUnit, page, pageSize, filters = [], startDate, endDate, ouMode, useOuModeWithOlderDHIS2Instance) {
3738
- const filterParams = buildFilters(filters);
3739
- const dateFilter = startDate && endDate ? `&startDate=${startDate}&endDate=${endDate}` : '';
3740
- const ouModeIdentifier = ouMode && useOuModeWithOlderDHIS2Instance
3741
- ? `&ouMode=${ouMode}`
3742
- : `&ouMode=${ouMode}`;
3743
- // const ouModeIdentifier = ouMode ? `&ouMode=${ouMode}`: ``;
3744
- return this.httpClient.get(`events.json?program=${programId}&orgUnit=${orgUnit}${ouModeIdentifier}&page=${page}&pageSize=${pageSize}&fields=*&totalPages=true&${filterParams}${dateFilter}`);
3745
- }
3746
- getEventsByProgramStage(programStageId, orgUnit, page, pageSize, filters = [], startDate, endDate, ouMode) {
3747
- const filterParams = buildFilters(filters);
3748
- const dateFilter = startDate && endDate ? `&startDate=${startDate}&endDate=${endDate}` : '';
3749
- const ouModeIdentifier = ouMode ? `&ouMode=${ouMode}` : ``;
3750
- return this.httpClient.get(`events.json?programStage=${programStageId}&orgUnit=${orgUnit}${ouModeIdentifier}&page=${page}&pageSize=${pageSize}&fields=*&totalPages=true&${filterParams}${dateFilter}`);
3751
- }
3752
- getLineListData(programId, orgUnit = '', programStageId, page = 1, pageSize = 10, filters = [], startDate, endDate, ouMode, filterRootOrgUnit, useOuModeWithOlderDHIS2Instance, filtersFromEvents = []) {
3753
- return this.getProgramMetadata(programId).pipe(switchMap((programMetadata) => {
3754
- if (programStageId) {
3755
- return this.getEventsByProgramStage(programStageId, orgUnit, page, pageSize, filters, startDate, endDate, ouMode).pipe(map$1((events) => ({
3756
- metadata: programMetadata,
3757
- data: events,
3758
- })));
3759
- }
3760
- if (programMetadata.programType === 'WITH_REGISTRATION') {
3761
- return this.getTrackedEntityInstances(programId, orgUnit, page, pageSize, filters, startDate, endDate, ouMode, filterRootOrgUnit, useOuModeWithOlderDHIS2Instance, filtersFromEvents).pipe(map$1((teis) => ({
3762
- metadata: programMetadata,
3763
- data: teis,
3764
- orgUnits: teis.orgUnitsMap,
3765
- })));
3766
- }
3767
- else {
3768
- return this.getEvents(programId, orgUnit, page, pageSize, filters, startDate, endDate, ouMode, useOuModeWithOlderDHIS2Instance).pipe(map$1((events) => ({
3769
- metadata: programMetadata,
3770
- data: events,
3771
- })));
3772
- }
3773
- }));
3774
- }
3775
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: LineListService, deps: [{ token: i1.NgxDhis2HttpClientService }], target: i0.ɵɵFactoryTarget.Injectable }); }
3776
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: LineListService }); }
3777
- }
3778
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: LineListService, decorators: [{
3779
- type: Injectable
3780
- }], ctorParameters: () => [{ type: i1.NgxDhis2HttpClientService }] });
3781
-
3782
- // export const getProgramStageData = (
3783
- // response: LineListResponse,
3784
- // programStageId: string,
3785
- // pager: any,
3786
- // isOptionSetNameVisible: boolean
3787
- // ): { columns: ColumnDefinition[]; data: TableRow[] } => {
3788
- // const events = (response.data as EventsResponse).events;
3789
- // const allDataElements = new Set<string>();
3790
- // events.forEach((event: any) => {
3791
- // event.dataValues.forEach((dv: any) => allDataElements.add(dv.dataElement));
3792
- // });
3793
- // const stageFromMetaData = response.metadata.programStages.find(
3794
- // (stage: any) => stage.id === programStageId
3795
- // );
3796
- // if (!stageFromMetaData) {
3797
- // throw new Error(`Program stage with ID ${programStageId} not found`);
3798
- // }
3799
- // const entityColumns = Array.from(allDataElements).map(
3800
- // (dataElementId: string) => ({
3801
- // label:
3802
- // stageFromMetaData.programStageDataElements.find(
3803
- // (psde: any) => psde.dataElement.id === dataElementId
3804
- // )?.dataElement.name || dataElementId,
3805
- // key: dataElementId,
3806
- // })
3807
- // );
3808
- // const dataElementsData: TableRow[] = events.map((event: any, idx: number) => {
3809
- // const row: TableRow = {
3810
- // event: event.event,
3811
- // index: (pager.page - 1) * pager.pageSize + idx + 1,
3812
- // };
3813
- // allDataElements.forEach(
3814
- // (dataElementId: string) => (row[dataElementId] = '')
3815
- // );
3816
- // if (isOptionSetNameVisible) {
3817
- // event.dataValues.forEach((dv: any) => (row[dv.dataElement] = dv.value));
3818
- // } else {
3819
- // event.dataValues.forEach((dv: any) => (row[dv.dataElement] = dv.value));
3820
- // }
3821
- // return row;
3822
- // });
3823
- // return { columns: entityColumns, data: dataElementsData };
3824
- // };
3825
- // export const getTrackedEntityData = (
3826
- // response: LineListResponse,
3827
- // programId: string,
3828
- // pager: any,
3829
- // isOptionSetNameVisible: boolean,
3830
- // filters?: FilterConfig[]
3831
- // ): {
3832
- // columns: ColumnDefinition[];
3833
- // data: TableRow[];
3834
- // filteredEntityColumns: ColumnDefinition[];
3835
- // } => {
3836
- // let teis =
3837
- // (response.data as TrackedEntityResponse)?.trackedEntities ??
3838
- // (response.data as TrackedEntityResponse)?.instances ??
3839
- // [];
3840
- // const programMetaData = response.metadata.programTrackedEntityAttributes;
3841
- // // //organisation units from metadata
3842
- // // let orgUnitsFromMetaData = response.metadata.organisationUnits;
3843
- // // //a Map to efficiently look up orgUnit names by ID
3844
- // // const orgUnitMap = new Map<string, string>(
3845
- // // orgUnitsFromMetaData.map((ou: { id: string; name: string }) => [
3846
- // // ou.id,
3847
- // // ou.name,
3848
- // // ])
3849
- // // );
3850
- // const orgUnitMap = (response.data as TrackedEntityResponse).orgUnitsMap;
3851
- // const mappedProgramMetadataAttributes = programMetaData.map((attr) => ({
3852
- // displayInList: attr.displayInList,
3853
- // searchable: attr.searchable,
3854
- // id: attr.trackedEntityAttribute.id,
3855
- // }));
3856
- // const programAttributesMap = programMetaData.reduce(
3857
- // (acc: { [key: string]: string }, attribute: any) => {
3858
- // if (attribute.displayInList) {
3859
- // acc[attribute.id] = attribute.displayName;
3860
- // }
3861
- // return acc;
3862
- // },
3863
- // {}
3864
- // );
3865
- // if (filters) {
3866
- // teis = getFilteredTrackedEntites(teis, filters);
3867
- // }
3868
- // const allAttributes = new Set<string>();
3869
- // teis.forEach((tei: any) => {
3870
- // const matchingEnrollment = tei.enrollments.find(
3871
- // (enrollment: any) => enrollment.program === programId
3872
- // );
3873
- // const attributes = matchingEnrollment
3874
- // ? matchingEnrollment.attributes
3875
- // : tei.attributes;
3876
- // attributes.forEach((attr: any) => allAttributes.add(attr.attribute));
3877
- // });
3878
- // let entityColumns = Array.from(allAttributes).map((attrId: string) => {
3879
- // const foundAttribute = teis
3880
- // .flatMap((tei: any) => {
3881
- // const matchingEnrollment = tei.enrollments.find(
3882
- // (enrollment: any) => enrollment.program === programId
3883
- // );
3884
- // return matchingEnrollment
3885
- // ? matchingEnrollment.attributes
3886
- // : tei.attributes;
3887
- // })
3888
- // .find((attr: any) => attr.attribute === attrId);
3889
- // return {
3890
- // label: foundAttribute?.displayName || attrId,
3891
- // key: attrId,
3892
- // };
3893
- // });
3894
- // entityColumns = entityColumns.filter((column) => {
3895
- // // Check if the column label is part of any value in programAttributesMap
3896
- // return Object.values(programAttributesMap).some((value: string) =>
3897
- // value.includes(column.label)
3898
- // );
3899
- // });
3900
- // // Add orgUnit as the first column
3901
- // entityColumns.unshift({
3902
- // label: 'Location',
3903
- // key: 'orgUnit',
3904
- // });
3905
- // const searchableAttributes = mappedProgramMetadataAttributes
3906
- // .filter((attr) => attr.searchable && attr.displayInList)
3907
- // .map((attr) => ({
3908
- // // label: attr.trackedEntityAttribute.displayName,
3909
- // key: attr.id,
3910
- // }));
3911
- // // Extract keys from searchableAttributes for quick lookup
3912
- // const searchableKeys = new Set(searchableAttributes.map((attr) => attr.key));
3913
- // // Filter entityColumns to keep only those whose key exists in searchableAttributes
3914
- // const filteredEntityColumns = entityColumns.filter((column) =>
3915
- // searchableKeys.has(column.key)
3916
- // );
3917
- // const attributesData = teis.map((tei: any, idx: number) => {
3918
- // const row: TableRow = {
3919
- // trackedEntityInstance: tei.trackedEntity,
3920
- // index: (pager.page - 1) * pager.pageSize + idx + 1,
3921
- // };
3922
- // allAttributes.forEach((attrId: string) => (row[attrId] = ''));
3923
- // const matchingEnrollment = tei.enrollments.find(
3924
- // (enrollment: any) => enrollment.program === programId
3925
- // );
3926
- // const attributesToUse = matchingEnrollment
3927
- // ? matchingEnrollment.attributes
3928
- // : tei.attributes;
3929
- // console.log('RESPONSE::: ', JSON.stringify(attributesToUse));
3930
- // console.log('HERE WEARE', JSON.stringify(response.metadata));
3931
- // if (isOptionSetNameVisible) {
3932
- // attributesToUse.forEach(
3933
- // (attr: any) => (row[attr.attribute] = attr.value)
3934
- // );
3935
- // } else {
3936
- // attributesToUse.forEach(
3937
- // (attr: any) => (row[attr.attribute] = attr.value)
3938
- // );
3939
- // }
3940
- // //include orgUnit in the row for id access
3941
- // row['orgUnitId'] = matchingEnrollment.orgUnit;
3942
- // // Access the name of the orgUnit using the Map
3943
- // // row['orgUnit'] = matchingEnrollment.orgUnitName;
3944
- // row['orgUnit'] = orgUnitMap?.get(matchingEnrollment.orgUnit) || 'N/A';
3945
- // // row['orgUnit'] =
3946
- // // orgUnitMap && orgUnitMap[matchingEnrollment.orgUnit]
3947
- // // ? orgUnitMap[matchingEnrollment.orgUnit]
3948
- // // : 'N/A';
3949
- // return row;
3950
- // });
3951
- // return {
3952
- // columns: entityColumns,
3953
- // data: attributesData,
3954
- // filteredEntityColumns: filteredEntityColumns,
3955
- // };
3956
- // };
3957
- const getProgramStageData = (response, programStageId, pager, isOptionSetNameVisible) => {
3958
- const events = response.data.events;
3959
- const allDataElements = new Set();
3960
- events.forEach((event) => {
3961
- event.dataValues.forEach((dv) => allDataElements.add(dv.dataElement));
3962
- });
3963
- const stageFromMetaData = response.metadata.programStages.find((stage) => stage.id === programStageId);
3964
- if (!stageFromMetaData) {
3965
- throw new Error(`Program stage with ID ${programStageId} not found`);
3966
- }
3967
- const entityColumns = Array.from(allDataElements).map((dataElementId) => {
3968
- const dataElementMeta = stageFromMetaData.programStageDataElements.find((psde) => psde.dataElement.id === dataElementId);
3969
- return {
3970
- label: dataElementMeta?.dataElement.name || dataElementId,
3971
- key: dataElementId,
3972
- };
3973
- });
3974
- const dataElementsData = events.map((event, idx) => {
3975
- const row = {
3976
- event: event.event,
3977
- index: (pager.page - 1) * pager.pageSize + idx + 1,
3978
- };
3979
- allDataElements.forEach((dataElementId) => (row[dataElementId] = ''));
3980
- event.dataValues.forEach((dv) => {
3981
- const dataElementMeta = stageFromMetaData.programStageDataElements.find((psde) => psde.dataElement.id === dv.dataElement);
3982
- if (isOptionSetNameVisible && dataElementMeta?.dataElement.optionSet) {
3983
- const optionSet = dataElementMeta.dataElement.optionSet;
3984
- const matchingOption = optionSet.options.find((option) => option.code === dv.value);
3985
- row[dv.dataElement] = matchingOption ? matchingOption.name : dv.value;
3986
- }
3987
- else {
3988
- row[dv.dataElement] = dv.value;
3989
- }
3990
- });
3991
- return row;
3992
- });
3993
- return { columns: entityColumns, data: dataElementsData };
3994
- };
3995
- const getTrackedEntityData = (response, programId, pager, isOptionSetNameVisible, filters) => {
3996
- let teis = response.data?.trackedEntities ??
3997
- response.data?.instances ??
3998
- [];
3999
- const programMetaData = response.metadata.programTrackedEntityAttributes;
4000
- const orgUnitLabel = response.metadata.orgUnitLabel;
4001
- const orgUnitMap = response.data.orgUnitsMap;
4002
- const mappedProgramMetadataAttributes = programMetaData.map((attr) => ({
4003
- displayInList: attr.displayInList,
4004
- searchable: attr.searchable,
4005
- id: attr.trackedEntityAttribute.id,
4006
- name: attr.trackedEntityAttribute.name,
4007
- optionSet: attr.trackedEntityAttribute.optionSetValue
4008
- ? attr.trackedEntityAttribute.optionSet
4009
- : null,
4010
- sortOrder: attr.sortOrder,
4011
- }));
4012
- if (filters) {
4013
- teis = getFilteredTrackedEntites(teis, filters);
4014
- }
4015
- const allAttributes = new Set();
4016
- teis.forEach((tei) => {
4017
- const matchingEnrollment = tei.enrollments.find((enrollment) => enrollment.program === programId);
4018
- const attributes = matchingEnrollment
4019
- ? matchingEnrollment.attributes
4020
- : tei.attributes;
4021
- attributes.forEach((attr) => allAttributes.add(attr.attribute));
4022
- });
4023
- let entityColumns = Array.from(allAttributes).map((attrId) => {
4024
- const foundAttribute = teis
4025
- .flatMap((tei) => {
4026
- const matchingEnrollment = tei.enrollments.find((enrollment) => enrollment.program === programId);
4027
- return matchingEnrollment
4028
- ? matchingEnrollment.attributes
4029
- : tei.attributes;
4030
- })
4031
- .find((attr) => attr.attribute === attrId);
4032
- return {
4033
- label: foundAttribute?.displayName || attrId,
4034
- key: attrId,
4035
- };
4036
- });
4037
- entityColumns = entityColumns
4038
- .filter((column) => {
4039
- return mappedProgramMetadataAttributes
4040
- .filter((attr) => attr.displayInList)
4041
- .some((attr) => attr.id === column.key); // Ensure the column's key matches an id in the filtered list
4042
- })
4043
- .sort((a, b) => {
4044
- // Ensures sortOrder values are treated as numbers
4045
- const sortOrderA = Number(mappedProgramMetadataAttributes.find((attr) => attr.id === a.key)
4046
- ?.sortOrder ?? 0); // Default to 0 if undefined, explicitly cast to number
4047
- const sortOrderB = Number(mappedProgramMetadataAttributes.find((attr) => attr.id === b.key)
4048
- ?.sortOrder ?? 0); // Default to 0 if undefined, explicitly cast to number
4049
- return sortOrderA - sortOrderB; // Ascending order based on sortOrder
4050
- });
4051
- entityColumns.unshift({
4052
- label: orgUnitLabel || 'registering unit',
4053
- key: 'orgUnit',
4054
- });
4055
- const searchableAttributes = mappedProgramMetadataAttributes
4056
- .filter((attr) => attr.searchable && attr.displayInList)
4057
- .map((attr) => ({
4058
- key: attr.id,
4059
- }));
4060
- const searchableKeys = new Set(searchableAttributes.map((attr) => attr.key));
4061
- const filteredEntityColumns = Array.from(allAttributes)
4062
- .map((attrId) => {
4063
- const foundAttribute = teis
4064
- .flatMap((tei) => {
4065
- const matchingEnrollment = tei.enrollments.find((enrollment) => enrollment.program === programId);
4066
- return matchingEnrollment
4067
- ? matchingEnrollment.attributes
4068
- : tei.attributes;
4069
- })
4070
- .find((attr) => attr.attribute === attrId);
4071
- // Find the corresponding attribute in mappedProgramMetadataAttributes
4072
- const mappedAttr = mappedProgramMetadataAttributes.find((attr) => attr.id === attrId);
4073
- return {
4074
- label: foundAttribute?.displayName || attrId,
4075
- key: attrId,
4076
- valueType: foundAttribute?.valueType,
4077
- options: mappedAttr?.optionSet ?? undefined,
4078
- };
4079
- })
4080
- .filter((column) => {
4081
- return mappedProgramMetadataAttributes
4082
- .filter((attr) => attr.displayInList)
4083
- .some((attr) => attr.id === column.key);
4084
- })
4085
- .sort((a, b) => {
4086
- const sortOrderA = Number(mappedProgramMetadataAttributes.find((attr) => attr.id === a.key)
4087
- ?.sortOrder ?? 0);
4088
- const sortOrderB = Number(mappedProgramMetadataAttributes.find((attr) => attr.id === b.key)
4089
- ?.sortOrder ?? 0);
4090
- return sortOrderA - sortOrderB;
4091
- })
4092
- .filter((column) => searchableKeys.has(column.key));
4093
- const attributesData = teis.map((tei, idx) => {
4094
- const row = {
4095
- trackedEntityInstance: tei.trackedEntity,
4096
- index: (pager.page - 1) * pager.pageSize + idx + 1,
4097
- };
4098
- allAttributes.forEach((attrId) => (row[attrId] = ''));
4099
- const matchingEnrollment = tei.enrollments.find((enrollment) => enrollment.program === programId);
4100
- let attributesToUse = matchingEnrollment
4101
- ? matchingEnrollment.attributes
4102
- : tei.attributes;
4103
- //TODO: find a better way to do optimize this date parsing
4104
- //map any date that occur in the attributes to dd-mm-yyyy
4105
- attributesToUse = attributesToUse.map((attr) => {
4106
- // Check if the attribute is of type DATE
4107
- if (attr?.valueType === 'DATE' || attr?.valueType === 'date') {
4108
- try {
4109
- // Parse the date and format it as dd-MM-yyyy
4110
- const parsedDate = parse$1(attr.value, 'yyyy-MM-dd', new Date());
4111
- const formattedDate = format(parsedDate, 'dd-MM-yyyy');
4112
- // Update the value to the formatted date
4113
- return {
4114
- ...attr,
4115
- value: formattedDate,
4116
- };
4117
- }
4118
- catch {
4119
- // If parsing fails, keep the original value
4120
- return {
4121
- ...attr,
4122
- value: attr.value,
4123
- };
4124
- }
4125
- }
4126
- // If not a date, just return the attribute as is
4127
- return attr;
4128
- });
4129
- // If option set names are visible, transform the attribute values
4130
- if (isOptionSetNameVisible) {
4131
- attributesToUse.forEach((attr) => {
4132
- const attributeMeta = programMetaData.find((metadata) => metadata.trackedEntityAttribute.id === attr.attribute);
4133
- // Check if the attribute has an option set and map value to option name
4134
- if (attributeMeta?.trackedEntityAttribute.optionSetValue) {
4135
- const optionSet = attributeMeta?.trackedEntityAttribute?.optionSet;
4136
- const option = optionSet?.options?.find((option) => option.code === attr.value);
4137
- row[attr.attribute] = option ? option.name : attr.value;
4138
- }
4139
- else {
4140
- row[attr.attribute] = attr.value;
4141
- }
4142
- });
4143
- }
4144
- else {
4145
- attributesToUse.forEach((attr) => (row[attr.attribute] = attr.value));
4146
- }
4147
- // Include orgUnit in the row for id access
4148
- row['orgUnitId'] = matchingEnrollment.orgUnit;
4149
- row['orgUnit'] = orgUnitMap?.get(matchingEnrollment.orgUnit) || 'N/A';
4150
- return row;
4151
- });
4152
- if (teis.length === 0) {
4153
- entityColumns = [
4154
- { label: orgUnitLabel || 'registering unit', key: 'orgUnit' },
4155
- ...mappedProgramMetadataAttributes
4156
- .filter((attr) => attr.displayInList === true)
4157
- .sort((a, b) => {
4158
- return Number(a.sortOrder) - Number(b.sortOrder);
4159
- })
4160
- .map((attr) => ({
4161
- key: attr.id,
4162
- label: attr.name,
4163
- })),
4164
- ];
4165
- }
4166
- return {
4167
- columns: entityColumns,
4168
- data: attributesData,
4169
- filteredEntityColumns: filteredEntityColumns,
4170
- orgUnitLabel: orgUnitLabel,
4171
- };
4172
- };
4173
- // export const getEventData = (
4174
- // response: LineListResponse,
4175
- // pager: any,
4176
- // isOptionSetNameVisible: boolean
4177
- // ): { columns: ColumnDefinition[]; data: TableRow[] } => {
4178
- // const events = (response.data as EventsResponse).events;
4179
- // const uniqueDataElements = new Set<string>();
4180
- // events?.forEach((event: any) => {
4181
- // event?.dataValues.forEach((dv: any) =>
4182
- // uniqueDataElements.add(dv.dataElement)
4183
- // );
4184
- // });
4185
- // const entityColumns = Array.from(uniqueDataElements).map(
4186
- // (dataElement: string) => ({
4187
- // label:
4188
- // response.metadata.programStages[0].programStageDataElements.find(
4189
- // (psde: any) => psde.dataElement.id === dataElement
4190
- // )?.dataElement.name || dataElement,
4191
- // key: dataElement,
4192
- // })
4193
- // );
4194
- // const dataElementsData = events.map((event: any, idx: number) => {
4195
- // const row: TableRow = {
4196
- // event: event.event,
4197
- // index: (pager.page - 1) * pager.pageSize + idx + 1,
4198
- // };
4199
- // uniqueDataElements.forEach(
4200
- // (dataElement: string) => (row[dataElement] = '')
4201
- // );
4202
- // event.dataValues.forEach((dv: any) => {
4203
- // if (isOptionSetNameVisible) {
4204
- // return (row[dv.dataElement] = dv.value)
4205
- // } else {
4206
- // return (row[dv.dataElement] = dv.value)
4207
- // }
4208
- // });
4209
- // return row;
4210
- // });
4211
- // return { columns: entityColumns, data: dataElementsData };
4212
- // };
4213
- const getEventData = (response, pager, isOptionSetNameVisible) => {
4214
- const events = response.data.events;
4215
- const uniqueDataElements = new Set();
4216
- events?.forEach((event) => {
4217
- event?.dataValues.forEach((dv) => uniqueDataElements.add(dv.dataElement));
4218
- });
4219
- const entityColumns = Array.from(uniqueDataElements).map((dataElement) => ({
4220
- label: response.metadata.programStages[0].programStageDataElements.find((psde) => psde.dataElement.id === dataElement)?.dataElement.name || dataElement,
4221
- key: dataElement,
4222
- }));
4223
- const dataElementsData = events.map((event, idx) => {
4224
- const row = {
4225
- event: event.event,
4226
- index: (pager.page - 1) * pager.pageSize + idx + 1,
4227
- };
4228
- uniqueDataElements.forEach((dataElement) => (row[dataElement] = ''));
4229
- event.dataValues.forEach((dv) => {
4230
- if (isOptionSetNameVisible && dv.optionSetValue) {
4231
- const dataElementMetadata = response.metadata.programStages
4232
- .flatMap((programStage) => programStage.programStageDataElements)
4233
- .find((psde) => psde.dataElement.id === dv.dataElement)
4234
- ?.dataElement.optionSet;
4235
- if (dataElementMetadata && dataElementMetadata.options) {
4236
- const matchingOption = dataElementMetadata.options.find((option) => option.code === dv.value);
4237
- if (matchingOption) {
4238
- row[dv.dataElement] = matchingOption.name;
4239
- }
4240
- else {
4241
- row[dv.dataElement] = dv.value;
4242
- }
4243
- }
4244
- else {
4245
- row[dv.dataElement] = dv.value;
4246
- }
4247
- }
4248
- else {
4249
- row[dv.dataElement] = dv.value;
4250
- }
4251
- });
4252
- return row;
4253
- });
4254
- return { columns: entityColumns, data: dataElementsData };
4255
- };
4256
- const addActionsColumn = (columns, actionOptions) => {
4257
- return [
4258
- ...columns,
4259
- ...(actionOptions && actionOptions.length > 0
4260
- ? [{ label: 'Actions', key: 'actions' }]
4261
- : []),
4262
- ];
4263
- };
3681
+ const OrgUnitSelector = ({ hide, setHide, selectedOrgUnit, setSelectedOrgUnit, setOrgUnitState, }) => (React__default.createElement(Modal$1, { hide: hide, position: "middle" },
3682
+ React__default.createElement(ModalTitle$1, null, "Select organization unit"),
3683
+ React__default.createElement(ModalContent$1, null,
3684
+ React__default.createElement(OrgUnitFormField$1, { key: selectedOrgUnit, onSelectOrgUnit: (selectedOrgUnit) => {
3685
+ setSelectedOrgUnit(selectedOrgUnit.displayName);
3686
+ setOrgUnitState(selectedOrgUnit.id);
3687
+ setHide(true);
3688
+ } })),
3689
+ React__default.createElement(ModalActions$1, null,
3690
+ React__default.createElement(ButtonStrip$1, { end: true },
3691
+ React__default.createElement(Button$1, { onClick: () => setHide(true), secondary: true }, "Close")))));
4264
3692
 
4265
3693
  // src/app/line-list-table.component.ts
4266
3694
  class LineListTableComponent extends ReactWrapperModule {
4267
3695
  constructor() {
4268
3696
  super(...arguments);
4269
3697
  this.actionOptionOrientation = 'DROPDOWN';
4270
- this.dispatchTeis = false;
4271
3698
  this.actionSelected = new EventEmitter();
4272
3699
  this.reactStateUpdaters = null;
4273
3700
  this.approvalSelected = new EventEmitter();
4274
3701
  this.isButtonLoading = false;
4275
- this.buttonLabel = '';
4276
- this.firstValue = new EventEmitter();
4277
3702
  this.filterRootOrgUnit = false;
4278
3703
  this.showFilters = false;
4279
3704
  this.isOptionSetNameVisible = false;
@@ -4284,29 +3709,25 @@ class LineListTableComponent extends ReactWrapperModule {
4284
3709
  this.LineList = () => {
4285
3710
  const [columns, setColumns] = useState([]);
4286
3711
  const [data, setData] = useState([]);
4287
- const [pager, setPager] = useState({
3712
+ const [pager, setPager] = useState(new Pager({
4288
3713
  page: 1,
4289
3714
  pageSize: 10,
4290
3715
  total: 0,
4291
3716
  pageCount: 1,
4292
- });
4293
- const paginationRef = useRef(null);
3717
+ }));
4294
3718
  const [programIdState, setProgramIdState] = useState(this.programId);
4295
3719
  const [isOptionSetNameVisibleState, setOptionSetNameVisible] = useState(this.isOptionSetNameVisible);
4296
3720
  const [orgUnitState, setOrgUnitState] = useState(this.orgUnit);
4297
3721
  const [programStageIdState, setProgramStageIdState] = useState(this.programStageId);
4298
3722
  const [attributeFiltersState, setAttributeFiltersState] = useState(this.attributeFilters);
3723
+ const [dataQueryFiltersState, setDataQueryFiltersState] = useState(this.dataQueryFilters);
4299
3724
  const [startDateState, setStartDateState] = useState(this.startDate);
4300
3725
  const [endDateState, setEndDateState] = useState(this.endDate);
4301
3726
  const [loading, setLoading] = useState(false);
4302
- const [isButtonLoading, setIsButtonLoading] = useState(this.isButtonLoading);
3727
+ const [metaDataLoadng, setMetaDataLoading] = useState(false);
4303
3728
  const [filteredColumns, setFilteredColumns] = useState();
4304
3729
  const [inputValues, setInputValues] = useState({});
4305
- const [filters, setFilters] = useState(false);
4306
3730
  const [orgUnitLabel, setOrgUnitLabel] = useState('');
4307
- //TODO: this will be migrated on the parent component
4308
- const [checkValue, setCheckValue] = useState([]);
4309
- const [valueMatch, setValuesMatch] = useState(false);
4310
3731
  const [selectedOrgUnit, setSelectedOrgUnit] = useState('');
4311
3732
  const [hide, setHide] = useState(true);
4312
3733
  const [showAllFilters, setShowAllFilters] = useState(false);
@@ -4316,6 +3737,8 @@ class LineListTableComponent extends ReactWrapperModule {
4316
3737
  const defaultOrgUnit = this.orgUnit;
4317
3738
  const [prevValue, setPrevValue] = useState();
4318
3739
  const [dateStates, setDateStates] = useState({});
3740
+ const [metaData, setMetaData] = useState(null);
3741
+ const d2 = window.d2Web;
4319
3742
  // Store updaters in refs for Angular to access
4320
3743
  const updateRefs = useRef({
4321
3744
  setProgramIdState,
@@ -4324,7 +3747,6 @@ class LineListTableComponent extends ReactWrapperModule {
4324
3747
  setAttributeFiltersState,
4325
3748
  setStartDateState,
4326
3749
  setEndDateState,
4327
- setIsButtonLoading,
4328
3750
  setOptionSetNameVisible,
4329
3751
  });
4330
3752
  useEffect(() => {
@@ -4332,64 +3754,83 @@ class LineListTableComponent extends ReactWrapperModule {
4332
3754
  }, []);
4333
3755
  useEffect(() => {
4334
3756
  setLoading(true);
4335
- const subscription = this.lineListService
4336
- .getLineListData(this.programId, orgUnitState, this.programStageId, pager.page, pager.pageSize, attributeFiltersState, startDateState, endDateState, this.ouMode, this.filterRootOrgUnit, this.useOuModeWithOlderDHIS2Instance, this.filters)
4337
- .pipe(take(1)) // Automatically unsubscribe after the first emission
4338
- .subscribe((response) => {
4339
- let entityColumns = [];
4340
- let responsePager;
4341
- let entityData = [];
4342
- let filteredDataColumns = [];
4343
- if (this.programStageId) {
4344
- responsePager = response.data.pager;
4345
- const { columns, data } = getProgramStageData(response, this.programStageId, pager, this.isOptionSetNameVisible);
4346
- entityColumns = columns;
4347
- entityData = data;
4348
- }
4349
- else if ('trackedEntities' in response.data ||
4350
- 'instances' in response.data) {
4351
- const responseData = response.data;
4352
- responsePager = responseData.pager || {
4353
- page: responseData.page,
4354
- pageSize: responseData.pageSize,
4355
- total: responseData.total,
4356
- pageCount: responseData.pageCount,
4357
- };
4358
- const { columns, data, filteredEntityColumns, orgUnitLabel } = getTrackedEntityData(response, this.programId, pager, this.isOptionSetNameVisible, this.filters);
4359
- entityColumns = columns;
4360
- entityData = data;
4361
- setOrgUnitLabel(orgUnitLabel);
4362
- const checkValues = [
4363
- ...new Set(responseData?.trackedEntities?.[0]?.enrollments?.[0]?.events?.flatMap((event) => event.dataValues
4364
- .filter((dataValue) => /^[A-Za-z]{3}$/.test(dataValue.value))
4365
- .map((dataValue) => dataValue.value)) ??
4366
- responseData?.instances?.[0]?.enrollments?.[0]?.events?.flatMap((event) => event.dataValues
4367
- .filter((dataValue) => /^[A-Za-z]{3}$/.test(dataValue.value))
4368
- .map((dataValue) => dataValue.value))),
4369
- ];
4370
- if (checkValues.length > 0) {
4371
- setCheckValue(checkValues);
4372
- setValuesMatch(!checkValues.includes(this.buttonFilter));
4373
- }
4374
- setFilteredColumns((prev) => filteredEntityColumns.length > 0 ? filteredEntityColumns : prev);
4375
- filteredDataColumns = filteredEntityColumns;
3757
+ const fetchmetaData = async () => {
3758
+ try {
3759
+ const trackerResponse = (await d2.trackerModule.trackedEntity
3760
+ .setProgram(this.programId)
3761
+ .getMetaData());
3762
+ const data = trackerResponse;
3763
+ setMetaData(data);
4376
3764
  }
4377
- else {
4378
- responsePager = response.data.pager;
4379
- const { columns, data } = getEventData(response, pager, this.isOptionSetNameVisible);
4380
- entityColumns = columns;
4381
- entityData = data;
3765
+ catch (error) {
3766
+ console.error('Failed to metadata:', error);
4382
3767
  }
4383
- const finalColumns = addActionsColumn([{ label: '#', key: 'index' }, ...entityColumns], this.actionOptions);
4384
- setLoading(false);
4385
- setColumns(finalColumns);
4386
- setData(entityData);
4387
- setPager(responsePager);
4388
- });
4389
- return () => {
4390
- subscription.unsubscribe(); // Ensure cleanup on unmount
4391
3768
  };
3769
+ if (this.programId) {
3770
+ fetchmetaData();
3771
+ }
3772
+ }, []);
3773
+ useEffect(() => {
3774
+ if (!metaData) {
3775
+ return undefined;
3776
+ }
3777
+ setLoading(true);
3778
+ const isTracker = metaData.programType === 'WITH_REGISTRATION';
3779
+ const endDate = endDateState ?? new Date().toISOString().split('T')[0];
3780
+ if (isTracker) {
3781
+ d2.trackerModule.trackedEntity
3782
+ .setEndDate(endDate)
3783
+ .setStartDate(startDateState)
3784
+ .setProgram(this.programId)
3785
+ .setOrgUnit(orgUnitState)
3786
+ .setOuMode(this.ouMode)
3787
+ .setFilters(dataQueryFiltersState)
3788
+ .setPagination(new Pager({
3789
+ pageSize: pager.pageSize,
3790
+ page: pager.page,
3791
+ }))
3792
+ .setOrderCriterias([
3793
+ new DataOrderCriteria().setField('createdAt').setOrder('desc'),
3794
+ ])
3795
+ .get()
3796
+ .then((response) => {
3797
+ const trackedEntityInstances = Array.isArray(response.data)
3798
+ ? response.data
3799
+ : [response.data];
3800
+ const orgUnitIdsFromEnrollments = new Set(trackedEntityInstances.map((tei) => tei.latestEnrollment.orgUnit));
3801
+ const uniqueOrgUnitIds = [...orgUnitIdsFromEnrollments];
3802
+ this.lineListService.fetchOrgUnits(uniqueOrgUnitIds).subscribe({
3803
+ next: (fetchedOrgUnits) => {
3804
+ const trackedEntityResponse = {
3805
+ trackedEntityInstances: response.data,
3806
+ pager: pager,
3807
+ orgUnitsMap: fetchedOrgUnits,
3808
+ };
3809
+ const { columns, data, filteredEntityColumns, orgUnitLabel } = getTrackedEntityTableData({ data: trackedEntityResponse }, this.programId, pager, metaData);
3810
+ setFilteredColumns((prev) => filteredEntityColumns.length > 0
3811
+ ? filteredEntityColumns
3812
+ : prev);
3813
+ const finalColumns = addActionsColumn([{ label: '#', key: 'index' }, ...columns], this.actionOptions);
3814
+ const pagerResponse = response.pagination;
3815
+ setLoading(false);
3816
+ setColumns(finalColumns);
3817
+ setData(data);
3818
+ setPager(new Pager(pagerResponse || {}));
3819
+ setOrgUnitLabel(orgUnitLabel);
3820
+ },
3821
+ error: (err) => {
3822
+ console.error('Error fetching org units:', err);
3823
+ setLoading(false);
3824
+ },
3825
+ });
3826
+ });
3827
+ }
3828
+ else {
3829
+ //TODO: TO IMPLEMEMNT EVENT QUERY FOR FILTERING EVENTS WHEN PROGRAM STAGE IS PASSED OR DEALING WITH EVENT PROGRAM USING TRACKER SDK QUERY
3830
+ }
3831
+ ;
4392
3832
  }, [
3833
+ metaData,
4393
3834
  programIdState,
4394
3835
  orgUnitState,
4395
3836
  programStageIdState,
@@ -4399,50 +3840,25 @@ class LineListTableComponent extends ReactWrapperModule {
4399
3840
  pager.page,
4400
3841
  pager.pageSize,
4401
3842
  isOptionSetNameVisibleState,
3843
+ dataQueryFiltersState,
4402
3844
  ]);
4403
- const handleApprovalClick = () => {
4404
- setIsButtonLoading(true);
4405
- const subscription = this.lineListService
4406
- .getLineListData(this.programId, this.orgUnit, this.programStageId, pager.page, 1000, this.attributeFilters, this.startDate, this.endDate, this.ouMode)
4407
- .pipe(take(1))
4408
- .subscribe((response) => {
4409
- if ('trackedEntities' in response.data ||
4410
- 'instances' in response.data) {
4411
- const trackedEntityInstances = response.data.trackedEntities;
4412
- // Map TEIs to objects with teiId and enrollmentId
4413
- const teiEnrollmentList = trackedEntityInstances
4414
- .map((tei) => {
4415
- const matchingEnrollment = tei.enrollments?.find((enrollment) => enrollment.program === this.programId);
4416
- return matchingEnrollment
4417
- ? {
4418
- teiId: tei.trackedEntity,
4419
- enrollmentId: matchingEnrollment.enrollment,
4420
- }
4421
- : null;
4422
- })
4423
- .filter(Boolean);
4424
- this.approvalSelected.emit(teiEnrollmentList);
4425
- }
4426
- else {
4427
- this.approvalSelected.emit([]);
4428
- }
4429
- setIsButtonLoading(false);
4430
- });
4431
- return () => {
4432
- subscription.unsubscribe();
4433
- };
4434
- };
4435
3845
  const handleInputChange = (key, value) => {
4436
3846
  setInputValues((prevValues) => ({
4437
3847
  ...prevValues,
4438
3848
  [key]: value ?? '',
4439
3849
  }));
4440
- setAttributeFiltersState((prevFilters = []) => {
3850
+ setDataQueryFiltersState((prevFilters) => {
4441
3851
  // Remove old filter for this key
4442
3852
  const filteredFilters = prevFilters.filter((f) => f.attribute !== key);
4443
3853
  // Only add new filter if value is not empty
4444
3854
  const updatedFilters = value.trim()
4445
- ? [...filteredFilters, { attribute: key, operator: 'like', value }]
3855
+ ? [
3856
+ ...filteredFilters,
3857
+ new DataQueryFilter()
3858
+ .setAttribute(key)
3859
+ .setCondition(DataFilterCondition.Like)
3860
+ .setValue(value),
3861
+ ]
4446
3862
  : filteredFilters;
4447
3863
  return updatedFilters;
4448
3864
  });
@@ -4453,175 +3869,69 @@ class LineListTableComponent extends ReactWrapperModule {
4453
3869
  ...prevValues,
4454
3870
  [key]: value ?? '',
4455
3871
  }));
4456
- setAttributeFiltersState((prevFilters = []) => {
4457
- // Remove old filter for this key
3872
+ setDataQueryFiltersState((prevFilters = []) => {
3873
+ // Remove existing filter for the same key (attribute)
4458
3874
  const filteredFilters = prevFilters.filter((f) => f.attribute !== key);
4459
3875
  // Only add new filter if value is not empty
4460
3876
  const updatedFilters = value.trim()
4461
- ? [...filteredFilters, { attribute: key, operator: 'eq', value }]
3877
+ ? [
3878
+ ...filteredFilters,
3879
+ new DataQueryFilter()
3880
+ .setAttribute(key)
3881
+ .setCondition(DataFilterCondition.Equal)
3882
+ .setValue(value),
3883
+ ]
4462
3884
  : filteredFilters;
4463
3885
  return updatedFilters;
4464
3886
  });
4465
3887
  };
4466
3888
  const handleDateSelect = (key, selectedDate) => {
4467
- const selectedDateString = selectedDate?.calendarDateString ?? ''; // Default to empty string if null
3889
+ const selectedDateString = selectedDate?.calendarDateString ?? '';
4468
3890
  // Update dateStates
4469
3891
  setDateStates((prevDateStates) => ({
4470
3892
  ...prevDateStates,
4471
- [key]: selectedDateString, // Will set it to empty if date is cleared
3893
+ [key]: selectedDateString,
4472
3894
  }));
4473
- // Update attributeFiltersState to remove filter if date is cleared
4474
- setAttributeFiltersState((prevFilters = []) => {
4475
- // Remove old filter for this key if the date is empty
4476
- const filteredFilters = prevFilters.filter((f) => f.attribute !== key);
4477
- // Only add a filter if the date is not empty
3895
+ // Update dataQueryFilters
3896
+ setDataQueryFiltersState((prevFilters) => {
3897
+ const filteredFilters = (prevFilters || []).filter((f) => f.attribute !== key);
4478
3898
  const updatedFilters = selectedDateString.trim()
4479
3899
  ? [
4480
3900
  ...filteredFilters,
4481
- { attribute: key, operator: 'like', value: selectedDateString },
3901
+ new DataQueryFilter()
3902
+ .setAttribute(key)
3903
+ .setCondition(DataFilterCondition.Equal)
3904
+ .setValue(selectedDateString),
4482
3905
  ]
4483
- : filteredFilters; // If empty, just keep the filteredFilters as they are
3906
+ : filteredFilters;
4484
3907
  return updatedFilters;
4485
3908
  });
4486
3909
  };
4487
- return (React__default.createElement("div", null,
4488
- React__default.createElement("div", null, valueMatch &&
4489
- this.dispatchTeis &&
4490
- (isButtonLoading ? (React__default.createElement(CircularLoader$1, { small: true })) : (
4491
- //TODO: this implementation should be done where the library will be consumed
4492
- React__default.createElement(Button$1, { style: {
4493
- backgroundColor: '#3b82f6',
4494
- color: 'white',
4495
- padding: '8px 16px',
4496
- borderRadius: '4px',
4497
- cursor: 'pointer',
4498
- }, onClick: handleApprovalClick, primary: true }, this.buttonLabel)))),
4499
- loading ? (React__default.createElement("div", { style: {
4500
- display: 'flex',
4501
- alignItems: 'center',
4502
- gap: 8,
4503
- padding: 8,
4504
- } },
4505
- React__default.createElement(CircularLoader$1, { small: true }),
4506
- React__default.createElement("div", { style: {
4507
- fontSize: 14,
4508
- } }, "Loading"))) : (
4509
- // <div>
4510
- // <div/>
4511
- React__default.createElement("div", null,
4512
- React__default.createElement(Modal$1, { hide: hide, position: "middle" },
4513
- React__default.createElement(ModalTitle$1, null, "Select organization unit"),
4514
- React__default.createElement(ModalContent$1, null,
4515
- React__default.createElement(OrgUnitFormField$1, { key: selectedOrgUnit, onSelectOrgUnit: (selectedOrgUnit) => {
4516
- setSelectedOrgUnit(selectedOrgUnit.displayName);
4517
- setOrgUnitState(selectedOrgUnit.id);
4518
- setHide(true);
4519
- } })),
4520
- React__default.createElement(ModalActions$1, null,
4521
- React__default.createElement(ButtonStrip$1, { end: true },
4522
- React__default.createElement(Button$1, { onClick: () => setHide(true), secondary: true }, "Close")))),
4523
- this.showFilters && (React__default.createElement(DataTableToolbar, { className: "table-top-toolbar" },
4524
- React__default.createElement("div", { style: {
4525
- display: 'flex',
4526
- alignItems: 'center',
4527
- gap: '10px',
4528
- flexWrap: 'wrap',
4529
- } },
4530
- React__default.createElement(InputField$1, { key: "location",
4531
- //label={orgUnitLabel}
4532
- label: orgUnitLabel ? orgUnitLabel : 'registering unit', value: selectedOrgUnit, onFocus: () => setHide(false), className: "custom-input", onChange: (event) => {
4533
- setSelectedOrgUnit(event.value);
4534
- setOrgUnitState(defaultOrgUnit);
4535
- } }),
4536
- React__default.createElement(CalendarInput, { label: "Start date:", calendar: "gregory", locale: "en-GB", timeZone: "Africa/Dar_es_Salaam", className: "custom-input", date: startDateState, onDateSelect: (selectedDate) => {
4537
- if (selectedDate?.calendarDateString) {
4538
- setStartDateState(selectedDate.calendarDateString);
4539
- }
4540
- // setStartDateState(selectedDate.calendarDateString);
4541
- } }),
4542
- React__default.createElement(CalendarInput, { label: "End date:", calendar: "gregory", locale: "en-GB", timeZone: "Africa/Dar_es_Salaam", className: "custom-input", date: endDateState, onDateSelect: (selectedDate) => {
4543
- setEndDateState(selectedDate.calendarDateString);
4544
- } }),
4545
- (visibleFilters ?? []).map(({ label, key, valueType, options }) => {
4546
- // Render CalendarInput for DATE fields
4547
- if (valueType === 'DATE') {
4548
- return (React__default.createElement(CalendarInput, { key: key, label: `${label}:`, calendar: "gregory", locale: "en-GB", timeZone: "Africa/Dar_es_Salaam", className: "custom-input", date: dateStates[key] || '', onDateSelect: (selectedDate) => handleDateSelect(key, selectedDate) }));
4549
- }
4550
- // Render SingleSelectField if options exist
4551
- if (options && options.options.length > 0) {
4552
- return (React__default.createElement(SingleSelectField, { key: key, label: `${label}:`, selected: inputValues[key] || '', className: "custom-select-input", clearable: true, onChange: ({ selected }) => {
4553
- setInputValues((prevValues) => ({
4554
- ...prevValues,
4555
- [key]: selected ?? '',
4556
- }));
4557
- handleInputChangeForSelectField(key, selected ?? '');
4558
- } }, (options.options ?? []).map((opt) => (React__default.createElement(SingleSelectOption, { key: opt.id, label: opt.name, value: opt.code })))));
4559
- }
4560
- // Fallback: default InputField
4561
- return (React__default.createElement(InputField$1, { key: key, label: `${label}:`, className: "custom-input", value: inputValues[key] || '', clearable: true, onChange: (e) => {
4562
- let currentValue = '';
4563
- if ('target' in e && e.target) {
4564
- currentValue = e.target.value;
4565
- }
4566
- else if ('value' in e) {
4567
- currentValue = e.value ?? '';
4568
- }
4569
- setInputValues((prevValues) => ({
4570
- ...prevValues,
4571
- [key]: currentValue,
4572
- }));
4573
- if (currentValue === '') {
4574
- handleInputChange(key, '');
4575
- }
4576
- }, onBlur: (e) => {
4577
- let currentValue = '';
4578
- if ('target' in e && e.target) {
4579
- currentValue = e.target.value;
4580
- }
4581
- else if ('value' in e) {
4582
- currentValue = e.value ?? '';
4583
- }
4584
- if (currentValue !== '' &&
4585
- currentValue !== prevValue) {
4586
- handleInputChange(key, currentValue);
4587
- setPrevValue(currentValue);
4588
- }
4589
- } }));
4590
- }),
4591
- React__default.createElement(Button$1, { onClick: () => setShowAllFilters(!showAllFilters) }, showAllFilters ? 'Less Filters' : 'More Filters')))),
4592
- React__default.createElement(DataTable, null,
4593
- React__default.createElement(TableHead, null,
4594
- React__default.createElement(DataTableRow, null, columns.map((col) => (React__default.createElement(DataTableColumnHeader, { key: col.key }, col.label))))),
4595
- React__default.createElement(TableBody, null, data.length > 0 ? (data.map((row) => (React__default.createElement(DataTableRow, { key: row.index }, columns.map((col) => (React__default.createElement(DataTableCell, { key: col.key }, col.key === 'actions'
4596
- ? this.actionOptions && (React__default.createElement(DataTableActions, { actionOptions: this.actionOptions, actionOptionOrientation: this.actionOptionOrientation, onClick: (option) => {
4597
- if (option.onClick) {
4598
- option.onClick(row);
4599
- }
4600
- this.actionSelected.emit({
4601
- action: option.label,
4602
- row,
4603
- });
4604
- } }))
4605
- : row[col.key] || '--' // Display '--' if value is undefined or null
4606
- ))))))) : (React__default.createElement(DataTableRow, null,
4607
- React__default.createElement(DataTableCell, { colSpan: columns.length?.toString(), style: {
4608
- textAlign: 'center',
4609
- fontWeight: 'bold',
4610
- color: 'grey',
4611
- padding: '20px',
4612
- } }, "No data found")))),
4613
- React__default.createElement(TableFoot, null,
4614
- React__default.createElement(DataTableRow, null,
4615
- React__default.createElement(DataTableCell, { colSpan: columns.length.toString() },
4616
- React__default.createElement("div", null,
4617
- React__default.createElement(Pagination, { page: pager.page, pageCount: pager.pageCount, pageSize: pager.pageSize, total: pager.total, onPageChange: (page) => setPager((prev) => ({ ...prev, page })), onPageSizeChange: (pageSize) => {
4618
- const newPageSize = Number(pageSize);
4619
- setPager((prev) => ({
4620
- ...prev,
4621
- page: 1,
4622
- pageSize: newPageSize,
4623
- }));
4624
- }, pageSizes: ['10', '20', '50', '100', '500'] }))))))))));
3910
+ function getTextColorFromBackGround(hex) {
3911
+ // Remove the hash if present
3912
+ hex = hex.replace('#', '');
3913
+ // Convert to RGB
3914
+ const r = parseInt(hex.substr(0, 2), 16);
3915
+ const g = parseInt(hex.substr(2, 2), 16);
3916
+ const b = parseInt(hex.substr(4, 2), 16);
3917
+ // YIQ formula to calculate brightness
3918
+ const yiq = (r * 299 + g * 587 + b * 114) / 1000;
3919
+ // Return black for light backgrounds, white for dark backgrounds
3920
+ return yiq >= 128 ? colors$1.grey700 : '#FFFFFF';
3921
+ }
3922
+ return (React__default.createElement("div", null, loading ? (React__default.createElement("div", { style: {
3923
+ display: 'flex',
3924
+ alignItems: 'center',
3925
+ gap: 8,
3926
+ padding: 8,
3927
+ } },
3928
+ React__default.createElement(CircularLoader$1, { small: true }),
3929
+ React__default.createElement("div", { style: {
3930
+ fontSize: 14,
3931
+ } }, "Loading"))) : (React__default.createElement("div", null,
3932
+ React__default.createElement(OrgUnitSelector, { hide: hide, setHide: setHide, selectedOrgUnit: selectedOrgUnit, setSelectedOrgUnit: setSelectedOrgUnit, setOrgUnitState: setOrgUnitState }),
3933
+ this.showFilters && (React__default.createElement(FilterToolbar, { orgUnitLabel: orgUnitLabel, selectedOrgUnit: selectedOrgUnit, setSelectedOrgUnit: setSelectedOrgUnit, setOrgUnitState: setOrgUnitState, defaultOrgUnit: defaultOrgUnit, setHide: setHide, startDateState: startDateState, setStartDateState: setStartDateState, endDateState: endDateState, setEndDateState: setEndDateState, visibleFilters: visibleFilters, dateStates: dateStates, inputValues: inputValues, setInputValues: setInputValues, handleInputChange: handleInputChange, handleInputChangeForSelectField: handleInputChangeForSelectField, handleDateSelect: handleDateSelect, prevValue: prevValue, setPrevValue: setPrevValue, showAllFilters: showAllFilters, setShowAllFilters: setShowAllFilters })),
3934
+ React__default.createElement(LineListTable, { columns: columns, data: data, pager: pager, setPager: setPager, getTextColorFromBackGround: getTextColorFromBackGround, actionOptions: this.actionOptions, actionOptionOrientation: this.actionOptionOrientation, actionSelected: this.actionSelected })))));
4625
3935
  };
4626
3936
  }
4627
3937
  ngOnChanges(changes) {
@@ -4660,7 +3970,7 @@ class LineListTableComponent extends ReactWrapperModule {
4660
3970
  this.render();
4661
3971
  }
4662
3972
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: LineListTableComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
4663
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.8", type: LineListTableComponent, isStandalone: false, selector: "ng-dhis2-ui-line-list", inputs: { programId: "programId", orgUnit: "orgUnit", programStageId: "programStageId", actionOptions: "actionOptions", actionOptionOrientation: "actionOptionOrientation", attributeFilters: "attributeFilters", useOuModeWithOlderDHIS2Instance: "useOuModeWithOlderDHIS2Instance", startDate: "startDate", endDate: "endDate", filters: "filters", ouMode: "ouMode", dispatchTeis: "dispatchTeis", isButtonLoading: "isButtonLoading", buttonLabel: "buttonLabel", buttonFilter: "buttonFilter", filterRootOrgUnit: "filterRootOrgUnit", showFilters: "showFilters", isOptionSetNameVisible: "isOptionSetNameVisible" }, outputs: { actionSelected: "actionSelected", approvalSelected: "approvalSelected", firstValue: "firstValue" }, usesInheritance: true, usesOnChanges: true, ngImport: i0, template: '<ng-content></ng-content>', isInline: true, styles: ["::ng-deep .custom-input{display:flex!important;gap:4px!important;align-items:center!important;border:1px solid #9fadba!important;border-radius:4px!important;margin:0;padding:0 0 0 8px;background-color:#fff!important}::ng-deep .custom-input div{margin:0!important}::ng-deep .custom-input label{font-size:12px;padding-right:0}::ng-deep .custom-input input{border:none!important;font-size:12px!important;display:flex;align-items:center;padding-left:4px;height:40px;outline:none!important;box-shadow:none!important}::ng-deep .custom-input input:focus{border:none!important;box-shadow:none!important}::ng-deep .custom-input [data-test=calendar-clear-button]{background-color:#f2f2f2!important;color:#870808!important;border-radius:6px!important;padding:4px 10px!important;font-size:14px!important}::ng-deep .custom-input [data-test=calendar-clear-button]:hover{background-color:#ddd}::ng-deep .custom-input label{color:gray!important;opacity:1}::ng-deep .table-top-toolbar{background-color:var(--colors-grey100)!important;color:var(--colors-grey900)!important}::ng-deep .custom-select-input{display:flex!important;gap:4px!important;align-items:center!important;border:1px solid #9fadba!important;border-radius:4px!important;margin:0;padding:0 0 0 8px;background-color:#fff!important}::ng-deep .custom-select-input div{margin:0!important}::ng-deep .custom-select-input [data-test=dhis2-uiwidgets-singleselectfield-label]{font-size:12px;color:gray!important}::ng-deep .custom-select-input [data-test=dhis2-uicore-select-input]{border:none!important;font-size:12px!important;display:flex;align-items:center;padding-left:4px;height:40px;outline:none!important;box-shadow:none!important}::ng-deep .custom-select-input [data-test=dhis2-uicore-select-input]:focus-within{box-shadow:none!important}::ng-deep .custom-select-input input:focus{border:none!important;box-shadow:none!important}\n"] }); }
3973
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.8", type: LineListTableComponent, isStandalone: false, selector: "ng-dhis2-ui-line-list", inputs: { programId: "programId", orgUnit: "orgUnit", programStageId: "programStageId", actionOptions: "actionOptions", actionOptionOrientation: "actionOptionOrientation", attributeFilters: "attributeFilters", useOuModeWithOlderDHIS2Instance: "useOuModeWithOlderDHIS2Instance", startDate: "startDate", endDate: "endDate", dataQueryFilters: "dataQueryFilters", ouMode: "ouMode", isButtonLoading: "isButtonLoading", buttonFilter: "buttonFilter", filterRootOrgUnit: "filterRootOrgUnit", showFilters: "showFilters", isOptionSetNameVisible: "isOptionSetNameVisible" }, outputs: { actionSelected: "actionSelected", approvalSelected: "approvalSelected" }, usesInheritance: true, usesOnChanges: true, ngImport: i0, template: '<ng-content></ng-content>', isInline: true, styles: ["::ng-deep .custom-input{display:flex!important;gap:4px!important;align-items:center!important;border:1px solid #9fadba!important;border-radius:4px!important;margin:0;padding:0 0 0 8px;background-color:#fff!important}::ng-deep .custom-input div{margin:0!important}::ng-deep .custom-input label{font-size:12px;padding-right:0}::ng-deep .custom-input input{border:none!important;font-size:12px!important;display:flex;align-items:center;padding-left:4px;height:40px;outline:none!important;box-shadow:none!important}::ng-deep .custom-input input:focus{border:none!important;box-shadow:none!important}::ng-deep .custom-input [data-test=calendar-clear-button]{background-color:#f2f2f2!important;color:#870808!important;border-radius:6px!important;padding:4px 10px!important;font-size:14px!important}::ng-deep .custom-input [data-test=calendar-clear-button]:hover{background-color:#ddd}::ng-deep .custom-input label{color:gray!important;opacity:1}::ng-deep .table-top-toolbar{background-color:var(--colors-grey100)!important;color:var(--colors-grey900)!important}::ng-deep .custom-select-input{display:flex!important;gap:4px!important;align-items:center!important;border:1px solid #9fadba!important;border-radius:4px!important;margin:0;padding:0 0 0 8px;background-color:#fff!important}::ng-deep .custom-select-input div{margin:0!important}::ng-deep .custom-select-input [data-test=dhis2-uiwidgets-singleselectfield-label]{font-size:12px;color:gray!important}::ng-deep .custom-select-input [data-test=dhis2-uicore-select-input]{border:none!important;font-size:12px!important;display:flex;align-items:center;padding-left:4px;height:40px;outline:none!important;box-shadow:none!important}::ng-deep .custom-select-input [data-test=dhis2-uicore-select-input]:focus-within{box-shadow:none!important}::ng-deep .custom-select-input input:focus{border:none!important;box-shadow:none!important}\n"] }); }
4664
3974
  }
4665
3975
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: LineListTableComponent, decorators: [{
4666
3976
  type: Component,
@@ -4683,22 +3993,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImpor
4683
3993
  type: Input
4684
3994
  }], endDate: [{
4685
3995
  type: Input
4686
- }], filters: [{
3996
+ }], dataQueryFilters: [{
4687
3997
  type: Input
4688
3998
  }], ouMode: [{
4689
3999
  type: Input
4690
- }], dispatchTeis: [{
4691
- type: Input
4692
4000
  }], actionSelected: [{
4693
4001
  type: Output
4694
4002
  }], approvalSelected: [{
4695
4003
  type: Output
4696
4004
  }], isButtonLoading: [{
4697
4005
  type: Input
4698
- }], buttonLabel: [{
4699
- type: Input
4700
- }], firstValue: [{
4701
- type: Output
4702
4006
  }], buttonFilter: [{
4703
4007
  type: Input
4704
4008
  }], filterRootOrgUnit: [{
@@ -4878,7 +4182,7 @@ class DataTableUIComponent extends ReactWrapperModule {
4878
4182
  React__default.createElement(DataTableRow, null,
4879
4183
  columns.map((col) => (React__default.createElement(DataTableColumnHeader, { key: col.column }, col.display))),
4880
4184
  this.actionOptions && this.actionOptions.length > 0 && (React__default.createElement(DataTableColumnHeader, null, "Actions")))),
4881
- React__default.createElement(TableBody, null, tableData.map((row, rowIndex) => (React__default.createElement(DataTableRow, { key: rowIndex },
4185
+ React__default.createElement(TableBody$1, null, tableData.map((row, rowIndex) => (React__default.createElement(DataTableRow, { key: rowIndex },
4882
4186
  columns.map((col) => (React__default.createElement(DataTableCell, { key: col.column }, row[col.column] || '-'))),
4883
4187
  this.actionOptions && this.actionOptions.length > 0 && (React__default.createElement(DataTableCell, null,
4884
4188
  React__default.createElement(DropdownMenu, { dropdownOptions: getDropdownOptions(row), onClick: (option) => option.onClick?.(row) }))))))),
@@ -7909,28 +7213,29 @@ class ProgramEntryFormMetaData {
7909
7213
  return metaData;
7910
7214
  }
7911
7215
  get formFields() {
7912
- if (!this.metaData) {
7216
+ if (!this.program) {
7913
7217
  return [];
7914
7218
  }
7915
- return new ProgramEntryFormFieldUtil(this.metaData, this.config).fields;
7219
+ return new ProgramEntryFormFieldUtil(this.program, this.config).fields;
7916
7220
  }
7917
7221
  get sections() {
7918
- if (!this.metaData || this.config.displayType !== 'SECTION') {
7222
+ if (!this.program || this.config.displayType !== 'SECTION') {
7919
7223
  return [];
7920
7224
  }
7921
- return new ProgramEntryFormSectionUtil(this.metaData, this.config).sections;
7225
+ return new ProgramEntryFormSectionUtil(this.program, this.config).sections;
7922
7226
  }
7923
7227
  get rules() {
7924
- if (!this.metaData || !this.metaData.programRules) {
7228
+ if (!this.program || !this.program.programRules) {
7925
7229
  return [];
7926
7230
  }
7927
- return this.metaData.programRules.map((programRule) => new MetadataRule(programRule, this.metaData.programRuleVariables || []).toJson());
7231
+ return this.program.programRules.map((programRule) => new MetadataRule(programRule, this.program.programRuleVariables || []).toJson());
7928
7232
  }
7929
7233
  toJson() {
7930
7234
  return {
7931
- id: this.metaData?.id,
7932
- name: this.metaData?.name,
7933
- description: this.metaData?.description,
7235
+ id: this.program?.id,
7236
+ name: this.program?.name,
7237
+ description: this.program?.description,
7238
+ program: this.program,
7934
7239
  formFields: this.formFields,
7935
7240
  sections: this.sections,
7936
7241
  rules: this.rules,
@@ -7938,9 +7243,9 @@ class ProgramEntryFormMetaData {
7938
7243
  }
7939
7244
  async get() {
7940
7245
  try {
7941
- const metaData = await this.#getProgramMetaData();
7942
- if (metaData) {
7943
- this.metaData = metaData;
7246
+ const program = await this.#getProgramMetaData();
7247
+ if (program) {
7248
+ this.program = program;
7944
7249
  return this.toJson();
7945
7250
  }
7946
7251
  return null;
@@ -8088,11 +7393,19 @@ class ProgramEntryFormModule {
8088
7393
  this.instanceQuery = this.d2.trackerModule.trackedEntity
8089
7394
  .setProgram(this.config().program)
8090
7395
  .setOrgUnit(this.orgUnit());
8091
- return this.trackedEntity()
8092
- ? (await this.instanceQuery
8093
- .setTrackedEntity(this.trackedEntity())
8094
- .get()).data || (await this.instanceQuery.create())
8095
- : await this.instanceQuery.create();
7396
+ if (!this.trackedEntity) {
7397
+ return await this.instanceQuery.create();
7398
+ }
7399
+ const instance = (await this.instanceQuery
7400
+ .setTrackedEntity(this.trackedEntity())
7401
+ .get()).data;
7402
+ if (!instance) {
7403
+ return await this.instanceQuery.create();
7404
+ }
7405
+ if (this.metaData()?.program) {
7406
+ instance.setFields(this.metaData().program);
7407
+ }
7408
+ return instance;
8096
7409
  }
8097
7410
  async #getEventInstance() {
8098
7411
  this.instanceQuery = this.d2.eventModule.event
@@ -8117,11 +7430,11 @@ class ProgramEntryFormModule {
8117
7430
  }
8118
7431
  }
8119
7432
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: ProgramEntryFormModule, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
8120
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.8", type: ProgramEntryFormModule, isStandalone: true, selector: "ng-dhis2-ui-program-entry-form", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null }, trackedEntity: { classPropertyName: "trackedEntity", publicName: "trackedEntity", isSignal: true, isRequired: false, transformFunction: null }, event: { classPropertyName: "event", publicName: "event", isSignal: true, isRequired: false, transformFunction: null }, enrollment: { classPropertyName: "enrollment", publicName: "enrollment", isSignal: true, isRequired: false, transformFunction: null }, orgUnit: { classPropertyName: "orgUnit", publicName: "orgUnit", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { instanceSave: "instanceSave", instanceSaveCompleted: "instanceSaveCompleted", instanceUpdate: "instanceUpdate", formValidityUpdate: "formValidityUpdate", formCancel: "formCancel" }, ngImport: i0, template: "@if (loading()) {\n<div className=\"program-entry__form-loader\">\n <ng-dhis2-ui-wrapper [component]=\"FormLoader\" />\n</div>\n} @else if(metaData()) {\n\n<div>\n <!-- Form content -->\n @switch (config().displayType) {\n\n <!-- Flat display -->\n @case ('FLAT') {\n <ng-dhis2-ui-flat-form\n [name]=\"metaData()!.name\"\n [dataValues]=\"instance()!\"\n [rules]=\"metaData()!.rules\"\n [fields]=\"metaData()!.formFields\"\n (formUpdate)=\"onFormUpdate($event)\"\n (formValidityUpdate)=\"onValidityUpdate($event)\"\n />\n }\n\n <!-- SECTION display -->\n @case ('SECTION') { Section form }\n\n <!-- CUSTOM FORM -->\n @case ('CUSTOM') { } }\n\n <!-- Action buttons -->\n\n @if(!config().hideActionButtons) {\n <ng-dhis2-ui-wrapper [component]=\"FormActionButtons()\" />\n }\n</div>\n}\n", styles: ["::ng-deep .program-entry__form-loader{padding:8px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: D2FormModule }, { kind: "component", type: FlatFormComponent, selector: "ng-dhis2-ui-flat-form" }, { kind: "directive", type: ReactWrapperModule, selector: "ng-dhis2-ui-wrapper", inputs: ["props", "component"] }] }); }
7433
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.8", type: ProgramEntryFormModule, isStandalone: true, selector: "ng-dhis2-ui-program-entry-form", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null }, trackedEntity: { classPropertyName: "trackedEntity", publicName: "trackedEntity", isSignal: true, isRequired: false, transformFunction: null }, event: { classPropertyName: "event", publicName: "event", isSignal: true, isRequired: false, transformFunction: null }, enrollment: { classPropertyName: "enrollment", publicName: "enrollment", isSignal: true, isRequired: false, transformFunction: null }, orgUnit: { classPropertyName: "orgUnit", publicName: "orgUnit", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { instanceSave: "instanceSave", instanceSaveCompleted: "instanceSaveCompleted", instanceUpdate: "instanceUpdate", formValidityUpdate: "formValidityUpdate", formCancel: "formCancel" }, ngImport: i0, template: "@if (loading()) {\n<div className=\"program-entry__form-loader\">\n <ng-dhis2-ui-wrapper [component]=\"FormLoader\" />\n</div>\n} @else if(metaData()) {\n\n<div>\n <!-- Form content -->\n @switch (config().displayType) {\n\n <!-- Flat display -->\n @case ('FLAT') {\n\n <ng-dhis2-ui-flat-form\n [name]=\"metaData()!.name\"\n [dataValues]=\"instance()!\"\n [rules]=\"metaData()!.rules\"\n [fields]=\"metaData()!.formFields\"\n (formUpdate)=\"onFormUpdate($event)\"\n (formValidityUpdate)=\"onValidityUpdate($event)\"\n />\n }\n\n <!-- SECTION display -->\n @case ('SECTION') { Section form }\n\n <!-- CUSTOM FORM -->\n @case ('CUSTOM') { } }\n\n <!-- Action buttons -->\n\n @if(!config().hideActionButtons) {\n <ng-dhis2-ui-wrapper [component]=\"FormActionButtons()\" />\n }\n</div>\n}\n", styles: ["::ng-deep .program-entry__form-loader{padding:8px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: D2FormModule }, { kind: "component", type: FlatFormComponent, selector: "ng-dhis2-ui-flat-form" }, { kind: "directive", type: ReactWrapperModule, selector: "ng-dhis2-ui-wrapper", inputs: ["props", "component"] }] }); }
8121
7434
  }
8122
7435
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: ProgramEntryFormModule, decorators: [{
8123
7436
  type: Component,
8124
- args: [{ selector: 'ng-dhis2-ui-program-entry-form', imports: [CommonModule, D2FormModule, ReactWrapperModule], template: "@if (loading()) {\n<div className=\"program-entry__form-loader\">\n <ng-dhis2-ui-wrapper [component]=\"FormLoader\" />\n</div>\n} @else if(metaData()) {\n\n<div>\n <!-- Form content -->\n @switch (config().displayType) {\n\n <!-- Flat display -->\n @case ('FLAT') {\n <ng-dhis2-ui-flat-form\n [name]=\"metaData()!.name\"\n [dataValues]=\"instance()!\"\n [rules]=\"metaData()!.rules\"\n [fields]=\"metaData()!.formFields\"\n (formUpdate)=\"onFormUpdate($event)\"\n (formValidityUpdate)=\"onValidityUpdate($event)\"\n />\n }\n\n <!-- SECTION display -->\n @case ('SECTION') { Section form }\n\n <!-- CUSTOM FORM -->\n @case ('CUSTOM') { } }\n\n <!-- Action buttons -->\n\n @if(!config().hideActionButtons) {\n <ng-dhis2-ui-wrapper [component]=\"FormActionButtons()\" />\n }\n</div>\n}\n", styles: ["::ng-deep .program-entry__form-loader{padding:8px}\n"] }]
7437
+ args: [{ selector: 'ng-dhis2-ui-program-entry-form', imports: [CommonModule, D2FormModule, ReactWrapperModule], template: "@if (loading()) {\n<div className=\"program-entry__form-loader\">\n <ng-dhis2-ui-wrapper [component]=\"FormLoader\" />\n</div>\n} @else if(metaData()) {\n\n<div>\n <!-- Form content -->\n @switch (config().displayType) {\n\n <!-- Flat display -->\n @case ('FLAT') {\n\n <ng-dhis2-ui-flat-form\n [name]=\"metaData()!.name\"\n [dataValues]=\"instance()!\"\n [rules]=\"metaData()!.rules\"\n [fields]=\"metaData()!.formFields\"\n (formUpdate)=\"onFormUpdate($event)\"\n (formValidityUpdate)=\"onValidityUpdate($event)\"\n />\n }\n\n <!-- SECTION display -->\n @case ('SECTION') { Section form }\n\n <!-- CUSTOM FORM -->\n @case ('CUSTOM') { } }\n\n <!-- Action buttons -->\n\n @if(!config().hideActionButtons) {\n <ng-dhis2-ui-wrapper [component]=\"FormActionButtons()\" />\n }\n</div>\n}\n", styles: ["::ng-deep .program-entry__form-loader{padding:8px}\n"] }]
8125
7438
  }], propDecorators: { instanceSave: [{
8126
7439
  type: Output
8127
7440
  }], instanceSaveCompleted: [{