@iapps/ng-dhis2-ui 1.1.58 → 1.1.59

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.
@@ -25,11 +25,11 @@ 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, IconFilter16, DataTable, TableHead, DataTableRow, DataTableColumnHeader, TableBody, DataTableCell, TableFoot, Pagination, FileInputField, FileListItem, Chip, MultiSelectField, TextAreaField } from '@dhis2/ui';
29
- import { isObject, isString, sortBy, isArray, find, camelCase, flatten, isUndefined, debounce, head, isEmpty } from 'lodash';
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';
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 { map as map$1, switchMap } from 'rxjs/operators';
32
+ import { switchMap, map as map$1 } from 'rxjs/operators';
33
33
  import * as i2 from '@angular/forms';
34
34
  import { Validators, UntypedFormControl, UntypedFormGroup, FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
35
35
  import { toObservable } from '@angular/core/rxjs-interop';
@@ -3287,32 +3287,100 @@ const getFilteredTrackedEntityInstances = (trackedEntityInstances, filters) => {
3287
3287
  event.dataValues?.some((dataValue) => dataValue.dataElement === filter.dataElement &&
3288
3288
  matchesCondition(dataValue.value, filter.operator, filter.value))))));
3289
3289
  };
3290
+ const getFilteredTrackedEntites = (trackedEntities, filters) => {
3291
+ if (!filters.length)
3292
+ return trackedEntities;
3293
+ return trackedEntities.filter((tei) => filters.every((filter) => tei.enrollments?.some((enrollment) => enrollment.events?.some((event) => event.programStage === filter.programStage &&
3294
+ event.dataValues?.some((dataValue) => dataValue.dataElement === filter.dataElement &&
3295
+ matchesCondition(dataValue.value, filter.operator, filter.value))))));
3296
+ };
3290
3297
 
3291
3298
  class LineListService {
3292
3299
  constructor(httpClient) {
3293
3300
  this.httpClient = httpClient;
3294
3301
  }
3295
3302
  getProgramMetadata(programId) {
3296
- return this.httpClient.get(`programs/${programId}.json?fields=programType,programStages[id,name,programStageDataElements[dataElement[id,name]]],organisationUnits[id,name],*`);
3297
- }
3303
+ return this.httpClient.get(`programs/${programId}.json?fields=programType,programStages[id,name,programStageDataElements[dataElement[id,name]]],programTrackedEntityAttributes[*]`);
3304
+ }
3305
+ // private getTrackedEntityInstances(
3306
+ // programId: string,
3307
+ // orgUnit: string,
3308
+ // page: number,
3309
+ // pageSize: number,
3310
+ // filters: AttributeFilter[] = [],
3311
+ // startDate?: string,
3312
+ // endDate?: string,
3313
+ // ouMode?: string,
3314
+ // filterRootOrgUnit?: boolean
3315
+ // ): Observable<TrackedEntityResponse> {
3316
+ // const filterParams = buildFilters(filters);
3317
+ // // const dateFilter = startDate || endDate ? `enrollmentEnrolledAfter=${startDate}&enrollmentEnrolledBefore=${endDate}` : '';
3318
+ // const dateFilter = [
3319
+ // startDate ? `enrollmentEnrolledAfter=${startDate}` : '',
3320
+ // endDate ? `enrollmentEnrolledBefore=${endDate}` : '',
3321
+ // ].filter(Boolean).join('&');
3322
+ // const ouModeIdentifier = ouMode ? `&orgUnitMode=${ouMode}`: ``;
3323
+ // return this.httpClient.get(
3324
+ // `tracker/trackedEntities.json?program=${programId}&orgUnit=${orgUnit}${ouModeIdentifier}&page=${page}&pageSize=${pageSize}&fields=trackedEntity,orgUnit,attributes[*],enrollments[*]&totalPages=true&${filterParams}${dateFilter}&order=createdAt:desc`
3325
+ // ).pipe(
3326
+ // map((response: any) => {
3327
+ // if (filterRootOrgUnit) {
3328
+ // response.trackedEntities = response.trackedEntities.filter(
3329
+ // (tei: any) => tei.orgUnit !== orgUnit // Exclude TEIs with the root orgUnit
3330
+ // );
3331
+ // }
3332
+ // return response;
3333
+ // })
3334
+ // );
3335
+ // }
3298
3336
  getTrackedEntityInstances(programId, orgUnit, page, pageSize, filters = [], startDate, endDate, ouMode, filterRootOrgUnit) {
3299
3337
  const filterParams = buildFilters(filters);
3300
- const dateFilter = startDate && endDate ? `&programStartDate=${startDate}&programEndDate=${endDate}` : '';
3301
- const ouModeIdentifier = ouMode ? `&ouMode=${ouMode}` : ``;
3302
- return this.httpClient.get(`trackedEntityInstances.json?program=${programId}&ou=${orgUnit}${ouModeIdentifier}&page=${page}&pageSize=${pageSize}&fields=trackedEntityInstance,orgUnit,attributes[*,displayInList],enrollments[*]&totalPages=true&${filterParams}${dateFilter}&order=created:desc`).pipe(map$1((response) => {
3338
+ const dateFilter = [
3339
+ startDate ? `enrollmentEnrolledAfter=${startDate}` : '',
3340
+ endDate ? `enrollmentEnrolledBefore=${endDate}` : '',
3341
+ ].filter(Boolean).join('&');
3342
+ const ouModeIdentifier = ouMode ? `&orgUnitMode=${ouMode}` : '';
3343
+ return this.httpClient
3344
+ .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`)
3345
+ .pipe(switchMap((response) => {
3303
3346
  if (filterRootOrgUnit) {
3304
- response.trackedEntityInstances = response.trackedEntityInstances.filter((tei) => tei.orgUnit !== orgUnit // Exclude TEIs with the root orgUnit
3305
- );
3347
+ response.trackedEntities = response.trackedEntities.filter((tei) => tei.orgUnit !== orgUnit);
3306
3348
  }
3307
- return response;
3349
+ // **Step 1:** Extract unique orgUnits from enrollments
3350
+ const uniqueOrgUnitIds = new Set();
3351
+ response.trackedEntities.forEach((tei) => {
3352
+ tei.enrollments?.forEach((enrollment) => {
3353
+ if (enrollment.program === programId) {
3354
+ uniqueOrgUnitIds.add(enrollment.orgUnit);
3355
+ }
3356
+ });
3357
+ });
3358
+ // If no unique orgUnits found, return immediately
3359
+ if (uniqueOrgUnitIds.size === 0) {
3360
+ return of({ ...response, orgUnitsMap: new Map() });
3361
+ }
3362
+ // **Step 2:** Fetch orgUnit names in a single request
3363
+ return this.fetchOrgUnits(Array.from(uniqueOrgUnitIds)).pipe(map$1((orgUnitsMap) => ({
3364
+ ...response,
3365
+ orgUnitsMap, // Attach orgUnitId → orgUnitName map
3366
+ })));
3367
+ }));
3368
+ }
3369
+ //filter=id:in:[id1,id2,id3]
3370
+ /**
3371
+ * Fetch orgUnit names for given orgUnit IDs
3372
+ */
3373
+ fetchOrgUnits(orgUnitIds) {
3374
+ const idsQuery = `filter=id:in:[${orgUnitIds}]`;
3375
+ return this.httpClient
3376
+ .get(`organisationUnits.json?fields=id,name&paging=false&${idsQuery}`)
3377
+ .pipe(map$1((response) => {
3378
+ const orgUnitsMap = new Map();
3379
+ response.organisationUnits.forEach((orgUnit) => {
3380
+ orgUnitsMap.set(orgUnit.id, orgUnit.name);
3381
+ });
3382
+ return orgUnitsMap;
3308
3383
  }));
3309
- // pipe(
3310
- // map((response: any) => {
3311
- // //TODO: use the api to to order by desc
3312
- // // response.trackedEntityInstances.reverse();
3313
- // return response;
3314
- // })
3315
- // );
3316
3384
  }
3317
3385
  getEvents(programId, orgUnit, page, pageSize, filters = [], startDate, endDate, ouMode) {
3318
3386
  const filterParams = buildFilters(filters);
@@ -3338,6 +3406,7 @@ class LineListService {
3338
3406
  return this.getTrackedEntityInstances(programId, orgUnit, page, pageSize, filters, startDate, endDate, ouMode, filterRootOrgUnit).pipe(map$1((teis) => ({
3339
3407
  metadata: programMetadata,
3340
3408
  data: teis,
3409
+ orgUnits: teis.orgUnitsMap
3341
3410
  })));
3342
3411
  }
3343
3412
  else {
@@ -3382,15 +3451,18 @@ const getProgramStageData = (response, programStageId, pager) => {
3382
3451
  };
3383
3452
  const getTrackedEntityData = (response, programId, pager, filters) => {
3384
3453
  let teis = response.data
3385
- .trackedEntityInstances;
3454
+ .trackedEntities;
3386
3455
  let programMetaData = response.metadata.programTrackedEntityAttributes;
3387
- //organisation units from metadata
3388
- let orgUnitsFromMetaData = response.metadata.organisationUnits;
3389
- //a Map to efficiently look up orgUnit names by ID
3390
- const orgUnitMap = new Map(orgUnitsFromMetaData.map((ou) => [
3391
- ou.id,
3392
- ou.name,
3393
- ]));
3456
+ // //organisation units from metadata
3457
+ // let orgUnitsFromMetaData = response.metadata.organisationUnits;
3458
+ // //a Map to efficiently look up orgUnit names by ID
3459
+ // const orgUnitMap = new Map<string, string>(
3460
+ // orgUnitsFromMetaData.map((ou: { id: string; name: string }) => [
3461
+ // ou.id,
3462
+ // ou.name,
3463
+ // ])
3464
+ // );
3465
+ const orgUnitMap = response.data.orgUnitsMap;
3394
3466
  const mappedProgramMetadataAttributes = programMetaData.map((attr) => ({
3395
3467
  displayInList: attr.displayInList,
3396
3468
  searchable: attr.searchable,
@@ -3403,7 +3475,7 @@ const getTrackedEntityData = (response, programId, pager, filters) => {
3403
3475
  return acc;
3404
3476
  }, {});
3405
3477
  if (filters) {
3406
- teis = getFilteredTrackedEntityInstances(teis, filters);
3478
+ teis = getFilteredTrackedEntites(teis, filters);
3407
3479
  }
3408
3480
  const allAttributes = new Set();
3409
3481
  teis.forEach((tei) => {
@@ -3431,10 +3503,6 @@ const getTrackedEntityData = (response, programId, pager, filters) => {
3431
3503
  // Check if the column label is part of any value in programAttributesMap
3432
3504
  return Object.values(programAttributesMap).some((value) => value.includes(column.label));
3433
3505
  });
3434
- // entityColumns.push({
3435
- // label: 'Location',
3436
- // key: 'orgUnit',
3437
- // });
3438
3506
  // Add orgUnit as the first column
3439
3507
  entityColumns.unshift({
3440
3508
  label: 'Location',
@@ -3462,9 +3530,14 @@ const getTrackedEntityData = (response, programId, pager, filters) => {
3462
3530
  : tei.attributes;
3463
3531
  attributesToUse.forEach((attr) => (row[attr.attribute] = attr.value));
3464
3532
  //include orgUnit in the row for id access
3465
- row['orgUnitId'] = tei.orgUnit;
3533
+ row['orgUnitId'] = matchingEnrollment.orgUnit;
3466
3534
  // Access the name of the orgUnit using the Map
3467
- row['orgUnit'] = orgUnitMap.get(tei.orgUnit) || tei.orgUnit || 'N/A';
3535
+ // row['orgUnit'] = matchingEnrollment.orgUnitName;
3536
+ row['orgUnit'] = orgUnitMap?.get(matchingEnrollment.orgUnit) || 'N/A';
3537
+ // row['orgUnit'] =
3538
+ // orgUnitMap && orgUnitMap[matchingEnrollment.orgUnit]
3539
+ // ? orgUnitMap[matchingEnrollment.orgUnit]
3540
+ // : 'N/A';
3468
3541
  return row;
3469
3542
  });
3470
3543
  return {
@@ -3503,12 +3576,195 @@ const addActionsColumn = (columns, actionOptions) => {
3503
3576
  ];
3504
3577
  };
3505
3578
 
3579
+ // Copyright 2025 UDSM DHIS2 Lab. All rights reserved.
3580
+ // Use of this source code is governed by a BSD-style
3581
+ // license that can be found in the LICENSE file.
3582
+ // @flow
3583
+ const orgUnitFieldStyles$1 = {
3584
+ container: {
3585
+ border: '1px solid',
3586
+ borderColor: colors$1.grey400,
3587
+ borderRadius: '3px',
3588
+ height: '100%',
3589
+ width: '100%',
3590
+ zIndex: 0,
3591
+ backgroundColor: 'white',
3592
+ },
3593
+ searchField: {
3594
+ height: '40px',
3595
+ overflow: 'hidden',
3596
+ borderBottomLeftRadius: 0,
3597
+ borderBottomRightRadius: 0,
3598
+ boxShadow: 'none',
3599
+ border: 'none',
3600
+ },
3601
+ debounceFieldContainer: {
3602
+ padding: '8px',
3603
+ background: colors$1.grey100,
3604
+ borderTopLeftRadius: '3px',
3605
+ borderTopRightRadius: '3px',
3606
+ },
3607
+ orgUnitTreeContainer: {
3608
+ borderBottomLeftRadius: '3px',
3609
+ borderBottomRightRadius: '3px',
3610
+ overflow: 'auto',
3611
+ },
3612
+ orgUnitTreeLoader: {
3613
+ padding: '8px',
3614
+ },
3615
+ orgUnitFieldLabel: {
3616
+ marginBottom: '8px',
3617
+ display: 'block',
3618
+ boxSizing: 'border-box',
3619
+ fontSize: '14px',
3620
+ lineHeight: '19px',
3621
+ color: 'rgb(33, 41, 52)',
3622
+ padding: '0',
3623
+ },
3624
+ orgUnitFieldRequiredLabel: {
3625
+ paddingInlineStart: '4px',
3626
+ },
3627
+ };
3628
+ const OrgUnitFormField$1 = (props) => {
3629
+ const { onSelectOrgUnit, label, required, selected, disabled, key } = props;
3630
+ const d2 = window?.d2Web;
3631
+ const classes = useDynamicStyles$2(orgUnitFieldStyles$1);
3632
+ const config = useMemo(() => {
3633
+ return d2.systemInfo?.toInitObject();
3634
+ }, []);
3635
+ const rootOrgUnits = useMemo(() => {
3636
+ return d2.currentUser?.organisationUnits || [];
3637
+ }, []);
3638
+ const getExpandedItems = () => {
3639
+ if (rootOrgUnits && rootOrgUnits.length === 1) {
3640
+ return [`/${rootOrgUnits[0].id}`];
3641
+ }
3642
+ else if (rootOrgUnits?.length > 1) {
3643
+ return rootOrgUnits.map((root) => root.path);
3644
+ }
3645
+ return undefined;
3646
+ };
3647
+ const initiallyExpanded = getExpandedItems();
3648
+ const [searchText, setSearchText] = useState(undefined);
3649
+ const [loading, setLoading] = useState(true);
3650
+ const [searchLoading, setSearchLoading] = useState();
3651
+ const [searchData, setSearchData] = useState();
3652
+ const [selectedOrgUnit, setSelectedOrgUnit] = useState();
3653
+ const [expanded, setExpanded] = useState(initiallyExpanded);
3654
+ const [showOrgUnitTree, setShowOrgUnitTree] = useState(!selected);
3655
+ useEffect(() => {
3656
+ setLoading(true);
3657
+ if (selected) {
3658
+ d2.httpInstance
3659
+ .get(`organisationUnits/${selected}.json?fields=id,displayName,path,code,ancestors[id,displayName]`)
3660
+ .then((response) => {
3661
+ if (response.data) {
3662
+ setSelectedOrgUnit(response.data);
3663
+ handleExpand({ path: response.data['path'] });
3664
+ setLoading(false);
3665
+ }
3666
+ });
3667
+ }
3668
+ else {
3669
+ setShowOrgUnitTree(true);
3670
+ setLoading(false);
3671
+ }
3672
+ }, []);
3673
+ const highlighted = useMemo(() => {
3674
+ if (selectedOrgUnit) {
3675
+ return [selectedOrgUnit['path']];
3676
+ }
3677
+ return undefined;
3678
+ }, [selectedOrgUnit]);
3679
+ const selectedOrgUnitLabel = useMemo(() => {
3680
+ if (selectedOrgUnit) {
3681
+ return [
3682
+ ...(selectedOrgUnit['ancestors'] || []),
3683
+ selectedOrgUnit,
3684
+ ]
3685
+ .map((orgUnit) => orgUnit['displayName'])
3686
+ .join(' / ');
3687
+ }
3688
+ return '';
3689
+ }, [selectedOrgUnit]);
3690
+ const handleExpand = ({ path }) => {
3691
+ if (expanded && !expanded.includes(path)) {
3692
+ setExpanded([...expanded, path]);
3693
+ }
3694
+ };
3695
+ const handleCollapse = ({ path }) => {
3696
+ const pathIndex = expanded?.indexOf(path);
3697
+ if (pathIndex && pathIndex !== -1 && expanded) {
3698
+ const updatedExpanded = pathIndex === 0
3699
+ ? expanded.slice(1)
3700
+ : [...expanded.slice(0, pathIndex), ...expanded.slice(pathIndex + 1)];
3701
+ setExpanded(updatedExpanded);
3702
+ }
3703
+ };
3704
+ const handleOrgUnitSearch = async (query) => {
3705
+ setSearchLoading(true);
3706
+ try {
3707
+ const searchResponse = await d2.httpInstance.get(`organisationUnits.json?fields=id,displayName,path,publicAccess,access,lastUpdated,children[id,displayName,publicAccess,access,path,children::isNotEmpty]&paging=true&query=${query}&withinUserSearchHierarchy=true&pageSize=15`);
3708
+ setSearchData((searchResponse.data || {})['organisationUnits']);
3709
+ setSearchLoading(false);
3710
+ }
3711
+ catch (e) {
3712
+ setSearchLoading(false);
3713
+ }
3714
+ };
3715
+ const debouncedSearch = useCallback(debounce((value) => {
3716
+ handleOrgUnitSearch(value);
3717
+ }, 500), []);
3718
+ const handleFilterChange = (event) => {
3719
+ setSearchText(event.value);
3720
+ debouncedSearch(event.value);
3721
+ };
3722
+ const ready = useMemo(() => {
3723
+ return searchText?.length ? !searchLoading : !loading;
3724
+ }, [searchText, searchLoading, loading]);
3725
+ const renderOrgUnitTree = () => {
3726
+ if (searchText && searchText?.length > 0) {
3727
+ if (searchLoading) {
3728
+ return (React__default.createElement("div", { className: classes.orgUnitTreeLoader },
3729
+ React__default.createElement(CircularLoader$1, { small: true })));
3730
+ }
3731
+ return (ready && (React__default.createElement(OrganisationUnitTree, { key: `${key}-search`, roots: searchData?.map((orgUnit) => orgUnit.id) || [], singleSelection: true, expanded: expanded, handleExpand: handleExpand, handleCollapse: handleCollapse, selected: highlighted, onChange: (event) => {
3732
+ setSelectedOrgUnit(event);
3733
+ setShowOrgUnitTree(false);
3734
+ onSelectOrgUnit(event);
3735
+ } })));
3736
+ }
3737
+ return (React__default.createElement(OrganisationUnitTree, { key: key, roots: rootOrgUnits?.map((orgUnit) => orgUnit.id) || [], singleSelection: true, expanded: expanded, handleExpand: handleExpand, handleCollapse: handleCollapse, selected: highlighted, onChange: (event) => {
3738
+ setSelectedOrgUnit(event);
3739
+ setShowOrgUnitTree(false);
3740
+ onSelectOrgUnit(event);
3741
+ } }));
3742
+ };
3743
+ const handleBlur = () => {
3744
+ // onBlur && onBlur(null);
3745
+ };
3746
+ return (config && (React__default.createElement(Provider, { config: config, plugin: false, parentAlertsAdd: undefined, showAlertsInPlugin: false },
3747
+ React__default.createElement("div", null,
3748
+ label && (React__default.createElement("div", { className: classes.orgUnitFieldLabel },
3749
+ React__default.createElement("span", null, label),
3750
+ required ? (React__default.createElement("span", { className: classes.orgUnitFieldRequiredLabel }, "*")) : (React__default.createElement(React__default.Fragment, null)))),
3751
+ !showOrgUnitTree ? (selectedOrgUnit ? (React__default.createElement(React__default.Fragment, null,
3752
+ React__default.createElement(Tooltip, { content: selectedOrgUnitLabel },
3753
+ React__default.createElement(Chip, { onRemove: () => {
3754
+ setShowOrgUnitTree(true);
3755
+ } }, selectedOrgUnit.displayName)))) : (React__default.createElement("div", { className: classes.orgUnitTreeLoader },
3756
+ React__default.createElement(CircularLoader$1, { small: true })))) : (React__default.createElement("div", { className: classes.container },
3757
+ React__default.createElement("div", { className: classes.debounceFieldContainer },
3758
+ React__default.createElement(InputField$1, { placeholder: "Search", value: searchText, disabled: disabled, onChange: handleFilterChange })),
3759
+ loading ? (React__default.createElement("div", { className: classes.orgUnitTreeLoader },
3760
+ React__default.createElement(CircularLoader$1, { small: true }))) : (React__default.createElement("div", { className: classes.orgUnitTreeContainer, style: { maxHeight: '200px', overflowY: 'auto' } }, renderOrgUnitTree()))))))));
3761
+ };
3762
+
3506
3763
  // src/app/line-list-table.component.ts
3507
3764
  class LineListTableComponent extends ReactWrapperModule {
3508
3765
  constructor() {
3509
3766
  super(...arguments);
3510
3767
  this.dispatchTeis = false;
3511
- this.showFilterButton = false;
3512
3768
  this.actionSelected = new EventEmitter();
3513
3769
  this.reactStateUpdaters = null;
3514
3770
  this.approvalSelected = new EventEmitter();
@@ -3516,6 +3772,7 @@ class LineListTableComponent extends ReactWrapperModule {
3516
3772
  this.buttonLabel = '';
3517
3773
  this.firstValue = new EventEmitter();
3518
3774
  this.filterRootOrgUnit = false;
3775
+ this.showFilters = false;
3519
3776
  this.setReactStateUpdaters = (updaters) => {
3520
3777
  this.reactStateUpdaters = updaters;
3521
3778
  };
@@ -3544,6 +3801,12 @@ class LineListTableComponent extends ReactWrapperModule {
3544
3801
  //TODO: this will be migrated on the parent component
3545
3802
  const [checkValue, setCheckValue] = useState([]);
3546
3803
  const [valueMatch, setValuesMatch] = useState(false);
3804
+ const [selectedOrgUnit, setSelectedOrgUnit] = useState(''); // for testing purposes to be removed
3805
+ const [hide, setHide] = useState(true);
3806
+ const [showAllFilters, setShowAllFilters] = useState(false);
3807
+ const visibleFilters = showAllFilters
3808
+ ? filteredColumns ?? []
3809
+ : (filteredColumns ?? []).slice(0, 2);
3547
3810
  // Store updaters in refs for Angular to access
3548
3811
  const updateRefs = useRef({
3549
3812
  setProgramIdState,
@@ -3557,25 +3820,10 @@ class LineListTableComponent extends ReactWrapperModule {
3557
3820
  useEffect(() => {
3558
3821
  this.setReactStateUpdaters?.(updateRefs.current);
3559
3822
  }, []);
3560
- useEffect(() => {
3561
- if (!loading) {
3562
- setTimeout(() => {
3563
- const paginationContainer = document.querySelector('[data-test="dhis2-uiwidgets-pagination"]');
3564
- if (paginationContainer) {
3565
- paginationContainer.style.display = 'flex';
3566
- paginationContainer.style.flexDirection = 'row';
3567
- paginationContainer.style.justifyContent = 'space-between';
3568
- paginationContainer.style.alignItems = 'center';
3569
- }
3570
- }, 500); // Short delay to ensure styles apply after data renders
3571
- }
3572
- }, [loading]);
3573
3823
  useEffect(() => {
3574
3824
  setLoading(true);
3575
3825
  this.lineListService
3576
- .getLineListData(this.programId, this.orgUnit, this.programStageId, pager.page, pager.pageSize, attributeFiltersState,
3577
- // this.attributeFilters,
3578
- this.startDate, this.endDate, this.ouMode, this.filterRootOrgUnit)
3826
+ .getLineListData(this.programId, orgUnitState, this.programStageId, pager.page, pager.pageSize, attributeFiltersState, startDateState, endDateState, this.ouMode, this.filterRootOrgUnit)
3579
3827
  .subscribe((response) => {
3580
3828
  let entityColumns = [];
3581
3829
  let responsePager;
@@ -3587,15 +3835,14 @@ class LineListTableComponent extends ReactWrapperModule {
3587
3835
  entityColumns = columns;
3588
3836
  entityData = data;
3589
3837
  }
3590
- else if ('trackedEntityInstances' in response.data) {
3591
- responsePager = response.data
3592
- .pager;
3838
+ else if ('trackedEntities' in response.data) {
3839
+ responsePager = response.data.pager;
3593
3840
  const { columns, data, filteredEntityColumns } = getTrackedEntityData(response, this.programId, pager, this.filters);
3594
3841
  entityColumns = columns;
3595
3842
  entityData = data;
3596
3843
  //TODO: Should be done on the parent
3597
3844
  let checkValues = [
3598
- ...new Set(response.data?.trackedEntityInstances?.[0]?.enrollments?.[0]?.events?.flatMap((event) => event.dataValues
3845
+ ...new Set(response.data?.trackedEntities?.[0]?.enrollments?.[0]?.events?.flatMap((event) => event.dataValues
3599
3846
  .filter((dataValue) => /^[A-Za-z]{3}$/.test(dataValue.value))
3600
3847
  .map((dataValue) => dataValue.value))),
3601
3848
  ];
@@ -3646,8 +3893,8 @@ class LineListTableComponent extends ReactWrapperModule {
3646
3893
  this.lineListService
3647
3894
  .getLineListData(this.programId, this.orgUnit, this.programStageId, pager.page, 1000, this.attributeFilters, this.startDate, this.endDate, this.ouMode)
3648
3895
  .subscribe((response) => {
3649
- if ('trackedEntityInstances' in response.data) {
3650
- const trackedEntityInstances = response.data.trackedEntityInstances;
3896
+ if ('trackedEntities' in response.data) {
3897
+ const trackedEntityInstances = response.data.trackedEntities;
3651
3898
  // Map TEIs to objects with teiId and enrollmentId
3652
3899
  const teiEnrollmentList = trackedEntityInstances
3653
3900
  .map((tei) => {
@@ -3656,7 +3903,7 @@ class LineListTableComponent extends ReactWrapperModule {
3656
3903
  // Return object with teiId and enrollmentId (if found)
3657
3904
  return matchingEnrollment
3658
3905
  ? {
3659
- teiId: tei.trackedEntityInstance,
3906
+ teiId: tei.trackedEntity,
3660
3907
  enrollmentId: matchingEnrollment.enrollment,
3661
3908
  }
3662
3909
  : null;
@@ -3685,55 +3932,17 @@ class LineListTableComponent extends ReactWrapperModule {
3685
3932
  });
3686
3933
  };
3687
3934
  return (React__default.createElement("div", null,
3688
- React__default.createElement("div", null,
3689
- valueMatch &&
3690
- this.dispatchTeis &&
3691
- (isButtonLoading ? (React__default.createElement(CircularLoader$1, { small: true })) : (
3692
- //TODO: this implementation should be done where the library will be consumed
3693
- React__default.createElement(Button$1, { style: {
3694
- backgroundColor: '#3b82f6',
3695
- color: 'white',
3696
- padding: '8px 16px',
3697
- borderRadius: '4px',
3698
- cursor: 'pointer',
3699
- }, onClick: handleApprovalClick, primary: true }, this.buttonLabel))),
3700
- this.showFilterButton && (React__default.createElement(Button$1
3701
- // style={{
3702
- // backgroundColor: '#6b7280',
3703
- // color: 'white',
3704
- // padding: '8px 16px',
3705
- // borderRadius: '4px',
3706
- // cursor: 'pointer',
3707
- // display: 'flex',
3708
- // alignItems: 'center',
3709
- // gap: 8,
3710
- // }}
3711
- , {
3712
- // style={{
3713
- // backgroundColor: '#6b7280',
3714
- // color: 'white',
3715
- // padding: '8px 16px',
3716
- // borderRadius: '4px',
3717
- // cursor: 'pointer',
3718
- // display: 'flex',
3719
- // alignItems: 'center',
3720
- // gap: 8,
3721
- // }}
3722
- onClick: () => {
3723
- setFilters(!filters);
3724
- }, secondary: true },
3725
- React__default.createElement(IconFilter16, null),
3726
- filters ? 'Hide Filters' : 'Show Filters'))),
3727
- filters && (React__default.createElement("div", null, (filteredColumns ?? []).map(({ label, key }) => (React__default.createElement(InputField$1, { key: key, label: label, value: inputValues[key] || '', onChange: (e) => {
3728
- // Check if it's a standard event with target.value
3729
- if ('target' in e && e.target) {
3730
- handleInputChange(key, e.target.value);
3731
- }
3732
- // Check if it's an event with direct value
3733
- else if ('value' in e) {
3734
- handleInputChange(key, e.value ?? '');
3735
- }
3736
- } }))))),
3935
+ React__default.createElement("div", null, valueMatch &&
3936
+ this.dispatchTeis &&
3937
+ (isButtonLoading ? (React__default.createElement(CircularLoader$1, { small: true })) : (
3938
+ //TODO: this implementation should be done where the library will be consumed
3939
+ React__default.createElement(Button$1, { style: {
3940
+ backgroundColor: '#3b82f6',
3941
+ color: 'white',
3942
+ padding: '8px 16px',
3943
+ borderRadius: '4px',
3944
+ cursor: 'pointer',
3945
+ }, onClick: handleApprovalClick, primary: true }, this.buttonLabel)))),
3737
3946
  loading ? (React__default.createElement("div", { style: {
3738
3947
  display: 'flex',
3739
3948
  alignItems: 'center',
@@ -3743,29 +3952,90 @@ class LineListTableComponent extends ReactWrapperModule {
3743
3952
  React__default.createElement(CircularLoader$1, { small: true }),
3744
3953
  React__default.createElement("div", { style: {
3745
3954
  fontSize: 14,
3746
- } }, "Loading"))) : (React__default.createElement(DataTable, null,
3747
- React__default.createElement(TableHead, null,
3748
- React__default.createElement(DataTableRow, null, columns.map((col) => (React__default.createElement(DataTableColumnHeader, { key: col.key }, col.label))))),
3749
- 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' ? (React__default.createElement(DropdownMenu$1, { dropdownOptions: getDropdownOptions(row), onClick: (option) => option.onClick?.() })) : (row[col.key] || '--' // Display '--' if value is undefined or null
3750
- )))))))) : (React__default.createElement(DataTableRow, null,
3751
- React__default.createElement(DataTableCell, { colSpan: columns.length?.toString(), style: {
3752
- textAlign: 'center',
3753
- fontWeight: 'bold',
3754
- color: 'grey',
3755
- padding: '20px',
3756
- } }, "No data found")))),
3757
- React__default.createElement(TableFoot, null,
3758
- React__default.createElement(DataTableRow, null,
3759
- React__default.createElement(DataTableCell, { colSpan: columns.length.toString() },
3760
- React__default.createElement("div", null,
3761
- React__default.createElement(Pagination, { page: pager.page, pageCount: pager.pageCount, pageSize: pager.pageSize, total: pager.total, onPageChange: (page) => setPager((prev) => ({ ...prev, page })), onPageSizeChange: (pageSize) => {
3762
- const newPageSize = Number(pageSize);
3763
- setPager((prev) => ({
3764
- ...prev,
3765
- page: 1,
3766
- pageSize: newPageSize,
3767
- }));
3768
- }, pageSizes: ['5', '10', '20', '50'] })))))))));
3955
+ } }, "Loading"))) : (
3956
+ // <div>
3957
+ // <div/>
3958
+ React__default.createElement("div", null,
3959
+ React__default.createElement(Modal$1, { hide: hide },
3960
+ React__default.createElement(ModalTitle$1, null, "Select organization unit"),
3961
+ React__default.createElement(ModalContent$1, null,
3962
+ React__default.createElement(OrgUnitFormField$1
3963
+ // label="Select organization unit"
3964
+ , {
3965
+ // label="Select organization unit"
3966
+ key: selectedOrgUnit, onSelectOrgUnit: (selectedOrgUnit) => {
3967
+ // console.log(
3968
+ // 'this is the selected org unit key',
3969
+ // selectedOrgUnit
3970
+ // );
3971
+ setSelectedOrgUnit(selectedOrgUnit.displayName);
3972
+ setOrgUnitState(selectedOrgUnit.id);
3973
+ setHide(true);
3974
+ } })),
3975
+ React__default.createElement(ModalActions$1, null,
3976
+ React__default.createElement(ButtonStrip$1, { end: true },
3977
+ React__default.createElement(Button$1, { onClick: () => setHide(true), secondary: true }, "Close")))),
3978
+ this.showFilters && (React__default.createElement(DataTableToolbar, { className: "table-top-toolbar" },
3979
+ React__default.createElement("div", { style: {
3980
+ display: 'flex',
3981
+ gap: '10px',
3982
+ flexWrap: 'wrap',
3983
+ } },
3984
+ React__default.createElement(InputField$1, { key: "location", label: "Location:", value: selectedOrgUnit, onFocus: () => setHide(false), className: "custom-input" }),
3985
+ React__default.createElement(CalendarInput, { label: "Start Date:", calendar: "gregory", locale: "en-GB", timeZone: "Africa/Dar_es_Salaam", className: "custom-input", date: startDateState, onDateSelect: (selectedDate) => {
3986
+ setStartDateState(selectedDate.calendarDateString);
3987
+ } }),
3988
+ React__default.createElement(CalendarInput, { label: "End Date:", calendar: "gregory", locale: "en-GB", timeZone: "Africa/Dar_es_Salaam", className: "custom-input", date: endDateState, onDateSelect: (selectedDate) => {
3989
+ setEndDateState(selectedDate.calendarDateString);
3990
+ } }),
3991
+ (visibleFilters ?? []).map(({ label, key }) => (React__default.createElement(InputField$1, { key: key, label: `${label}:`, className: "custom-input", value: inputValues[key] || '', onChange: (e) => {
3992
+ if ('target' in e && e.target) {
3993
+ setInputValues((prevValues) => ({
3994
+ ...prevValues,
3995
+ [key]: e
3996
+ .target.value,
3997
+ }));
3998
+ }
3999
+ else if ('value' in e) {
4000
+ setInputValues((prevValues) => ({
4001
+ ...prevValues,
4002
+ [key]: e.value ?? '',
4003
+ }));
4004
+ }
4005
+ }, onBlur: (e) => {
4006
+ let currentValue = '';
4007
+ if ('target' in e && e.target) {
4008
+ currentValue = e.target.value;
4009
+ }
4010
+ else if ('value' in e) {
4011
+ currentValue = e.value ?? '';
4012
+ }
4013
+ handleInputChange(key, currentValue);
4014
+ } }))),
4015
+ React__default.createElement(Button$1, { onClick: () => setShowAllFilters(!showAllFilters), className: "custom-button", secondary: true, large: true }, showAllFilters ? 'Less Filters' : 'More Filters')))),
4016
+ React__default.createElement(DataTable, null,
4017
+ React__default.createElement(TableHead, null,
4018
+ React__default.createElement(DataTableRow, null, columns.map((col) => (React__default.createElement(DataTableColumnHeader, { key: col.key }, col.label))))),
4019
+ 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' ? (React__default.createElement(DropdownMenu$1, { dropdownOptions: getDropdownOptions(row), onClick: (option) => option.onClick?.() })) : (row[col.key] || '--' // Display '--' if value is undefined or null
4020
+ )))))))) : (React__default.createElement(DataTableRow, null,
4021
+ React__default.createElement(DataTableCell, { colSpan: columns.length?.toString(), style: {
4022
+ textAlign: 'center',
4023
+ fontWeight: 'bold',
4024
+ color: 'grey',
4025
+ padding: '20px',
4026
+ } }, "No data found")))),
4027
+ React__default.createElement(TableFoot, null,
4028
+ React__default.createElement(DataTableRow, null,
4029
+ React__default.createElement(DataTableCell, { colSpan: columns.length.toString() },
4030
+ React__default.createElement("div", null,
4031
+ React__default.createElement(Pagination, { page: pager.page, pageCount: pager.pageCount, pageSize: pager.pageSize, total: pager.total, onPageChange: (page) => setPager((prev) => ({ ...prev, page })), onPageSizeChange: (pageSize) => {
4032
+ const newPageSize = Number(pageSize);
4033
+ setPager((prev) => ({
4034
+ ...prev,
4035
+ page: 1,
4036
+ pageSize: newPageSize,
4037
+ }));
4038
+ }, pageSizes: ['10', '20', '50', '100', '500'] }))))))))));
3769
4039
  };
3770
4040
  }
3771
4041
  ngOnChanges(changes) {
@@ -3801,11 +4071,11 @@ class LineListTableComponent extends ReactWrapperModule {
3801
4071
  this.render();
3802
4072
  }
3803
4073
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: LineListTableComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
3804
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.8", type: LineListTableComponent, isStandalone: false, selector: "app-line-list", inputs: { programId: "programId", orgUnit: "orgUnit", programStageId: "programStageId", actionOptions: "actionOptions", attributeFilters: "attributeFilters", startDate: "startDate", endDate: "endDate", filters: "filters", ouMode: "ouMode", dispatchTeis: "dispatchTeis", showFilterButton: "showFilterButton", isButtonLoading: "isButtonLoading", buttonLabel: "buttonLabel", buttonFilter: "buttonFilter", filterRootOrgUnit: "filterRootOrgUnit" }, outputs: { actionSelected: "actionSelected", approvalSelected: "approvalSelected", firstValue: "firstValue" }, usesInheritance: true, usesOnChanges: true, ngImport: i0, template: '<ng-content></ng-content>', isInline: true, styles: ["[data-test=dhis2-uiwidgets-pagination]{display:flex!important;flex-direction:row!important;justify-content:space-between!important;align-items:center!important}\n"] }); }
4074
+ 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", attributeFilters: "attributeFilters", startDate: "startDate", endDate: "endDate", filters: "filters", ouMode: "ouMode", dispatchTeis: "dispatchTeis", isButtonLoading: "isButtonLoading", buttonLabel: "buttonLabel", buttonFilter: "buttonFilter", filterRootOrgUnit: "filterRootOrgUnit", showFilters: "showFilters" }, 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;padding-left:16px}::ng-deep .custom-input input{border:none!important;outline:none!important;box-shadow:none!important}::ng-deep .custom-input input:focus{border:none!important;box-shadow:none!important}::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}\n"] }); }
3805
4075
  }
3806
4076
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: LineListTableComponent, decorators: [{
3807
4077
  type: Component,
3808
- args: [{ selector: 'app-line-list', template: '<ng-content></ng-content>', standalone: false, styles: ["[data-test=dhis2-uiwidgets-pagination]{display:flex!important;flex-direction:row!important;justify-content:space-between!important;align-items:center!important}\n"] }]
4078
+ args: [{ selector: 'ng-dhis2-ui-line-list', template: '<ng-content></ng-content>', standalone: false, styles: ["::ng-deep .custom-input{display:flex!important;gap:4px!important;align-items:center!important;border:1px solid #9FADBA!important;border-radius:4px!important;padding-left:16px}::ng-deep .custom-input input{border:none!important;outline:none!important;box-shadow:none!important}::ng-deep .custom-input input:focus{border:none!important;box-shadow:none!important}::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}\n"] }]
3809
4079
  }], propDecorators: { programId: [{
3810
4080
  type: Input
3811
4081
  }], orgUnit: [{
@@ -3826,8 +4096,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImpor
3826
4096
  type: Input
3827
4097
  }], dispatchTeis: [{
3828
4098
  type: Input
3829
- }], showFilterButton: [{
3830
- type: Input
3831
4099
  }], actionSelected: [{
3832
4100
  type: Output
3833
4101
  }], approvalSelected: [{
@@ -3842,11 +4110,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImpor
3842
4110
  type: Input
3843
4111
  }], filterRootOrgUnit: [{
3844
4112
  type: Input
4113
+ }], showFilters: [{
4114
+ type: Input
3845
4115
  }] } });
3846
4116
 
3847
4117
  class LineListModule {
3848
4118
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: LineListModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
3849
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.1.8", ngImport: i0, type: LineListModule, declarations: [LineListTableComponent], imports: [CommonModule, SharedDhis2UiModule], exports: [LineListTableComponent] }); }
4119
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.1.8", ngImport: i0, type: LineListModule, declarations: [LineListTableComponent], imports: [CommonModule, SharedDhis2UiModule, ReactWrapperModule], exports: [LineListTableComponent] }); }
3850
4120
  static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: LineListModule, providers: [LineListService], imports: [CommonModule, SharedDhis2UiModule] }); }
3851
4121
  }
3852
4122
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: LineListModule, decorators: [{
@@ -3854,7 +4124,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImpor
3854
4124
  args: [{
3855
4125
  declarations: [LineListTableComponent],
3856
4126
  exports: [LineListTableComponent],
3857
- imports: [CommonModule, SharedDhis2UiModule],
4127
+ imports: [CommonModule, SharedDhis2UiModule, ReactWrapperModule],
3858
4128
  providers: [LineListService],
3859
4129
  }]
3860
4130
  }] });