@iapps/ng-dhis2-ui 1.1.80 → 1.2.1

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,195 @@ 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
+ const teisRaw = response.data
3137
+ .trackedEntityInstances;
3138
+ const teis = Array.isArray(teisRaw)
3139
+ ? teisRaw
3140
+ : [teisRaw];
3141
+ const orgUnitLabel = metaData.orgUnitLabel;
3142
+ const orgUnitMap = response.data
3143
+ .orgUnitsMap;
3144
+ const attributeColumns = metaData.displayInListTrackedEntityAttributes
3145
+ .sort((a, b) => a.sortOrder - b.sortOrder)
3146
+ .map((attr) => ({
3147
+ label: attr.name,
3148
+ key: attr.id,
3149
+ }));
3150
+ const dataElementColumns = metaData.displayInListDataElements
3151
+ .sort((a, b) => a.sortOrder - b.sortOrder)
3152
+ .map((element) => ({
3153
+ label: element.name,
3154
+ key: element.id,
3155
+ }));
3156
+ const dataElementOptions = metaData.displayInListDataElements.map((element) => ({
3157
+ id: element.id,
3158
+ options: element.optionSet?.options.map((opt) => ({
3159
+ name: opt.name,
3160
+ color: opt.style?.color,
3161
+ })),
3162
+ }));
3163
+ const tableColumns = [
3164
+ {
3165
+ label: orgUnitLabel || 'registering unit',
3166
+ key: 'orgUnit',
3167
+ },
3168
+ ...attributeColumns,
3169
+ ...dataElementColumns,
3170
+ ];
3171
+ const tableFilters = metaData.searchableTrackedEntityAttributes
3172
+ .sort((a, b) => a.sortOrder - b.sortOrder)
3173
+ .map((attr) => ({
3174
+ label: attr.name,
3175
+ key: attr.id,
3176
+ valueType: attr.valueType,
3177
+ options: attr.optionSet ?? undefined,
3178
+ }));
3179
+ const tableData = teis.map((tei, idx) => {
3180
+ const row = {
3181
+ trackedEntityInstance: { value: tei.trackedEntity },
3182
+ index: { value: (pager.page - 1) * pager.pageSize + idx + 1 },
3183
+ };
3184
+ const matchingEnrollment = tei.latestEnrollment;
3185
+ let attributesData = matchingEnrollment.attributes;
3186
+ const dataElementsData = matchingEnrollment.events.flatMap((event) => event.dataValues);
3187
+ attributesData = attributesData.map((attr) => {
3188
+ if (attr?.valueType?.toLowerCase() === 'date') {
3189
+ try {
3190
+ return {
3191
+ ...attr,
3192
+ value: format(parse$1(attr.value, 'yyyy-MM-dd', new Date()), 'dd/MM/yyyy'),
3193
+ };
3194
+ }
3195
+ catch {
3196
+ return { ...attr }; // Leave value as is on parse failure
3197
+ }
3198
+ }
3199
+ return attr;
3200
+ });
3201
+ attributesData.forEach((attr) => {
3202
+ row[attr.attribute] = { value: attr.value };
3203
+ });
3204
+ dataElementsData.forEach((element) => {
3205
+ // Find the matching data element in dataElementOptions by ID
3206
+ const dataElementOption = dataElementOptions.find((deo) => deo.id === element.dataElement);
3207
+ // find a matching option within that data element's options
3208
+ const matchingOption = dataElementOption?.options?.find((opt) => opt.name === element.value);
3209
+ // Build the row entry with value and optionally style
3210
+ if (matchingOption) {
3211
+ row[element.dataElement] = {
3212
+ value: element.value,
3213
+ style: matchingOption.color,
3214
+ };
3215
+ }
3216
+ else {
3217
+ row[element.dataElement] = {
3218
+ value: element.value,
3219
+ };
3220
+ }
3221
+ });
3222
+ // Include orgUnit in the row for id access with style
3223
+ row['orgUnitId'] = { value: matchingEnrollment.orgUnit };
3224
+ row['orgUnit'] = {
3225
+ value: orgUnitMap?.get(matchingEnrollment.orgUnit) || '-',
3226
+ };
3227
+ row['responseData'] = { value: tei.toObject() };
3228
+ return row;
3229
+ });
3230
+ return {
3231
+ columns: tableColumns,
3232
+ data: tableData,
3233
+ filteredEntityColumns: tableFilters,
3234
+ orgUnitLabel: orgUnitLabel,
3235
+ };
3236
+ };
3237
+ const addActionsColumn = (columns, actionOptions) => {
3238
+ return [
3239
+ ...columns,
3240
+ ...(actionOptions && actionOptions.length > 0
3241
+ ? [{ label: 'Actions', key: 'actions' }]
3242
+ : []),
3243
+ ];
3244
+ };
3245
+
3246
+ 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" },
3247
+ React__default.createElement("div", { style: {
3248
+ display: 'flex',
3249
+ alignItems: 'center',
3250
+ gap: '10px',
3251
+ flexWrap: 'wrap',
3252
+ } },
3253
+ React__default.createElement(InputField$1, { key: "location", label: orgUnitLabel ? orgUnitLabel : 'registering unit:', value: selectedOrgUnit, onFocus: () => setHide(false), className: "custom-input", clearable: true, onChange: (event) => {
3254
+ setSelectedOrgUnit(event.value);
3255
+ setOrgUnitState(defaultOrgUnit);
3256
+ } }),
3257
+ React__default.createElement(CalendarInput, { label: "Start date:", calendar: "gregory", locale: "en-GB", timeZone: "Africa/Dar_es_Salaam", className: "custom-input", date: startDateState, onDateSelect: (selectedDate) => {
3258
+ setStartDateState(selectedDate.calendarDateString);
3259
+ } }),
3260
+ React__default.createElement(CalendarInput, { label: "End date:", calendar: "gregory", locale: "en-GB", timeZone: "Africa/Dar_es_Salaam", className: "custom-input", date: endDateState, onDateSelect: (selectedDate) => {
3261
+ setEndDateState(selectedDate.calendarDateString);
3262
+ } }),
3263
+ (visibleFilters ?? []).map(({ label, key, valueType, options }) => {
3264
+ if (valueType === 'DATE') {
3265
+ 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) }));
3266
+ }
3267
+ if (options && options.options.length > 0) {
3268
+ return (React__default.createElement(SingleSelectField, { key: key, label: `${label}:`, selected: inputValues[key] || '', className: "custom-select-input", clearable: true, onChange: ({ selected }) => {
3269
+ setInputValues((prevValues) => ({
3270
+ ...prevValues,
3271
+ [key]: selected ?? '',
3272
+ }));
3273
+ handleInputChangeForSelectField(key, selected ?? '');
3274
+ } }, (options.options ?? []).map((opt) => (React__default.createElement(SingleSelectOption, { key: opt.id, label: opt.name, value: opt.code })))));
3275
+ }
3276
+ return (React__default.createElement(InputField$1, { key: key, label: `${label}:`, className: "custom-input", value: inputValues[key] || '', clearable: true, onChange: (e) => {
3277
+ const currentValue = 'target' in e ? e.target.value : e.value ?? '';
3278
+ setInputValues((prevValues) => ({
3279
+ ...prevValues,
3280
+ [key]: currentValue,
3281
+ }));
3282
+ if (currentValue === '') {
3283
+ handleInputChange(key, '');
3284
+ }
3285
+ }, onBlur: (e) => {
3286
+ const currentValue = 'target' in e ? e.target.value : e.value ?? '';
3287
+ if (currentValue !== '' && currentValue !== prevValue) {
3288
+ handleInputChange(key, currentValue);
3289
+ setPrevValue(currentValue);
3290
+ }
3291
+ } }));
3292
+ }),
3293
+ React__default.createElement(Button$1, { onClick: () => setShowAllFilters(!showAllFilters) }, showAllFilters ? 'Less Filters' : 'More Filters'))));
3294
+
3295
+ const TableHeader = ({ columns }) => (React__default.createElement(TableHead, null,
3296
+ React__default.createElement(DataTableRow, null, columns.map((col) => (React__default.createElement(DataTableColumnHeader, { key: col.key }, col.label))))));
3297
+
3109
3298
  const dropdownStyles$1 = {
3110
3299
  layer: {
3111
3300
  zIndex: '1 !important',
@@ -3242,6 +3431,72 @@ const DataTableActions = (props) => {
3242
3431
  // Use of this source code is governed by a BSD-style
3243
3432
  // license that can be found in the LICENSE file.
3244
3433
 
3434
+ const TableCell = ({ cell, getTextColorFromBackGround, }) => {
3435
+ if (cell?.style && cell?.style !== 'default-value') {
3436
+ return (React__default.createElement(DataTableCell, null,
3437
+ React__default.createElement("div", { style: { display: 'flex', justifyContent: 'center' } },
3438
+ React__default.createElement("span", { style: {
3439
+ backgroundColor: cell.style,
3440
+ display: 'inline-flex',
3441
+ alignItems: 'center',
3442
+ padding: 4,
3443
+ borderRadius: 3,
3444
+ fontSize: 12,
3445
+ color: getTextColorFromBackGround(cell.style),
3446
+ } }, cell.value))));
3447
+ }
3448
+ return (React__default.createElement(DataTableCell, null,
3449
+ React__default.createElement("div", { className: "text-sm text-gray-800" }, cell?.value || '-')));
3450
+ };
3451
+
3452
+ const TableRow = ({ row, columns, getTextColorFromBackGround, actionOptions, actionOptionOrientation, actionSelected, }) => (React__default.createElement(DataTableRow, { key: row.index.value }, columns.map((col) => {
3453
+ if (col.key === 'actions') {
3454
+ return (React__default.createElement(DataTableCell, { key: col.key }, actionOptions && (React__default.createElement(DataTableActions, { actionOptions: actionOptions, actionOptionOrientation: actionOptionOrientation, onClick: (option) => {
3455
+ const data = row['responseData']?.['value'];
3456
+ if (option.onClick)
3457
+ option.onClick(data);
3458
+ actionSelected.emit({
3459
+ action: option.label,
3460
+ data,
3461
+ });
3462
+ } }))));
3463
+ }
3464
+ return (React__default.createElement(TableCell, { key: col.key, cell: row[col.key], getTextColorFromBackGround: getTextColorFromBackGround }));
3465
+ })));
3466
+
3467
+ 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,
3468
+ React__default.createElement(DataTableCell, { colSpan: columns.length.toString(), style: {
3469
+ textAlign: 'center',
3470
+ fontWeight: 'bold',
3471
+ color: 'grey',
3472
+ padding: '20px',
3473
+ } }, "No data found")))));
3474
+
3475
+ const Pagination = ({ pager, setPager }) => {
3476
+ if (!pager || pager.page === undefined || pager.pageSize === undefined) {
3477
+ return null; //skip rendering until valid
3478
+ }
3479
+ 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({
3480
+ ...prev,
3481
+ pageSize: Number(pageSize),
3482
+ page: 1,
3483
+ })), pageSizes: ['10', '20', '50', '100', '500'] }));
3484
+ };
3485
+
3486
+ const TableFooter = ({ pager, setPager, columns }) => {
3487
+ return (React__default.createElement(TableFoot, null,
3488
+ React__default.createElement(DataTableRow, null,
3489
+ React__default.createElement(DataTableCell, { colSpan: columns.length.toString() },
3490
+ React__default.createElement(Pagination, { pager: pager, setPager: setPager })))));
3491
+ };
3492
+
3493
+ const LineListTable = ({ columns, data, pager, setPager, getTextColorFromBackGround, actionOptions, actionOptionOrientation, actionSelected, }) => {
3494
+ return (React__default.createElement(DataTable, null,
3495
+ React__default.createElement(TableHeader, { columns: columns }),
3496
+ React__default.createElement(TableBody, { data: data, columns: columns, getTextColorFromBackGround: getTextColorFromBackGround, actionOptions: actionOptions, actionOptionOrientation: actionOptionOrientation, actionSelected: actionSelected }),
3497
+ React__default.createElement(TableFooter, { columns: columns, pager: pager, setPager: setPager })));
3498
+ };
3499
+
3245
3500
  // Copyright 2025 UDSM DHIS2 Lab. All rights reserved.
3246
3501
  // Use of this source code is governed by a BSD-style
3247
3502
  // license that can be found in the LICENSE file.
@@ -3426,857 +3681,30 @@ const OrgUnitFormField$1 = (props) => {
3426
3681
  React__default.createElement(CircularLoader$1, { small: true }))) : (React__default.createElement("div", { className: classes.orgUnitTreeContainer, style: { maxHeight: '200px', overflowY: 'auto' } }, renderOrgUnitTree()))))))));
3427
3682
  };
3428
3683
 
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
- };
3684
+ const OrgUnitSelector = ({ hide, setHide, selectedOrgUnit, setSelectedOrgUnit, setOrgUnitState, }) => (React__default.createElement(Modal$1, { hide: hide, position: "middle" },
3685
+ React__default.createElement(ModalTitle$1, null, "Select organization unit"),
3686
+ React__default.createElement(ModalContent$1, null,
3687
+ React__default.createElement(OrgUnitFormField$1, { key: selectedOrgUnit, onSelectOrgUnit: (selectedOrgUnit) => {
3688
+ setSelectedOrgUnit(selectedOrgUnit.displayName);
3689
+ setOrgUnitState(selectedOrgUnit.id);
3690
+ setHide(true);
3691
+ } })),
3692
+ React__default.createElement(ModalActions$1, null,
3693
+ React__default.createElement(ButtonStrip$1, { end: true },
3694
+ React__default.createElement(Button$1, { onClick: () => setHide(true), secondary: true }, "Close")))));
4264
3695
 
4265
3696
  // src/app/line-list-table.component.ts
4266
3697
  class LineListTableComponent extends ReactWrapperModule {
4267
3698
  constructor() {
4268
3699
  super(...arguments);
4269
3700
  this.actionOptionOrientation = 'DROPDOWN';
4270
- this.dispatchTeis = false;
4271
- this.actionSelected = new EventEmitter();
4272
- this.reactStateUpdaters = null;
4273
- 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;
3705
+ this.actionSelected = new EventEmitter();
3706
+ this.approvalSelected = new EventEmitter();
3707
+ this.reactStateUpdaters = null;
4280
3708
  this.setReactStateUpdaters = (updaters) => {
4281
3709
  this.reactStateUpdaters = updaters;
4282
3710
  };
@@ -4284,29 +3712,25 @@ class LineListTableComponent extends ReactWrapperModule {
4284
3712
  this.LineList = () => {
4285
3713
  const [columns, setColumns] = useState([]);
4286
3714
  const [data, setData] = useState([]);
4287
- const [pager, setPager] = useState({
3715
+ const [pager, setPager] = useState(new Pager({
4288
3716
  page: 1,
4289
3717
  pageSize: 10,
4290
3718
  total: 0,
4291
3719
  pageCount: 1,
4292
- });
4293
- const paginationRef = useRef(null);
3720
+ }));
4294
3721
  const [programIdState, setProgramIdState] = useState(this.programId);
4295
3722
  const [isOptionSetNameVisibleState, setOptionSetNameVisible] = useState(this.isOptionSetNameVisible);
4296
3723
  const [orgUnitState, setOrgUnitState] = useState(this.orgUnit);
4297
3724
  const [programStageIdState, setProgramStageIdState] = useState(this.programStageId);
4298
3725
  const [attributeFiltersState, setAttributeFiltersState] = useState(this.attributeFilters);
3726
+ const [dataQueryFiltersState, setDataQueryFiltersState] = useState(this.dataQueryFilters);
4299
3727
  const [startDateState, setStartDateState] = useState(this.startDate);
4300
3728
  const [endDateState, setEndDateState] = useState(this.endDate);
4301
3729
  const [loading, setLoading] = useState(false);
4302
- const [isButtonLoading, setIsButtonLoading] = useState(this.isButtonLoading);
3730
+ const [metaDataLoadng, setMetaDataLoading] = useState(false);
4303
3731
  const [filteredColumns, setFilteredColumns] = useState();
4304
3732
  const [inputValues, setInputValues] = useState({});
4305
- const [filters, setFilters] = useState(false);
4306
3733
  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
3734
  const [selectedOrgUnit, setSelectedOrgUnit] = useState('');
4311
3735
  const [hide, setHide] = useState(true);
4312
3736
  const [showAllFilters, setShowAllFilters] = useState(false);
@@ -4316,6 +3740,8 @@ class LineListTableComponent extends ReactWrapperModule {
4316
3740
  const defaultOrgUnit = this.orgUnit;
4317
3741
  const [prevValue, setPrevValue] = useState();
4318
3742
  const [dateStates, setDateStates] = useState({});
3743
+ const [metaData, setMetaData] = useState(null);
3744
+ const d2 = window.d2Web;
4319
3745
  // Store updaters in refs for Angular to access
4320
3746
  const updateRefs = useRef({
4321
3747
  setProgramIdState,
@@ -4324,7 +3750,6 @@ class LineListTableComponent extends ReactWrapperModule {
4324
3750
  setAttributeFiltersState,
4325
3751
  setStartDateState,
4326
3752
  setEndDateState,
4327
- setIsButtonLoading,
4328
3753
  setOptionSetNameVisible,
4329
3754
  });
4330
3755
  useEffect(() => {
@@ -4332,64 +3757,82 @@ class LineListTableComponent extends ReactWrapperModule {
4332
3757
  }, []);
4333
3758
  useEffect(() => {
4334
3759
  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;
3760
+ const fetchmetaData = async () => {
3761
+ try {
3762
+ const trackerResponse = (await d2.trackerModule.trackedEntity
3763
+ .setProgram(this.programId)
3764
+ .getMetaData());
3765
+ const data = trackerResponse;
3766
+ setMetaData(data);
4376
3767
  }
4377
- else {
4378
- responsePager = response.data.pager;
4379
- const { columns, data } = getEventData(response, pager, this.isOptionSetNameVisible);
4380
- entityColumns = columns;
4381
- entityData = data;
3768
+ catch (error) {
3769
+ console.error('Failed to metadata:', error);
4382
3770
  }
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
3771
  };
3772
+ if (this.programId) {
3773
+ fetchmetaData();
3774
+ }
3775
+ }, []);
3776
+ useEffect(() => {
3777
+ if (!metaData) {
3778
+ return undefined;
3779
+ }
3780
+ setLoading(true);
3781
+ const isTracker = metaData.programType === 'WITH_REGISTRATION';
3782
+ const endDate = endDateState ?? new Date().toISOString().split('T')[0];
3783
+ if (isTracker) {
3784
+ d2.trackerModule.trackedEntity
3785
+ .setEndDate(endDate)
3786
+ .setStartDate(startDateState)
3787
+ .setProgram(this.programId)
3788
+ .setOrgUnit(orgUnitState)
3789
+ .setOuMode(this.ouMode)
3790
+ .setFilters(dataQueryFiltersState)
3791
+ .setPagination(new Pager({
3792
+ pageSize: pager.pageSize,
3793
+ page: pager.page,
3794
+ }))
3795
+ .setOrderCriterias([
3796
+ new DataOrderCriteria().setField('createdAt').setOrder('desc'),
3797
+ ])
3798
+ .get()
3799
+ .then((response) => {
3800
+ const trackedEntityInstances = Array.isArray(response.data)
3801
+ ? response.data
3802
+ : [response.data];
3803
+ const orgUnitIdsFromEnrollments = new Set(trackedEntityInstances.map((tei) => tei.latestEnrollment.orgUnit));
3804
+ const uniqueOrgUnitIds = [...orgUnitIdsFromEnrollments];
3805
+ this.lineListService.fetchOrgUnits(uniqueOrgUnitIds).subscribe({
3806
+ next: (fetchedOrgUnits) => {
3807
+ const trackedEntityResponse = {
3808
+ trackedEntityInstances: response.data,
3809
+ pager: pager,
3810
+ orgUnitsMap: fetchedOrgUnits,
3811
+ };
3812
+ const { columns, data, filteredEntityColumns, orgUnitLabel } = getTrackedEntityTableData({ data: trackedEntityResponse }, this.programId, pager, metaData);
3813
+ setFilteredColumns((prev) => filteredEntityColumns.length > 0
3814
+ ? filteredEntityColumns
3815
+ : prev);
3816
+ const finalColumns = addActionsColumn([{ label: '#', key: 'index' }, ...columns], this.actionOptions);
3817
+ const pagerResponse = response.pagination;
3818
+ setLoading(false);
3819
+ setColumns(finalColumns);
3820
+ setData(data);
3821
+ setPager(new Pager(pagerResponse || {}));
3822
+ setOrgUnitLabel(orgUnitLabel);
3823
+ },
3824
+ error: (err) => {
3825
+ console.error('Error fetching org units:', err);
3826
+ setLoading(false);
3827
+ },
3828
+ });
3829
+ });
3830
+ }
3831
+ else {
3832
+ //TODO: TO IMPLEMEMNT EVENT QUERY FOR FILTERING EVENTS WHEN PROGRAM STAGE IS PASSED OR DEALING WITH EVENT PROGRAM USING TRACKER SDK QUERY
3833
+ }
4392
3834
  }, [
3835
+ metaData,
4393
3836
  programIdState,
4394
3837
  orgUnitState,
4395
3838
  programStageIdState,
@@ -4399,50 +3842,25 @@ class LineListTableComponent extends ReactWrapperModule {
4399
3842
  pager.page,
4400
3843
  pager.pageSize,
4401
3844
  isOptionSetNameVisibleState,
3845
+ dataQueryFiltersState,
4402
3846
  ]);
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
3847
  const handleInputChange = (key, value) => {
4436
3848
  setInputValues((prevValues) => ({
4437
3849
  ...prevValues,
4438
3850
  [key]: value ?? '',
4439
3851
  }));
4440
- setAttributeFiltersState((prevFilters = []) => {
3852
+ setDataQueryFiltersState((prevFilters) => {
4441
3853
  // Remove old filter for this key
4442
3854
  const filteredFilters = prevFilters.filter((f) => f.attribute !== key);
4443
3855
  // Only add new filter if value is not empty
4444
3856
  const updatedFilters = value.trim()
4445
- ? [...filteredFilters, { attribute: key, operator: 'like', value }]
3857
+ ? [
3858
+ ...filteredFilters,
3859
+ new DataQueryFilter()
3860
+ .setAttribute(key)
3861
+ .setCondition(DataFilterCondition.Like)
3862
+ .setValue(value),
3863
+ ]
4446
3864
  : filteredFilters;
4447
3865
  return updatedFilters;
4448
3866
  });
@@ -4453,175 +3871,69 @@ class LineListTableComponent extends ReactWrapperModule {
4453
3871
  ...prevValues,
4454
3872
  [key]: value ?? '',
4455
3873
  }));
4456
- setAttributeFiltersState((prevFilters = []) => {
4457
- // Remove old filter for this key
3874
+ setDataQueryFiltersState((prevFilters = []) => {
3875
+ // Remove existing filter for the same key (attribute)
4458
3876
  const filteredFilters = prevFilters.filter((f) => f.attribute !== key);
4459
3877
  // Only add new filter if value is not empty
4460
3878
  const updatedFilters = value.trim()
4461
- ? [...filteredFilters, { attribute: key, operator: 'eq', value }]
3879
+ ? [
3880
+ ...filteredFilters,
3881
+ new DataQueryFilter()
3882
+ .setAttribute(key)
3883
+ .setCondition(DataFilterCondition.Equal)
3884
+ .setValue(value),
3885
+ ]
4462
3886
  : filteredFilters;
4463
3887
  return updatedFilters;
4464
3888
  });
4465
3889
  };
4466
3890
  const handleDateSelect = (key, selectedDate) => {
4467
- const selectedDateString = selectedDate?.calendarDateString ?? ''; // Default to empty string if null
3891
+ const selectedDateString = selectedDate?.calendarDateString ?? '';
4468
3892
  // Update dateStates
4469
3893
  setDateStates((prevDateStates) => ({
4470
3894
  ...prevDateStates,
4471
- [key]: selectedDateString, // Will set it to empty if date is cleared
3895
+ [key]: selectedDateString,
4472
3896
  }));
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
3897
+ // Update dataQueryFilters
3898
+ setDataQueryFiltersState((prevFilters) => {
3899
+ const filteredFilters = (prevFilters || []).filter((f) => f.attribute !== key);
4478
3900
  const updatedFilters = selectedDateString.trim()
4479
3901
  ? [
4480
3902
  ...filteredFilters,
4481
- { attribute: key, operator: 'like', value: selectedDateString },
3903
+ new DataQueryFilter()
3904
+ .setAttribute(key)
3905
+ .setCondition(DataFilterCondition.Equal)
3906
+ .setValue(selectedDateString),
4482
3907
  ]
4483
- : filteredFilters; // If empty, just keep the filteredFilters as they are
3908
+ : filteredFilters;
4484
3909
  return updatedFilters;
4485
3910
  });
4486
3911
  };
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'] }))))))))));
3912
+ function getTextColorFromBackGround(hex) {
3913
+ // Remove the hash if present
3914
+ hex = hex.replace('#', '');
3915
+ // Convert to RGB
3916
+ const r = parseInt(hex.substr(0, 2), 16);
3917
+ const g = parseInt(hex.substr(2, 2), 16);
3918
+ const b = parseInt(hex.substr(4, 2), 16);
3919
+ // YIQ formula to calculate brightness
3920
+ const yiq = (r * 299 + g * 587 + b * 114) / 1000;
3921
+ // Return black for light backgrounds, white for dark backgrounds
3922
+ return yiq >= 128 ? colors$1.grey700 : '#FFFFFF';
3923
+ }
3924
+ return (React__default.createElement("div", null, loading ? (React__default.createElement("div", { style: {
3925
+ display: 'flex',
3926
+ alignItems: 'center',
3927
+ gap: 8,
3928
+ padding: 8,
3929
+ } },
3930
+ React__default.createElement(CircularLoader$1, { small: true }),
3931
+ React__default.createElement("div", { style: {
3932
+ fontSize: 14,
3933
+ } }, "Loading"))) : (React__default.createElement("div", null,
3934
+ React__default.createElement(OrgUnitSelector, { hide: hide, setHide: setHide, selectedOrgUnit: selectedOrgUnit, setSelectedOrgUnit: setSelectedOrgUnit, setOrgUnitState: setOrgUnitState }),
3935
+ 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 })),
3936
+ React__default.createElement(LineListTable, { columns: columns, data: data, pager: pager, setPager: setPager, getTextColorFromBackGround: getTextColorFromBackGround, actionOptions: this.actionOptions, actionOptionOrientation: this.actionOptionOrientation, actionSelected: this.actionSelected })))));
4625
3937
  };
4626
3938
  }
4627
3939
  ngOnChanges(changes) {
@@ -4660,7 +3972,7 @@ class LineListTableComponent extends ReactWrapperModule {
4660
3972
  this.render();
4661
3973
  }
4662
3974
  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"] }); }
3975
+ 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
3976
  }
4665
3977
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: LineListTableComponent, decorators: [{
4666
3978
  type: Component,
@@ -4683,22 +3995,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImpor
4683
3995
  type: Input
4684
3996
  }], endDate: [{
4685
3997
  type: Input
4686
- }], filters: [{
3998
+ }], dataQueryFilters: [{
4687
3999
  type: Input
4688
4000
  }], ouMode: [{
4689
4001
  type: Input
4690
- }], dispatchTeis: [{
4691
- type: Input
4692
- }], actionSelected: [{
4693
- type: Output
4694
- }], approvalSelected: [{
4695
- type: Output
4696
4002
  }], isButtonLoading: [{
4697
4003
  type: Input
4698
- }], buttonLabel: [{
4699
- type: Input
4700
- }], firstValue: [{
4701
- type: Output
4702
4004
  }], buttonFilter: [{
4703
4005
  type: Input
4704
4006
  }], filterRootOrgUnit: [{
@@ -4707,6 +4009,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImpor
4707
4009
  type: Input
4708
4010
  }], isOptionSetNameVisible: [{
4709
4011
  type: Input
4012
+ }], actionSelected: [{
4013
+ type: Output
4014
+ }], approvalSelected: [{
4015
+ type: Output
4710
4016
  }] } });
4711
4017
 
4712
4018
  class LineListModule {
@@ -4878,7 +4184,7 @@ class DataTableUIComponent extends ReactWrapperModule {
4878
4184
  React__default.createElement(DataTableRow, null,
4879
4185
  columns.map((col) => (React__default.createElement(DataTableColumnHeader, { key: col.column }, col.display))),
4880
4186
  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 },
4187
+ React__default.createElement(TableBody$1, null, tableData.map((row, rowIndex) => (React__default.createElement(DataTableRow, { key: rowIndex },
4882
4188
  columns.map((col) => (React__default.createElement(DataTableCell, { key: col.column }, row[col.column] || '-'))),
4883
4189
  this.actionOptions && this.actionOptions.length > 0 && (React__default.createElement(DataTableCell, null,
4884
4190
  React__default.createElement(DropdownMenu, { dropdownOptions: getDropdownOptions(row), onClick: (option) => option.onClick?.(row) }))))))),
@@ -7909,28 +7215,29 @@ class ProgramEntryFormMetaData {
7909
7215
  return metaData;
7910
7216
  }
7911
7217
  get formFields() {
7912
- if (!this.metaData) {
7218
+ if (!this.program) {
7913
7219
  return [];
7914
7220
  }
7915
- return new ProgramEntryFormFieldUtil(this.metaData, this.config).fields;
7221
+ return new ProgramEntryFormFieldUtil(this.program, this.config).fields;
7916
7222
  }
7917
7223
  get sections() {
7918
- if (!this.metaData || this.config.displayType !== 'SECTION') {
7224
+ if (!this.program || this.config.displayType !== 'SECTION') {
7919
7225
  return [];
7920
7226
  }
7921
- return new ProgramEntryFormSectionUtil(this.metaData, this.config).sections;
7227
+ return new ProgramEntryFormSectionUtil(this.program, this.config).sections;
7922
7228
  }
7923
7229
  get rules() {
7924
- if (!this.metaData || !this.metaData.programRules) {
7230
+ if (!this.program || !this.program.programRules) {
7925
7231
  return [];
7926
7232
  }
7927
- return this.metaData.programRules.map((programRule) => new MetadataRule(programRule, this.metaData.programRuleVariables || []).toJson());
7233
+ return this.program.programRules.map((programRule) => new MetadataRule(programRule, this.program.programRuleVariables || []).toJson());
7928
7234
  }
7929
7235
  toJson() {
7930
7236
  return {
7931
- id: this.metaData?.id,
7932
- name: this.metaData?.name,
7933
- description: this.metaData?.description,
7237
+ id: this.program?.id,
7238
+ name: this.program?.name,
7239
+ description: this.program?.description,
7240
+ program: this.program,
7934
7241
  formFields: this.formFields,
7935
7242
  sections: this.sections,
7936
7243
  rules: this.rules,
@@ -7938,9 +7245,9 @@ class ProgramEntryFormMetaData {
7938
7245
  }
7939
7246
  async get() {
7940
7247
  try {
7941
- const metaData = await this.#getProgramMetaData();
7942
- if (metaData) {
7943
- this.metaData = metaData;
7248
+ const program = await this.#getProgramMetaData();
7249
+ if (program) {
7250
+ this.program = program;
7944
7251
  return this.toJson();
7945
7252
  }
7946
7253
  return null;
@@ -8088,11 +7395,19 @@ class ProgramEntryFormModule {
8088
7395
  this.instanceQuery = this.d2.trackerModule.trackedEntity
8089
7396
  .setProgram(this.config().program)
8090
7397
  .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();
7398
+ if (!this.trackedEntity) {
7399
+ return await this.instanceQuery.create();
7400
+ }
7401
+ const instance = (await this.instanceQuery
7402
+ .setTrackedEntity(this.trackedEntity())
7403
+ .get()).data;
7404
+ if (!instance) {
7405
+ return await this.instanceQuery.create();
7406
+ }
7407
+ if (this.metaData()?.program) {
7408
+ instance.setFields(this.metaData().program);
7409
+ }
7410
+ return instance;
8096
7411
  }
8097
7412
  async #getEventInstance() {
8098
7413
  this.instanceQuery = this.d2.eventModule.event
@@ -8117,11 +7432,11 @@ class ProgramEntryFormModule {
8117
7432
  }
8118
7433
  }
8119
7434
  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"] }] }); }
7435
+ 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
7436
  }
8122
7437
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: ProgramEntryFormModule, decorators: [{
8123
7438
  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"] }]
7439
+ 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
7440
  }], propDecorators: { instanceSave: [{
8126
7441
  type: Output
8127
7442
  }], instanceSaveCompleted: [{