@iapps/ng-dhis2-ui 1.1.1 → 1.1.3

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.
Files changed (44) hide show
  1. package/fesm2022/iapps-ng-dhis2-ui.mjs +786 -232
  2. package/fesm2022/iapps-ng-dhis2-ui.mjs.map +1 -1
  3. package/index.d.ts +4 -1
  4. package/lib/modules/button/button.component.d.ts +2 -2
  5. package/lib/modules/data-table-ui/components/dropdown-menu/dropdown-menu.d.ts +19 -0
  6. package/lib/modules/data-table-ui/components/dropdown-menu/dropdown-menu.styles.d.ts +5 -0
  7. package/lib/modules/data-table-ui/components/dropdown-menu/index.d.ts +1 -0
  8. package/lib/modules/data-table-ui/containers/data-table-ui/data-table-ui.component.d.ts +19 -0
  9. package/lib/modules/data-table-ui/data-table-ui.module.d.ts +10 -0
  10. package/lib/modules/data-table-ui/hooks/index.d.ts +1 -0
  11. package/lib/modules/data-table-ui/hooks/use-dynamic-styles.hook.d.ts +1 -0
  12. package/lib/modules/data-table-ui/index.d.ts +3 -0
  13. package/lib/modules/data-table-ui/models/data-table.models.d.ts +10 -0
  14. package/lib/modules/form/components/base-form-field.component.d.ts +2 -2
  15. package/lib/modules/form/containers/repeatable-form/repeatable-form.component.d.ts +11 -4
  16. package/lib/modules/form/containers/section-form/section-form.component.d.ts +10 -9
  17. package/lib/modules/form/form.module.d.ts +3 -2
  18. package/lib/modules/form/interfaces/form-field-group.interface.d.ts +2 -1
  19. package/lib/modules/form/models/form-field-group.model.d.ts +1 -1
  20. package/lib/modules/form/models/form-metadata.model.d.ts +2 -1
  21. package/lib/modules/form/models/form-value.model.d.ts +3 -1
  22. package/lib/modules/form/utils/field-type.util.d.ts +1 -1
  23. package/lib/modules/form/utils/field.util.d.ts +1 -1
  24. package/lib/modules/form/utils/index.d.ts +1 -0
  25. package/lib/modules/form/utils/translation.util.d.ts +3 -0
  26. package/lib/modules/header-bar/header-bar.component.d.ts +2 -2
  27. package/lib/modules/line-list/containers/line-list.component.d.ts +6 -5
  28. package/lib/modules/line-list/models/line-list.models.d.ts +43 -0
  29. package/lib/modules/line-list/services/line-list.service.d.ts +1 -1
  30. package/lib/modules/organisation-unit-selector/containers/organisation-unit-selector/organisation-unit-selector.component.d.ts +2 -2
  31. package/lib/modules/organisation-unit-selector/containers/organisation-unit-selector-modal/organisation-unit-selector-modal.component-modal.d.ts +2 -2
  32. package/lib/modules/period-selector/containers/period-selector/period-selector.component.d.ts +2 -2
  33. package/lib/modules/period-selector/containers/period-selector-modal/period-selector-modal.component.d.ts +2 -2
  34. package/lib/modules/react-wrapper/react-wrapper.component.d.ts +3 -3
  35. package/lib/modules/selection-filters-ui/containers/selection-filters-ui/selection-filters-ui.component.d.ts +20 -0
  36. package/lib/modules/selection-filters-ui/index.d.ts +2 -0
  37. package/lib/modules/selection-filters-ui/models/selection-filters-ui.model.d.ts +36 -0
  38. package/lib/modules/selection-filters-ui/selection-filters-ui.module.d.ts +10 -0
  39. package/lib/modules/tracker-form/index.d.ts +2 -0
  40. package/lib/modules/tracker-form/tracker-form.component.d.ts +15 -0
  41. package/lib/modules/tracker-form/tracker-form.module.d.ts +9 -0
  42. package/package.json +1 -1
  43. package/lib/modules/react-wrapper/index.d.ts +0 -2
  44. package/lib/modules/react-wrapper/react-wrapper.module.d.ts +0 -8
@@ -27,7 +27,7 @@ import { MenuItem, MenuDivider } from '@dhis2-ui/menu';
27
27
  import parse from 'html-react-parser';
28
28
  import { Button as Button$1, IconDimensionData16, IconClock16, IconDimensionOrgUnit16, spacers as spacers$1, colors as colors$1, IconEdit16, theme as theme$1, Tooltip, 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, DataTable, TableHead, DataTableRow, DataTableColumnHeader, TableBody, DataTableCell, TableFoot, Pagination, FileInputField, FileListItem, TextAreaField } from '@dhis2/ui';
29
29
  import { getNowInCalendar, generateFixedPeriods } from '@dhis2/multi-calendar-dates';
30
- import { isObject, isString, sortBy, isArray, find, camelCase, flatten, head, range } from 'lodash';
30
+ import { isObject, isString, sortBy, isArray, find, camelCase, flatten, head, isEmpty } from 'lodash';
31
31
  import cx from 'classnames';
32
32
  import { map as map$1, switchMap } from 'rxjs/operators';
33
33
  import * as i2 from '@angular/forms';
@@ -1018,7 +1018,7 @@ HeaderBar.propTypes = {
1018
1018
  };
1019
1019
 
1020
1020
  window.React = React;
1021
- class ReactWrapperComponent {
1021
+ class ReactWrapperModule {
1022
1022
  constructor(elementRef) {
1023
1023
  this.elementRef = elementRef;
1024
1024
  }
@@ -1047,14 +1047,13 @@ class ReactWrapperComponent {
1047
1047
  " "));
1048
1048
  }
1049
1049
  }
1050
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: ReactWrapperComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); }
1051
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.1.8", type: ReactWrapperComponent, isStandalone: false, selector: "ng-dhis2-ui-wrapper", inputs: { props: "props", component: "component" }, queries: [{ propertyName: "content", first: true, predicate: ["ngDhis2UiContent"], descendants: true }], ngImport: i0 }); }
1050
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: ReactWrapperModule, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); }
1051
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.1.8", type: ReactWrapperModule, isStandalone: true, selector: "ng-dhis2-ui-wrapper", inputs: { props: "props", component: "component" }, queries: [{ propertyName: "content", first: true, predicate: ["ngDhis2UiContent"], descendants: true }], ngImport: i0 }); }
1052
1052
  }
1053
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: ReactWrapperComponent, decorators: [{
1053
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: ReactWrapperModule, decorators: [{
1054
1054
  type: Directive,
1055
1055
  args: [{
1056
1056
  selector: 'ng-dhis2-ui-wrapper',
1057
- standalone: false,
1058
1057
  }]
1059
1058
  }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { props: [{
1060
1059
  type: Input
@@ -1065,25 +1064,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImpor
1065
1064
  args: ['ngDhis2UiContent']
1066
1065
  }] } });
1067
1066
 
1068
- class ReactWrapperModule {
1069
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: ReactWrapperModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
1070
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.1.8", ngImport: i0, type: ReactWrapperModule, declarations: [ReactWrapperComponent], imports: [CommonModule], exports: [ReactWrapperComponent] }); }
1071
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: ReactWrapperModule, imports: [CommonModule] }); }
1072
- }
1073
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: ReactWrapperModule, decorators: [{
1074
- type: NgModule,
1075
- args: [{
1076
- imports: [CommonModule],
1077
- declarations: [ReactWrapperComponent],
1078
- exports: [ReactWrapperComponent],
1079
- }]
1080
- }] });
1081
-
1082
- // Copyright 2023 UDSM DHIS2 Lab. All rights reserved.
1083
- // Use of this source code is governed by a BSD-style
1084
- // license that can be found in the LICENSE file.
1085
-
1086
- class HeaderBarComponent extends ReactWrapperComponent {
1067
+ class HeaderBarComponent extends ReactWrapperModule {
1087
1068
  constructor(elementRef, httpClient) {
1088
1069
  super(elementRef);
1089
1070
  this.httpClient = httpClient;
@@ -1107,7 +1088,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImpor
1107
1088
  args: [{
1108
1089
  selector: 'ng-dhis2-ui-header-bar',
1109
1090
  template: `<ng-container></ng-container>`,
1110
- standalone: false
1091
+ standalone: false,
1111
1092
  }]
1112
1093
  }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i1.NgxDhis2HttpClientService }] });
1113
1094
 
@@ -1129,7 +1110,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImpor
1129
1110
  // Use of this source code is governed by a BSD-style
1130
1111
  // license that can be found in the LICENSE file.
1131
1112
 
1132
- class ButtonComponent extends ReactWrapperComponent {
1113
+ class ButtonComponent extends ReactWrapperModule {
1133
1114
  constructor() {
1134
1115
  super(...arguments);
1135
1116
  this.buttonClick = new EventEmitter();
@@ -1164,7 +1145,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImpor
1164
1145
  args: [{
1165
1146
  selector: 'ng-dhis2-ui-button',
1166
1147
  template: '<ng-content></ng-content>',
1167
- standalone: false
1148
+ standalone: false,
1168
1149
  }]
1169
1150
  }], propDecorators: { label: [{
1170
1151
  type: Input
@@ -2251,7 +2232,7 @@ PeriodDimension.defaultProps = {
2251
2232
  selectedPeriods: [],
2252
2233
  };
2253
2234
 
2254
- class PeriodSelectorModalComponent extends ReactWrapperComponent {
2235
+ class PeriodSelectorModalComponent extends ReactWrapperModule {
2255
2236
  constructor(elementRef, httpClient) {
2256
2237
  super(elementRef);
2257
2238
  this.httpClient = httpClient;
@@ -2321,7 +2302,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImpor
2321
2302
  type: Output
2322
2303
  }] } });
2323
2304
 
2324
- class PeriodSelectorComponent extends ReactWrapperComponent {
2305
+ class PeriodSelectorComponent extends ReactWrapperModule {
2325
2306
  constructor(elementRef, httpClient, ngZone) {
2326
2307
  super(elementRef);
2327
2308
  this.httpClient = httpClient;
@@ -2758,7 +2739,7 @@ class OrganisationUnitSelectionConfig {
2758
2739
  // Use of this source code is governed by a BSD-style
2759
2740
  // license that can be found in the LICENSE file.
2760
2741
 
2761
- class OrganisationUnitSelectorComponent extends ReactWrapperComponent {
2742
+ class OrganisationUnitSelectorComponent extends ReactWrapperModule {
2762
2743
  constructor(elementRef, httpClient, ngZone) {
2763
2744
  super(elementRef);
2764
2745
  this.httpClient = httpClient;
@@ -2839,7 +2820,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImpor
2839
2820
  type: Output
2840
2821
  }] } });
2841
2822
 
2842
- class OrganisationUnitSelectorModalComponent extends ReactWrapperComponent {
2823
+ class OrganisationUnitSelectorModalComponent extends ReactWrapperModule {
2843
2824
  constructor(elementRef, httpClient) {
2844
2825
  super(elementRef);
2845
2826
  this.httpClient = httpClient;
@@ -2967,6 +2948,102 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImpor
2967
2948
  // Use of this source code is governed by a BSD-style
2968
2949
  // license that can be found in the LICENSE file.
2969
2950
 
2951
+ const dropdownStyles$1 = {
2952
+ layer: {
2953
+ zIndex: '1 !important',
2954
+ },
2955
+ };
2956
+
2957
+ // Helper function to generate a unique class name
2958
+ const generateClassName$1 = (base) => `${base}-${Math.random().toString(36).substr(2, 9)}`;
2959
+ // Helper function to convert camelCased properties to hyphenated CSS properties
2960
+ const convertStylesToCSS$1 = (className, styles) => {
2961
+ let cssString = `.${className} {`;
2962
+ for (const key in styles) {
2963
+ if (typeof styles[key] === "object" && key.startsWith("@media")) {
2964
+ const mediaStyles = convertStylesToCSS$1(className, styles[key]);
2965
+ cssString += `${key} { ${mediaStyles} }`;
2966
+ }
2967
+ else if (key.startsWith("&:")) {
2968
+ const pseudoClass = key.replace("&", "");
2969
+ cssString += `${pseudoClass} { ${convertStylesToCSS$1("", styles[key])} }`;
2970
+ }
2971
+ else {
2972
+ const cssKey = key.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
2973
+ cssString += `${cssKey}: ${styles[key]}; `;
2974
+ }
2975
+ }
2976
+ cssString += "}";
2977
+ return cssString;
2978
+ };
2979
+ // Custom hook for dynamic styles with generics
2980
+ const useDynamicStyles$1 = (stylesObj) => {
2981
+ const [classNames, setClassNames] = useState({});
2982
+ useEffect(() => {
2983
+ const convertedStyles = Object.keys(stylesObj).map((key) => {
2984
+ const className = generateClassName$1(key);
2985
+ const styleElement = document.createElement("style");
2986
+ styleElement.innerHTML = convertStylesToCSS$1(className, stylesObj[key]);
2987
+ document.head.appendChild(styleElement);
2988
+ return {
2989
+ key,
2990
+ className,
2991
+ styleElement,
2992
+ };
2993
+ });
2994
+ setClassNames(convertedStyles.reduce((classNameEntity, convertedStyle) => {
2995
+ return {
2996
+ ...classNameEntity,
2997
+ [convertedStyle.key]: convertedStyle.className,
2998
+ };
2999
+ }, {}));
3000
+ return () => {
3001
+ convertedStyles.forEach((convertedStyle) => {
3002
+ document.head.removeChild(convertedStyle.styleElement);
3003
+ });
3004
+ };
3005
+ }, []);
3006
+ return classNames;
3007
+ };
3008
+
3009
+ const useCurrentModal$1 = () => {
3010
+ const [CurrentModal, setCurrentModal] = useState();
3011
+ return [
3012
+ CurrentModal,
3013
+ (Modal) => {
3014
+ // As setState supports functional updates, we can't pass functional
3015
+ // components directly
3016
+ setCurrentModal(() => Modal);
3017
+ },
3018
+ ];
3019
+ };
3020
+ const ContextMenu$1 = (params) => {
3021
+ const { onClose, onMenuClick, anchorRef, dropDownOptions } = params;
3022
+ const [CurrentModal, setCurrentModal] = useCurrentModal$1();
3023
+ const styles = useDynamicStyles$1(dropdownStyles$1);
3024
+ return (React__default.createElement(React__default.Fragment, null,
3025
+ React__default.createElement(Layer$1, { onBackdropClick: (event, data) => onClose(event, data), className: styles.layer },
3026
+ React__default.createElement(Popper, { reference: anchorRef, placement: "bottom-start" },
3027
+ React__default.createElement(FlyoutMenu, null, dropDownOptions.map((dropDownOption, index) => (React__default.createElement(MenuItem$1, { key: index, destructive: dropDownOption.destructive, label: dropDownOption.label, icon: dropDownOption.icon, onClick: () => {
3028
+ onMenuClick(dropDownOption);
3029
+ onClose();
3030
+ }, dense: true })))))),
3031
+ CurrentModal && (React__default.createElement(CurrentModal, { onClose: () => {
3032
+ onClose();
3033
+ setCurrentModal(null);
3034
+ } }))));
3035
+ };
3036
+ const DropdownMenu$1 = (props) => {
3037
+ const ref = useRef();
3038
+ const [visible, setVisible] = useState(false);
3039
+ const { dropdownOptions, onClick } = props;
3040
+ return (React__default.createElement("div", { ref: ref, style: { display: "inline-block" } },
3041
+ React__default.createElement(Button$1, { small: true, secondary: true, icon: React__default.createElement(IconMore24, { color: colors$1.grey600 }), onClick: () => setVisible(true) }),
3042
+ visible && (React__default.createElement(ContextMenu$1, { dropDownOptions: dropdownOptions, anchorRef: ref, onClose: () => setVisible(false), onMenuClick: (dropDownOption) => {
3043
+ onClick(dropDownOption);
3044
+ } }))));
3045
+ };
3046
+
2970
3047
  // export function buildFilters(filters: AttributeFilter[]): string {
2971
3048
  // return filters
2972
3049
  // .map(({ attribute, operator, value }) => `filter=${attribute}:${operator}:${value}`)
@@ -3031,12 +3108,13 @@ class LineListService {
3031
3108
  this.httpClient = httpClient;
3032
3109
  }
3033
3110
  getProgramMetadata(programId) {
3034
- return this.httpClient.get(`programs/${programId}.json?fields=programType,programStages[id,name,programStageDataElements[dataElement[id,name]]],organisationUnits[id,name]`);
3111
+ return this.httpClient.get(`programs/${programId}.json?fields=programType,programStages[id,name,programStageDataElements[dataElement[id,name]]],organisationUnits[id,name],*`);
3035
3112
  }
3036
- getTrackedEntityInstances(programId, orgUnit, page, pageSize, filters = [], startDate, endDate) {
3113
+ getTrackedEntityInstances(programId, orgUnit, page, pageSize, filters = [], startDate, endDate, ouMode) {
3037
3114
  const filterParams = buildFilters(filters);
3038
3115
  const dateFilter = startDate && endDate ? `&programStartDate=${startDate}&programEndDate=${endDate}` : '';
3039
- return this.httpClient.get(`trackedEntityInstances.json?program=${programId}&ou=${orgUnit}&page=${page}&pageSize=${pageSize}&fields=trackedEntityInstance,attributes[*],enrollments[*]&totalPages=true&${filterParams}${dateFilter}`).pipe(map$1((response) => {
3116
+ const ouModeIdentifier = ouMode ? `&ouMode=${ouMode}` : ``;
3117
+ return this.httpClient.get(`trackedEntityInstances.json?program=${programId}&ou=${orgUnit}${ouModeIdentifier}&page=${page}&pageSize=${pageSize}&fields=trackedEntityInstance,attributes[*,displayInList],enrollments[*]&totalPages=true&${filterParams}${dateFilter}`).pipe(map$1((response) => {
3040
3118
  response.trackedEntityInstances.forEach((tei) => {
3041
3119
  // Filter attributes to only include those with displayInList=true
3042
3120
  tei.attributes = tei.attributes.filter((attr) => attr.displayInList);
@@ -3044,32 +3122,34 @@ class LineListService {
3044
3122
  return response;
3045
3123
  }));
3046
3124
  }
3047
- getEvents(programId, orgUnit, page, pageSize, filters = [], startDate, endDate) {
3125
+ getEvents(programId, orgUnit, page, pageSize, filters = [], startDate, endDate, ouMode) {
3048
3126
  const filterParams = buildFilters(filters);
3049
3127
  const dateFilter = startDate && endDate ? `&startDate=${startDate}&endDate=${endDate}` : '';
3050
- return this.httpClient.get(`events.json?program=${programId}&orgUnit=${orgUnit}&page=${page}&pageSize=${pageSize}&fields=*&totalPages=true&${filterParams}${dateFilter}`);
3128
+ const ouModeIdentifier = ouMode ? `&ouMode=${ouMode}` : ``;
3129
+ return this.httpClient.get(`events.json?program=${programId}&orgUnit=${orgUnit}${ouModeIdentifier}&page=${page}&pageSize=${pageSize}&fields=*&totalPages=true&${filterParams}${dateFilter}`);
3051
3130
  }
3052
- getEventsByProgramStage(programStageId, orgUnit, page, pageSize, filters = [], startDate, endDate) {
3131
+ getEventsByProgramStage(programStageId, orgUnit, page, pageSize, filters = [], startDate, endDate, ouMode) {
3053
3132
  const filterParams = buildFilters(filters);
3054
3133
  const dateFilter = startDate && endDate ? `&startDate=${startDate}&endDate=${endDate}` : '';
3055
- return this.httpClient.get(`events.json?programStage=${programStageId}&orgUnit=${orgUnit}&page=${page}&pageSize=${pageSize}&fields=*&totalPages=true&${filterParams}${dateFilter}`);
3134
+ const ouModeIdentifier = ouMode ? `&ouMode=${ouMode}` : ``;
3135
+ return this.httpClient.get(`events.json?programStage=${programStageId}&orgUnit=${orgUnit}${ouModeIdentifier}&page=${page}&pageSize=${pageSize}&fields=*&totalPages=true&${filterParams}${dateFilter}`);
3056
3136
  }
3057
- getLineListData(programId, orgUnit = '', programStageId, page = 1, pageSize = 10, filters = [], startDate, endDate) {
3137
+ getLineListData(programId, orgUnit = '', programStageId, page = 1, pageSize = 10, filters = [], startDate, endDate, ouMode) {
3058
3138
  return this.getProgramMetadata(programId).pipe(switchMap((programMetadata) => {
3059
3139
  if (programStageId) {
3060
- return this.getEventsByProgramStage(programStageId, orgUnit, page, pageSize, filters, startDate, endDate).pipe(map$1((events) => ({
3140
+ return this.getEventsByProgramStage(programStageId, orgUnit, page, pageSize, filters, startDate, endDate, ouMode).pipe(map$1((events) => ({
3061
3141
  metadata: programMetadata,
3062
3142
  data: events,
3063
3143
  })));
3064
3144
  }
3065
3145
  if (programMetadata.programType === 'WITH_REGISTRATION') {
3066
- return this.getTrackedEntityInstances(programId, orgUnit, page, pageSize, filters, startDate, endDate).pipe(map$1((teis) => ({
3146
+ return this.getTrackedEntityInstances(programId, orgUnit, page, pageSize, filters, startDate, endDate, ouMode).pipe(map$1((teis) => ({
3067
3147
  metadata: programMetadata,
3068
3148
  data: teis,
3069
3149
  })));
3070
3150
  }
3071
3151
  else {
3072
- return this.getEvents(programId, orgUnit, page, pageSize, filters, startDate, endDate).pipe(map$1((events) => ({
3152
+ return this.getEvents(programId, orgUnit, page, pageSize, filters, startDate, endDate, ouMode).pipe(map$1((events) => ({
3073
3153
  metadata: programMetadata,
3074
3154
  data: events,
3075
3155
  })));
@@ -3083,102 +3163,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImpor
3083
3163
  type: Injectable
3084
3164
  }], ctorParameters: () => [{ type: i1.NgxDhis2HttpClientService }] });
3085
3165
 
3086
- const dropdownStyles = {
3087
- layer: {
3088
- zIndex: '1 !important',
3089
- },
3090
- };
3091
-
3092
- // Helper function to generate a unique class name
3093
- const generateClassName = (base) => `${base}-${Math.random().toString(36).substr(2, 9)}`;
3094
- // Helper function to convert camelCased properties to hyphenated CSS properties
3095
- const convertStylesToCSS = (className, styles) => {
3096
- let cssString = `.${className} {`;
3097
- for (const key in styles) {
3098
- if (typeof styles[key] === "object" && key.startsWith("@media")) {
3099
- const mediaStyles = convertStylesToCSS(className, styles[key]);
3100
- cssString += `${key} { ${mediaStyles} }`;
3101
- }
3102
- else if (key.startsWith("&:")) {
3103
- const pseudoClass = key.replace("&", "");
3104
- cssString += `${pseudoClass} { ${convertStylesToCSS("", styles[key])} }`;
3105
- }
3106
- else {
3107
- const cssKey = key.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
3108
- cssString += `${cssKey}: ${styles[key]}; `;
3109
- }
3110
- }
3111
- cssString += "}";
3112
- return cssString;
3113
- };
3114
- // Custom hook for dynamic styles with generics
3115
- const useDynamicStyles = (stylesObj) => {
3116
- const [classNames, setClassNames] = useState({});
3117
- useEffect(() => {
3118
- const convertedStyles = Object.keys(stylesObj).map((key) => {
3119
- const className = generateClassName(key);
3120
- const styleElement = document.createElement("style");
3121
- styleElement.innerHTML = convertStylesToCSS(className, stylesObj[key]);
3122
- document.head.appendChild(styleElement);
3123
- return {
3124
- key,
3125
- className,
3126
- styleElement,
3127
- };
3128
- });
3129
- setClassNames(convertedStyles.reduce((classNameEntity, convertedStyle) => {
3130
- return {
3131
- ...classNameEntity,
3132
- [convertedStyle.key]: convertedStyle.className,
3133
- };
3134
- }, {}));
3135
- return () => {
3136
- convertedStyles.forEach((convertedStyle) => {
3137
- document.head.removeChild(convertedStyle.styleElement);
3138
- });
3139
- };
3140
- }, []);
3141
- return classNames;
3142
- };
3143
-
3144
- const useCurrentModal = () => {
3145
- const [CurrentModal, setCurrentModal] = useState();
3146
- return [
3147
- CurrentModal,
3148
- (Modal) => {
3149
- // As setState supports functional updates, we can't pass functional
3150
- // components directly
3151
- setCurrentModal(() => Modal);
3152
- },
3153
- ];
3154
- };
3155
- const ContextMenu = (params) => {
3156
- const { onClose, onMenuClick, anchorRef, dropDownOptions } = params;
3157
- const [CurrentModal, setCurrentModal] = useCurrentModal();
3158
- const styles = useDynamicStyles(dropdownStyles);
3159
- return (React__default.createElement(React__default.Fragment, null,
3160
- React__default.createElement(Layer$1, { onBackdropClick: (event, data) => onClose(event, data), className: styles.layer },
3161
- React__default.createElement(Popper, { reference: anchorRef, placement: "bottom-start" },
3162
- React__default.createElement(FlyoutMenu, null, dropDownOptions.map((dropDownOption, index) => (React__default.createElement(MenuItem$1, { key: index, destructive: dropDownOption.destructive, label: dropDownOption.label, icon: dropDownOption.icon, onClick: () => {
3163
- onMenuClick(dropDownOption);
3164
- onClose();
3165
- }, dense: true })))))),
3166
- CurrentModal && (React__default.createElement(CurrentModal, { onClose: () => {
3167
- onClose();
3168
- setCurrentModal(null);
3169
- } }))));
3170
- };
3171
- const DropdownMenu = (props) => {
3172
- const ref = useRef();
3173
- const [visible, setVisible] = useState(false);
3174
- const { dropdownOptions, onClick } = props;
3175
- return (React__default.createElement("div", { ref: ref, style: { display: "inline-block" } },
3176
- React__default.createElement(Button$1, { small: true, secondary: true, icon: React__default.createElement(IconMore24, { color: colors$1.grey600 }), onClick: () => setVisible(true) }),
3177
- visible && (React__default.createElement(ContextMenu, { dropDownOptions: dropdownOptions, anchorRef: ref, onClose: () => setVisible(false), onMenuClick: (dropDownOption) => {
3178
- onClick(dropDownOption);
3179
- } }))));
3180
- };
3181
-
3182
3166
  const getProgramStageData = (response, programStageId, pager) => {
3183
3167
  const events = response.data.events;
3184
3168
  const allDataElements = new Set();
@@ -3207,6 +3191,14 @@ const getProgramStageData = (response, programStageId, pager) => {
3207
3191
  const getTrackedEntityData = (response, programId, pager, filters) => {
3208
3192
  let teis = response.data
3209
3193
  .trackedEntityInstances;
3194
+ let programMetaData = response.metadata.programTrackedEntityAttributes;
3195
+ const programAttributesMap = programMetaData.reduce((acc, attribute) => {
3196
+ if (attribute.displayInList) {
3197
+ acc[attribute.id] = attribute.displayName;
3198
+ }
3199
+ return acc;
3200
+ }, {});
3201
+ console.log('metadata', programAttributesMap);
3210
3202
  if (filters) {
3211
3203
  teis = getFilteredTrackedEntityInstances(teis, filters);
3212
3204
  }
@@ -3218,7 +3210,12 @@ const getTrackedEntityData = (response, programId, pager, filters) => {
3218
3210
  : tei.attributes;
3219
3211
  attributes.forEach((attr) => allAttributes.add(attr.attribute));
3220
3212
  });
3221
- const entityColumns = Array.from(allAttributes).map((attrId) => {
3213
+ console.log('all of the attributes', allAttributes);
3214
+ // const filteredAttributes = new Set(
3215
+ // [...allAttributes].filter((attributeId) => programAttributesMap[attributeId])
3216
+ // );
3217
+ // console.log('Filtered All Attributes:', filteredAttributes);
3218
+ let entityColumns = Array.from(allAttributes).map((attrId) => {
3222
3219
  const foundAttribute = teis
3223
3220
  .flatMap((tei) => {
3224
3221
  const matchingEnrollment = tei.enrollments.find((enrollment) => enrollment.program === programId);
@@ -3232,6 +3229,10 @@ const getTrackedEntityData = (response, programId, pager, filters) => {
3232
3229
  key: attrId,
3233
3230
  };
3234
3231
  });
3232
+ entityColumns = entityColumns.filter((column) => {
3233
+ // Check if the column label is part of any value in programAttributesMap
3234
+ return Object.values(programAttributesMap).some((value) => value.includes(column.label));
3235
+ });
3235
3236
  const attributesData = teis.map((tei, idx) => {
3236
3237
  let row = {
3237
3238
  trackedEntityInstance: tei.trackedEntityInstance,
@@ -3278,7 +3279,7 @@ const addActionsColumn = (columns, actionOptions) => {
3278
3279
  };
3279
3280
 
3280
3281
  // src/app/line-list-table.component.ts
3281
- class LineListTableComponent extends ReactWrapperComponent {
3282
+ class LineListTableComponent extends ReactWrapperModule {
3282
3283
  constructor() {
3283
3284
  super(...arguments);
3284
3285
  this.actionSelected = new EventEmitter();
@@ -3332,7 +3333,7 @@ class LineListTableComponent extends ReactWrapperComponent {
3332
3333
  useEffect(() => {
3333
3334
  setLoading(true);
3334
3335
  this.lineListService
3335
- .getLineListData(this.programId, this.orgUnit, this.programStageId, pager.page, pager.pageSize, this.attributeFilters, this.startDate, this.endDate)
3336
+ .getLineListData(this.programId, this.orgUnit, this.programStageId, pager.page, pager.pageSize, this.attributeFilters, this.startDate, this.endDate, this.ouMode)
3336
3337
  .subscribe((response) => {
3337
3338
  let entityColumns = [];
3338
3339
  let responsePager;
@@ -3384,23 +3385,31 @@ class LineListTableComponent extends ReactWrapperComponent {
3384
3385
  },
3385
3386
  }));
3386
3387
  };
3387
- return (React__default.createElement("div", null, loading ? (React__default.createElement(CircularLoader$1, null)) :
3388
- (React__default.createElement(DataTable, null,
3389
- React__default.createElement(TableHead, null,
3390
- React__default.createElement(DataTableRow, null, columns.map((col) => (React__default.createElement(DataTableColumnHeader, { key: col.key }, col.label))))),
3391
- React__default.createElement(TableBody, null, 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, { dropdownOptions: getDropdownOptions(row), onClick: (option) => option.onClick?.() })) : (row[col.key])))))))),
3392
- React__default.createElement(TableFoot, null,
3393
- React__default.createElement(DataTableRow, null,
3394
- React__default.createElement(DataTableCell, { colSpan: columns.length.toString() },
3395
- React__default.createElement("div", null,
3396
- React__default.createElement(Pagination, { page: pager.page, pageCount: pager.pageCount, pageSize: pager.pageSize, total: pager.total, onPageChange: (page) => setPager((prev) => ({ ...prev, page })), onPageSizeChange: (pageSize) => {
3397
- const newPageSize = Number(pageSize);
3398
- setPager((prev) => ({
3399
- ...prev,
3400
- page: 1,
3401
- pageSize: newPageSize,
3402
- }));
3403
- }, pageSizes: ['5', '10', '20', '50'] })))))))));
3388
+ return (React__default.createElement("div", null, loading ? (React__default.createElement("div", { style: {
3389
+ display: 'flex',
3390
+ alignItems: 'center',
3391
+ gap: 8,
3392
+ padding: 8,
3393
+ } },
3394
+ React__default.createElement(CircularLoader$1, { small: true }),
3395
+ React__default.createElement("div", { style: {
3396
+ fontSize: 14,
3397
+ } }, "Loading"))) : (React__default.createElement(DataTable, null,
3398
+ React__default.createElement(TableHead, null,
3399
+ React__default.createElement(DataTableRow, null, columns.map((col) => (React__default.createElement(DataTableColumnHeader, { key: col.key }, col.label))))),
3400
+ React__default.createElement(TableBody, null, 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])))))))),
3401
+ React__default.createElement(TableFoot, null,
3402
+ React__default.createElement(DataTableRow, null,
3403
+ React__default.createElement(DataTableCell, { colSpan: columns.length.toString() },
3404
+ React__default.createElement("div", null,
3405
+ React__default.createElement(Pagination, { page: pager.page, pageCount: pager.pageCount, pageSize: pager.pageSize, total: pager.total, onPageChange: (page) => setPager((prev) => ({ ...prev, page })), onPageSizeChange: (pageSize) => {
3406
+ const newPageSize = Number(pageSize);
3407
+ setPager((prev) => ({
3408
+ ...prev,
3409
+ page: 1,
3410
+ pageSize: newPageSize,
3411
+ }));
3412
+ }, pageSizes: ['5', '10', '20', '50'] })))))))));
3404
3413
  };
3405
3414
  }
3406
3415
  ngOnChanges(changes) {
@@ -3433,7 +3442,7 @@ class LineListTableComponent extends ReactWrapperComponent {
3433
3442
  this.render();
3434
3443
  }
3435
3444
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: LineListTableComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
3436
- 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" }, outputs: { actionSelected: "actionSelected" }, 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"] }); }
3445
+ 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" }, outputs: { actionSelected: "actionSelected" }, 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"] }); }
3437
3446
  }
3438
3447
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: LineListTableComponent, decorators: [{
3439
3448
  type: Component,
@@ -3454,6 +3463,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImpor
3454
3463
  type: Input
3455
3464
  }], filters: [{
3456
3465
  type: Input
3466
+ }], ouMode: [{
3467
+ type: Input
3457
3468
  }], actionSelected: [{
3458
3469
  type: Output
3459
3470
  }] } });
@@ -3473,6 +3484,186 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImpor
3473
3484
  }]
3474
3485
  }] });
3475
3486
 
3487
+ const dropdownStyles = {
3488
+ layer: {
3489
+ zIndex: '1 !important',
3490
+ },
3491
+ };
3492
+
3493
+ // Helper function to generate a unique class name
3494
+ const generateClassName = (base) => `${base}-${Math.random().toString(36).substr(2, 9)}`;
3495
+ // Helper function to convert camelCased properties to hyphenated CSS properties
3496
+ const convertStylesToCSS = (className, styles) => {
3497
+ let cssString = `.${className} {`;
3498
+ for (const key in styles) {
3499
+ if (typeof styles[key] === "object" && key.startsWith("@media")) {
3500
+ const mediaStyles = convertStylesToCSS(className, styles[key]);
3501
+ cssString += `${key} { ${mediaStyles} }`;
3502
+ }
3503
+ else if (key.startsWith("&:")) {
3504
+ const pseudoClass = key.replace("&", "");
3505
+ cssString += `${pseudoClass} { ${convertStylesToCSS("", styles[key])} }`;
3506
+ }
3507
+ else {
3508
+ const cssKey = key.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
3509
+ cssString += `${cssKey}: ${styles[key]}; `;
3510
+ }
3511
+ }
3512
+ cssString += "}";
3513
+ return cssString;
3514
+ };
3515
+ // Custom hook for dynamic styles with generics
3516
+ const useDynamicStyles = (stylesObj) => {
3517
+ const [classNames, setClassNames] = useState({});
3518
+ useEffect(() => {
3519
+ const convertedStyles = Object.keys(stylesObj).map((key) => {
3520
+ const className = generateClassName(key);
3521
+ const styleElement = document.createElement("style");
3522
+ styleElement.innerHTML = convertStylesToCSS(className, stylesObj[key]);
3523
+ document.head.appendChild(styleElement);
3524
+ return {
3525
+ key,
3526
+ className,
3527
+ styleElement,
3528
+ };
3529
+ });
3530
+ setClassNames(convertedStyles.reduce((classNameEntity, convertedStyle) => {
3531
+ return {
3532
+ ...classNameEntity,
3533
+ [convertedStyle.key]: convertedStyle.className,
3534
+ };
3535
+ }, {}));
3536
+ return () => {
3537
+ convertedStyles.forEach((convertedStyle) => {
3538
+ document.head.removeChild(convertedStyle.styleElement);
3539
+ });
3540
+ };
3541
+ }, []);
3542
+ return classNames;
3543
+ };
3544
+
3545
+ const useCurrentModal = () => {
3546
+ const [CurrentModal, setCurrentModal] = useState();
3547
+ return [
3548
+ CurrentModal,
3549
+ (Modal) => {
3550
+ // As setState supports functional updates, we can't pass functional
3551
+ // components directly
3552
+ setCurrentModal(() => Modal);
3553
+ },
3554
+ ];
3555
+ };
3556
+ const ContextMenu = (params) => {
3557
+ const { onClose, onMenuClick, anchorRef, dropDownOptions } = params;
3558
+ const [CurrentModal, setCurrentModal] = useCurrentModal();
3559
+ const styles = useDynamicStyles(dropdownStyles);
3560
+ return (React__default.createElement(React__default.Fragment, null,
3561
+ React__default.createElement(Layer$1, { onBackdropClick: (event, data) => onClose(event, data), className: styles.layer },
3562
+ React__default.createElement(Popper, { reference: anchorRef, placement: "bottom-start" },
3563
+ React__default.createElement(FlyoutMenu, null, dropDownOptions.map((dropDownOption, index) => (React__default.createElement(MenuItem$1, { key: index, destructive: dropDownOption.destructive, label: dropDownOption.label, icon: dropDownOption.icon, onClick: () => {
3564
+ onMenuClick(dropDownOption);
3565
+ onClose();
3566
+ }, dense: true })))))),
3567
+ CurrentModal && (React__default.createElement(CurrentModal, { onClose: () => {
3568
+ onClose();
3569
+ setCurrentModal(null);
3570
+ } }))));
3571
+ };
3572
+ const DropdownMenu = (props) => {
3573
+ const ref = useRef();
3574
+ const [visible, setVisible] = useState(false);
3575
+ const { dropdownOptions, onClick } = props;
3576
+ return (React__default.createElement("div", { ref: ref, style: { display: "inline-block" } },
3577
+ React__default.createElement(Button$1, { small: true, secondary: true, icon: React__default.createElement(IconMore24, { color: colors$1.grey600 }), onClick: () => setVisible(true) }),
3578
+ visible && (React__default.createElement(ContextMenu, { dropDownOptions: dropdownOptions, anchorRef: ref, onClose: () => setVisible(false), onMenuClick: (dropDownOption) => {
3579
+ onClick(dropDownOption);
3580
+ } }))));
3581
+ };
3582
+
3583
+ class DataTableUIComponent extends ReactWrapperModule {
3584
+ constructor() {
3585
+ super(...arguments);
3586
+ this.actionSelected = new EventEmitter();
3587
+ this.DataTableUI = () => {
3588
+ const [columns, setColumns] = useState([]);
3589
+ const [tableData, setTableData] = useState([]);
3590
+ useEffect(() => {
3591
+ if (!this.data || !this.columnDefinitions)
3592
+ return;
3593
+ const filteredColumns = this.columnDefinitions.filter((col) => col.visible !== false);
3594
+ const sortedColumns = filteredColumns.sort((a, b) => {
3595
+ const indexA = Number(a.index) || 0;
3596
+ const indexB = Number(b.index) || 0;
3597
+ return indexA - indexB;
3598
+ });
3599
+ setColumns(sortedColumns);
3600
+ setTableData(this.data);
3601
+ }, [this.data, this.columnDefinitions]);
3602
+ const getDropdownOptions = (row) => {
3603
+ return (this.actionOptions || []).map((option) => ({
3604
+ ...option,
3605
+ onClick: () => {
3606
+ // Ensure the onClick is called with the correct context
3607
+ if (option.onClick) {
3608
+ option.onClick(row); // Passing row to the handler
3609
+ }
3610
+ this.actionSelected.emit({ action: option.label, row }); // Emit action and row details
3611
+ },
3612
+ }));
3613
+ };
3614
+ return (React__default.createElement("div", null,
3615
+ React__default.createElement(DataTable, null,
3616
+ React__default.createElement(TableHead, null,
3617
+ React__default.createElement(DataTableRow, null,
3618
+ columns.map((col) => (React__default.createElement(DataTableColumnHeader, { key: col.column }, col.display))),
3619
+ this.actionOptions && this.actionOptions.length > 0 && (React__default.createElement(DataTableColumnHeader, null, "Actions")))),
3620
+ React__default.createElement(TableBody, null, tableData.map((row, rowIndex) => (React__default.createElement(DataTableRow, { key: rowIndex },
3621
+ columns.map((col) => (React__default.createElement(DataTableCell, { key: col.column }, row[col.column] || '-'))),
3622
+ this.actionOptions && this.actionOptions.length > 0 && (React__default.createElement(DataTableCell, null,
3623
+ React__default.createElement(DropdownMenu, { dropdownOptions: getDropdownOptions(row), onClick: (option) => option.onClick?.(row) }))))))),
3624
+ React__default.createElement(TableFoot, null,
3625
+ React__default.createElement(DataTableRow, null,
3626
+ React__default.createElement(DataTableCell, { colSpan: columns.length + 1 }))))));
3627
+ };
3628
+ }
3629
+ async ngAfterViewInit() {
3630
+ if (!this.elementRef)
3631
+ throw new Error('No element ref');
3632
+ this.reactDomRoot = ReactDOM.createRoot(this.elementRef.nativeElement);
3633
+ this.component = this.DataTableUI;
3634
+ this.render();
3635
+ }
3636
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: DataTableUIComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
3637
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.8", type: DataTableUIComponent, isStandalone: false, selector: "app-data-table-ui", inputs: { data: "data", columnDefinitions: "columnDefinitions", actionOptions: "actionOptions" }, outputs: { actionSelected: "actionSelected" }, usesInheritance: true, ngImport: i0, template: '<ng-content></ng-content>', isInline: true, styles: [""] }); }
3638
+ }
3639
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: DataTableUIComponent, decorators: [{
3640
+ type: Component,
3641
+ args: [{ selector: 'app-data-table-ui', standalone: false, template: '<ng-content></ng-content>' }]
3642
+ }], propDecorators: { data: [{
3643
+ type: Input
3644
+ }], columnDefinitions: [{
3645
+ type: Input
3646
+ }], actionOptions: [{
3647
+ type: Input
3648
+ }], actionSelected: [{
3649
+ type: Output
3650
+ }] } });
3651
+
3652
+ class DataTableUIModule {
3653
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: DataTableUIModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
3654
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.1.8", ngImport: i0, type: DataTableUIModule, declarations: [DataTableUIComponent], imports: [CommonModule, SharedDhis2UiModule, ReactWrapperModule], exports: [DataTableUIComponent] }); }
3655
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: DataTableUIModule, imports: [CommonModule, SharedDhis2UiModule] }); }
3656
+ }
3657
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: DataTableUIModule, decorators: [{
3658
+ type: NgModule,
3659
+ args: [{
3660
+ declarations: [DataTableUIComponent],
3661
+ exports: [DataTableUIComponent],
3662
+ imports: [CommonModule, SharedDhis2UiModule, ReactWrapperModule],
3663
+ providers: [],
3664
+ }]
3665
+ }] });
3666
+
3476
3667
  class FormField {
3477
3668
  constructor(options = {}) {
3478
3669
  this.value = options.value || '';
@@ -3911,6 +4102,13 @@ class FormValueUtil {
3911
4102
  }
3912
4103
  }
3913
4104
 
4105
+ class TranslationUtil {
4106
+ static getTranslatedFormName(field, locale = 'sw') {
4107
+ const translation = (field['translations'] || []).find((translation) => translation['locale'] == locale && translation['property'] == 'NAME');
4108
+ return (translation ? translation['value'] : field['formName'] || field['name']);
4109
+ }
4110
+ }
4111
+
3914
4112
  // Copyright 2023 UDSM DHIS2 Lab. All rights reserved.
3915
4113
  // Use of this source code is governed by a BSD-style
3916
4114
  // license that can be found in the LICENSE file.
@@ -3922,6 +4120,9 @@ class FormFieldGroup {
3922
4120
  const fields = this.params.formFieldGroup?.fields || [];
3923
4121
  return fields
3924
4122
  .map((field) => {
4123
+ if (field instanceof FormField) {
4124
+ return field;
4125
+ }
3925
4126
  const fieldMetaData = this.params.fieldMetaData.find((attribute) => attribute['id'] === field.id);
3926
4127
  if (!fieldMetaData) {
3927
4128
  return null;
@@ -3964,7 +4165,7 @@ class FormFieldGroup {
3964
4165
  toJson() {
3965
4166
  return {
3966
4167
  id: this.params.formFieldGroup?.id,
3967
- name: this.params.formFieldGroup?.name,
4168
+ name: TranslationUtil.getTranslatedFormName(this.params.formFieldGroup, this.params.locale),
3968
4169
  isFormHorizontal: this.params.formFieldGroup?.isFormHorizontal,
3969
4170
  repeatDependentField: this.params.formFieldGroup?.repeatDependentField,
3970
4171
  dataKey: this.params.formFieldGroup?.dataKey,
@@ -4071,7 +4272,11 @@ class FormMetaData {
4071
4272
  this.params = params;
4072
4273
  }
4073
4274
  get sections() {
4074
- return (this.params.formMetaData.sections || [])
4275
+ const customSections = this.params.customFormMetaData?.sections;
4276
+ if (!customSections) {
4277
+ return this.#getSectionFromPrograms(this.params.programs);
4278
+ }
4279
+ return (this.params.customFormMetaData?.sections || [])
4075
4280
  .map((section) => {
4076
4281
  const program = this.params.programs.find((program) => section.program === program['id']);
4077
4282
  if (!program) {
@@ -4091,7 +4296,7 @@ class FormMetaData {
4091
4296
  get rules() {
4092
4297
  let ruleVariables = [];
4093
4298
  return [
4094
- ...(this.params.formMetaData.rules || []),
4299
+ ...(this.params.customFormMetaData?.rules || []),
4095
4300
  ...(flatten(this.params.programs.map((program) => {
4096
4301
  ruleVariables = [
4097
4302
  ...ruleVariables,
@@ -4101,10 +4306,131 @@ class FormMetaData {
4101
4306
  })) || []).map((rule) => new MetadataRule(rule, ruleVariables).toJson()),
4102
4307
  ];
4103
4308
  }
4309
+ #getSectionFromPrograms(programs) {
4310
+ const sections = flatten(programs.map((program) => {
4311
+ return [
4312
+ this.#getReportingDetailsSection(program),
4313
+ new FormMetadataSection({
4314
+ section: {
4315
+ id: 'registration',
4316
+ name: 'Registration',
4317
+ fieldGroups: (program.programSections || []).length > 0
4318
+ ? program.programSections.map((programSection) => {
4319
+ return {
4320
+ id: programSection.id,
4321
+ name: programSection.name,
4322
+ sortOrder: programSection.sortOrder,
4323
+ fields: programSection.trackedEntityAttributes,
4324
+ };
4325
+ })
4326
+ : [
4327
+ {
4328
+ id: 'registration',
4329
+ name: '',
4330
+ sortOrder: 1,
4331
+ fields: (program.programTrackedEntityAttributes || []).map((programTrackedEntityAttribute) => {
4332
+ return {
4333
+ id: programTrackedEntityAttribute
4334
+ .trackedEntityAttribute?.id,
4335
+ };
4336
+ }),
4337
+ },
4338
+ ],
4339
+ },
4340
+ program,
4341
+ locale: this.params.locale,
4342
+ }).toJson(),
4343
+ ...(program.programStages || []).map((programStage) => {
4344
+ return new FormMetadataSection({
4345
+ section: {
4346
+ id: programStage.id,
4347
+ name: programStage.name,
4348
+ fieldGroups: (programStage.programStageSections || []).length > 0
4349
+ ? programStage.programStageSections.map((programStageSection) => {
4350
+ return {
4351
+ id: programStageSection.id,
4352
+ name: programStageSection.name,
4353
+ dataKey: camelCase(programStage.code),
4354
+ repeatableStage: programStage.repeatable
4355
+ ? programStage.id
4356
+ : undefined,
4357
+ sortOrder: programStageSection.sortOrder,
4358
+ fields: programStageSection.dataElements,
4359
+ };
4360
+ })
4361
+ : [
4362
+ {
4363
+ id: programStage.id,
4364
+ dataKey: camelCase(programStage.code),
4365
+ repeatableStage: programStage.repeatable
4366
+ ? programStage.id
4367
+ : undefined,
4368
+ fields: (programStage.programStageDataElements || []).map((programStageDataElement) => {
4369
+ return {
4370
+ id: programStageDataElement.dataElement?.id,
4371
+ };
4372
+ }),
4373
+ },
4374
+ ],
4375
+ },
4376
+ program,
4377
+ locale: this.params.locale,
4378
+ }).toJson();
4379
+ }),
4380
+ ];
4381
+ }));
4382
+ if (sections.length === 0) {
4383
+ return [];
4384
+ }
4385
+ return sections;
4386
+ }
4387
+ #getReportingDetailsSection(program) {
4388
+ return new FormMetadataSection({
4389
+ section: {
4390
+ id: 'reporting_details',
4391
+ name: 'Reporting details',
4392
+ fieldGroups: [
4393
+ {
4394
+ id: 'reporting_details',
4395
+ sortOrder: 1,
4396
+ isFormHorizontal: true,
4397
+ fields: [
4398
+ new FormField({
4399
+ id: 'orgUnit',
4400
+ key: 'orgUnit',
4401
+ label: 'Organisation unit',
4402
+ code: 'orgUnit',
4403
+ required: true,
4404
+ controlType: 'org-unit',
4405
+ }),
4406
+ new DateField({
4407
+ id: 'enrollmentDate',
4408
+ label: program.enrollmentDateLabel || 'Enrollment date',
4409
+ code: 'enrollmentDate',
4410
+ key: 'enrollmentDate',
4411
+ required: true,
4412
+ }),
4413
+ program.displayIncidentDate
4414
+ ? new DateField({
4415
+ id: 'incidentDate',
4416
+ label: program.incidentDateLabel || 'Incident date',
4417
+ code: 'incidentDate',
4418
+ key: 'incidentDate',
4419
+ required: true,
4420
+ })
4421
+ : null,
4422
+ ].filter((field) => field),
4423
+ },
4424
+ ],
4425
+ },
4426
+ program,
4427
+ locale: this.params.locale,
4428
+ }).toJson();
4429
+ }
4104
4430
  toJson() {
4105
4431
  return {
4106
- id: this.params.formMetaData?.id,
4107
- name: this.params.formMetaData?.name,
4432
+ id: this.params.customFormMetaData?.id,
4433
+ name: TranslationUtil.getTranslatedFormName(this.params.customFormMetaData || {}, this.params.locale),
4108
4434
  fields: this.fields,
4109
4435
  sections: this.sections,
4110
4436
  rules: this.rules,
@@ -4124,16 +4450,18 @@ class FormValue {
4124
4450
  clear() {
4125
4451
  this.form.reset();
4126
4452
  }
4127
- getValues() {
4453
+ getValues(options) {
4128
4454
  const newValues = {};
4129
4455
  const formValues = this.form?.getRawValue();
4456
+ if (options?.valueOnly) {
4457
+ return formValues;
4458
+ }
4130
4459
  Object.keys(formValues).forEach((key) => {
4131
4460
  const field = find(this.fields, ['key', key]);
4132
4461
  if (field) {
4133
4462
  newValues[key] = {
4134
- id: field.id,
4463
+ ...field,
4135
4464
  value: formValues[key],
4136
- options: field.options,
4137
4465
  };
4138
4466
  }
4139
4467
  });
@@ -4148,7 +4476,7 @@ class FormValue {
4148
4476
  // Copyright 2024 UDSM DHIS2 Lab. All rights reserved.
4149
4477
  // Use of this source code is governed by a BSD-style
4150
4478
  // license that can be found in the LICENSE file.
4151
- class BaseFormFieldComponent extends ReactWrapperComponent {
4479
+ class BaseFormFieldComponent extends ReactWrapperModule {
4152
4480
  constructor() {
4153
4481
  super(...arguments);
4154
4482
  this.ngZone = inject(NgZone);
@@ -4774,12 +5102,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImpor
4774
5102
  }] } });
4775
5103
 
4776
5104
  class RepeatableFormComponent {
5105
+ #eventFormValue$;
5106
+ #showForm$;
5107
+ #events$;
4777
5108
  constructor() {
5109
+ this.ngZone = inject(NgZone);
4778
5110
  this.fieldGroup = input.required();
5111
+ this.events = model();
4779
5112
  this.dataEntities = input.required();
4780
5113
  this.repeatableEvents = [];
4781
5114
  this.repeatableData = {};
4782
5115
  this.repeatableStageUpdate = new EventEmitter();
5116
+ this.eventFormValue = signal(null);
5117
+ this.showForm = signal(false);
5118
+ this.eventIndex = signal(0);
5119
+ this.#eventFormValue$ = toObservable(this.eventFormValue);
5120
+ this.#showForm$ = toObservable(this.showForm);
5121
+ this.#events$ = toObservable(this.events);
4783
5122
  }
4784
5123
  get isValid() {
4785
5124
  return !Object.keys(this.repeatableData).some((index) => {
@@ -4788,9 +5127,9 @@ class RepeatableFormComponent {
4788
5127
  });
4789
5128
  }
4790
5129
  ngOnInit() {
4791
- this.repeatableEvents = (this.events?.length > 0
4792
- ? this.events
4793
- : range(this.numberOfRows).map(() => ({}))).map((event, index) => {
5130
+ this.eventForm = FormUtil.getFormGroup(this.fieldGroup().fields, {});
5131
+ this.eventFormValue.set(new FormValue(this.eventForm, this.fieldGroup().fields));
5132
+ this.repeatableEvents = (this.events() || []).map((event, index) => {
4794
5133
  const fieldControls = (this.fieldGroup().fields || []).reduce((fieldObject, field) => {
4795
5134
  const value = (event.dataValueEntities || {})[field.key] || '';
4796
5135
  return {
@@ -4804,19 +5143,20 @@ class RepeatableFormComponent {
4804
5143
  });
4805
5144
  this.repeatableStageUpdate.emit(this.repeatableData);
4806
5145
  }
4807
- onFormUpdate(formValue, eventIndex) {
4808
- this.repeatableData = { ...this.repeatableData, [eventIndex]: formValue };
4809
- if (this.isValid) {
4810
- this.repeatableStageUpdate.emit(this.repeatableData);
4811
- }
5146
+ onFormUpdate(formValue) {
5147
+ this.eventFormValue.set(formValue);
5148
+ this.repeatableData = {
5149
+ ...this.repeatableData,
5150
+ [this.eventIndex()]: formValue,
5151
+ };
4812
5152
  }
4813
5153
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: RepeatableFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4814
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.1.8", type: RepeatableFormComponent, isStandalone: false, selector: "ng-dhis2-ui-repeatable-form", inputs: { formObject: { classPropertyName: "formObject", publicName: "formObject", isSignal: false, isRequired: false, transformFunction: null }, formData: { classPropertyName: "formData", publicName: "formData", isSignal: false, isRequired: false, transformFunction: null }, fieldGroup: { classPropertyName: "fieldGroup", publicName: "fieldGroup", isSignal: true, isRequired: true, transformFunction: null }, form: { classPropertyName: "form", publicName: "form", isSignal: false, isRequired: false, transformFunction: null }, numberOfRows: { classPropertyName: "numberOfRows", publicName: "numberOfRows", isSignal: false, isRequired: false, transformFunction: null }, programRuleActions: { classPropertyName: "programRuleActions", publicName: "programRuleActions", isSignal: false, isRequired: false, transformFunction: null }, events: { classPropertyName: "events", publicName: "events", isSignal: false, isRequired: false, transformFunction: null }, program: { classPropertyName: "program", publicName: "program", isSignal: false, isRequired: false, transformFunction: null }, programStage: { classPropertyName: "programStage", publicName: "programStage", isSignal: false, isRequired: false, transformFunction: null }, repeatDependentField: { classPropertyName: "repeatDependentField", publicName: "repeatDependentField", isSignal: false, isRequired: false, transformFunction: null }, dataEntities: { classPropertyName: "dataEntities", publicName: "dataEntities", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { repeatableStageUpdate: "repeatableStageUpdate" }, ngImport: i0, template: "<div>\n <div\n *ngFor=\"let repeatableEvent of repeatableEvents; let i = index\"\n class=\"card p-3 mb-2\"\n >\n <div class=\"font-weight-bold h6\">{{ fieldGroup().name }}: #{{ i + 1 }}</div>\n <ng-dhis2-ui-form\n [fields]=\"fieldGroup().fields || []\"\n [form]=\"repeatableEvent.form\"\n [programRuleActions]=\"programRuleActions\"\n [dataEntities]=\"repeatableEvent\"\n [isFormHorizontal]=\"true\"\n (formUpdate)=\"onFormUpdate($event, i)\"\n />\n </div>\n</div>\n", styles: [""], dependencies: [{ kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: FormComponent, selector: "ng-dhis2-ui-form", inputs: ["formConfig", "fields", "form", "isFormHorizontal", "showSaveButton", "fieldsData", "fieldClass", "shouldRenderAsCheckBoxesButton", "programRuleActions", "dataEntities"], outputs: ["formUpdate"] }] }); }
5154
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.8", type: RepeatableFormComponent, isStandalone: false, selector: "ng-dhis2-ui-repeatable-form", inputs: { formObject: { classPropertyName: "formObject", publicName: "formObject", isSignal: false, isRequired: false, transformFunction: null }, formData: { classPropertyName: "formData", publicName: "formData", isSignal: false, isRequired: false, transformFunction: null }, fieldGroup: { classPropertyName: "fieldGroup", publicName: "fieldGroup", isSignal: true, isRequired: true, transformFunction: null }, form: { classPropertyName: "form", publicName: "form", isSignal: false, isRequired: false, transformFunction: null }, numberOfRows: { classPropertyName: "numberOfRows", publicName: "numberOfRows", isSignal: false, isRequired: false, transformFunction: null }, programRuleActions: { classPropertyName: "programRuleActions", publicName: "programRuleActions", isSignal: false, isRequired: false, transformFunction: null }, events: { classPropertyName: "events", publicName: "events", isSignal: true, isRequired: false, transformFunction: null }, program: { classPropertyName: "program", publicName: "program", isSignal: false, isRequired: false, transformFunction: null }, programStage: { classPropertyName: "programStage", publicName: "programStage", isSignal: false, isRequired: false, transformFunction: null }, repeatDependentField: { classPropertyName: "repeatDependentField", publicName: "repeatDependentField", isSignal: false, isRequired: false, transformFunction: null }, dataEntities: { classPropertyName: "dataEntities", publicName: "dataEntities", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { events: "eventsChange", repeatableStageUpdate: "repeatableStageUpdate" }, ngImport: i0, template: "<div class=\"form__repeatable-stage-container\">\n <!-- <ng-dhis2-ui-wrapper [component]=\"EventTable()\"></ng-dhis2-ui-wrapper> -->\n @if(showForm()) {\n <div class=\"form__repeatable-stage-form\">\n <ng-dhis2-ui-form\n [fields]=\"fieldGroup().fields || []\"\n [form]=\"eventForm\"\n [programRuleActions]=\"programRuleActions\"\n [dataEntities]=\"{}\"\n [isFormHorizontal]=\"false\"\n (formUpdate)=\"onFormUpdate($event)\"\n >\n </ng-dhis2-ui-form>\n\n <!-- <ng-dhis2-ui-wrapper [component]=\"FormActionButtons\"></ng-dhis2-ui-wrapper> -->\n </div>\n }\n</div>\n", styles: [".form__repeatable-stage-container{margin-top:16px}.form__repeatable-stage-form{border:solid 1px rgb(232,237,242);border-top-style:none;background-color:#fff;padding:16px}\n"], dependencies: [{ kind: "component", type: FormComponent, selector: "ng-dhis2-ui-form", inputs: ["formConfig", "fields", "form", "isFormHorizontal", "showSaveButton", "fieldsData", "fieldClass", "shouldRenderAsCheckBoxesButton", "programRuleActions", "dataEntities"], outputs: ["formUpdate"] }] }); }
4815
5155
  }
4816
5156
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: RepeatableFormComponent, decorators: [{
4817
5157
  type: Component,
4818
- args: [{ selector: 'ng-dhis2-ui-repeatable-form', standalone: false, template: "<div>\n <div\n *ngFor=\"let repeatableEvent of repeatableEvents; let i = index\"\n class=\"card p-3 mb-2\"\n >\n <div class=\"font-weight-bold h6\">{{ fieldGroup().name }}: #{{ i + 1 }}</div>\n <ng-dhis2-ui-form\n [fields]=\"fieldGroup().fields || []\"\n [form]=\"repeatableEvent.form\"\n [programRuleActions]=\"programRuleActions\"\n [dataEntities]=\"repeatableEvent\"\n [isFormHorizontal]=\"true\"\n (formUpdate)=\"onFormUpdate($event, i)\"\n />\n </div>\n</div>\n" }]
4819
- }], propDecorators: { formObject: [{
5158
+ args: [{ selector: 'ng-dhis2-ui-repeatable-form', standalone: false, template: "<div class=\"form__repeatable-stage-container\">\n <!-- <ng-dhis2-ui-wrapper [component]=\"EventTable()\"></ng-dhis2-ui-wrapper> -->\n @if(showForm()) {\n <div class=\"form__repeatable-stage-form\">\n <ng-dhis2-ui-form\n [fields]=\"fieldGroup().fields || []\"\n [form]=\"eventForm\"\n [programRuleActions]=\"programRuleActions\"\n [dataEntities]=\"{}\"\n [isFormHorizontal]=\"false\"\n (formUpdate)=\"onFormUpdate($event)\"\n >\n </ng-dhis2-ui-form>\n\n <!-- <ng-dhis2-ui-wrapper [component]=\"FormActionButtons\"></ng-dhis2-ui-wrapper> -->\n </div>\n }\n</div>\n", styles: [".form__repeatable-stage-container{margin-top:16px}.form__repeatable-stage-form{border:solid 1px rgb(232,237,242);border-top-style:none;background-color:#fff;padding:16px}\n"] }]
5159
+ }], ctorParameters: () => [], propDecorators: { formObject: [{
4820
5160
  type: Input
4821
5161
  }], formData: [{
4822
5162
  type: Input
@@ -4826,8 +5166,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImpor
4826
5166
  type: Input
4827
5167
  }], programRuleActions: [{
4828
5168
  type: Input
4829
- }], events: [{
4830
- type: Input
4831
5169
  }], program: [{
4832
5170
  type: Input
4833
5171
  }], programStage: [{
@@ -4840,8 +5178,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImpor
4840
5178
 
4841
5179
  class SectionFormComponent {
4842
5180
  constructor() {
5181
+ this.ngZone = inject(NgZone);
4843
5182
  this.loading = input();
4844
- this.isLabResulst = false;
4845
5183
  this.formMetaData = input.required();
4846
5184
  this.dataValueEntities = input.required();
4847
5185
  this.formGroups = {};
@@ -4851,43 +5189,27 @@ class SectionFormComponent {
4851
5189
  this.save = new EventEmitter();
4852
5190
  this.formUpdate = new EventEmitter();
4853
5191
  this.cancel = new EventEmitter();
4854
- }
4855
- get inValid() {
4856
- const valueValidity = Object.keys(this.formValueEntity)
4857
- .map((key) => {
4858
- return (this.formValueEntity[key] || {}).isValid;
4859
- })
4860
- .some((validity) => !validity);
4861
- const repeatableDataValidity = Object.keys(this.repeatableFormValueEntity)
4862
- .map((key) => {
4863
- return Object.keys(this.repeatableFormValueEntity[key]).some((valueIndex) => {
4864
- return ((this.repeatableFormValueEntity[key] || {})[+valueIndex] || {}).isValid;
4865
- });
4866
- })
4867
- .some((validity) => !validity);
4868
- return valueValidity && repeatableDataValidity;
5192
+ this.inValid = signal(true);
5193
+ this.inValid$ = toObservable(this.inValid);
4869
5194
  }
4870
5195
  ngOnInit() {
4871
5196
  if (this.formMetaData().sections) {
4872
5197
  (this.formMetaData().sections || []).forEach((formSection) => {
4873
5198
  (formSection.fieldGroups || []).forEach((fieldGroup) => {
4874
5199
  const formGroup = FormUtil.getFormGroup(fieldGroup.fields, this.dataValueEntities());
4875
- // Set bookingId as default value for `travelerReferenceId` after search refLabNum
4876
- const refLabNum = formGroup.get('refLabNum');
4877
- const travelerReferenceIdControl = formGroup.get('travelerReferenceId');
4878
- if (travelerReferenceIdControl) {
4879
- const defaultValue = this.clientId ? this.clientId : '';
4880
- travelerReferenceIdControl.setValue(defaultValue);
4881
- }
4882
- else if (refLabNum) {
4883
- const defaultValue = this.labNumber ? this.labNumber : '';
4884
- refLabNum.setValue(defaultValue);
4885
- }
4886
5200
  const formValue = new FormValue(formGroup, fieldGroup.fields);
4887
- this.formValueEntity[fieldGroup.id] = formValue;
4888
5201
  this.formGroups[fieldGroup.id] = formGroup;
5202
+ if (!fieldGroup.repeatableStage) {
5203
+ this.formValueEntity[fieldGroup.id] = formValue;
5204
+ }
5205
+ else {
5206
+ this.repeatableFormValueEntity[fieldGroup.dataKey || fieldGroup.id] = {
5207
+ 0: formValue,
5208
+ };
5209
+ }
4889
5210
  });
4890
5211
  });
5212
+ this.inValid.set(this.checkIfInValid());
4891
5213
  this.ruleActions = new ProgramRuleEngine()
4892
5214
  .setRules(this.formMetaData().rules)
4893
5215
  .setDataValues(this.#getDataValue())
@@ -4895,13 +5217,17 @@ class SectionFormComponent {
4895
5217
  }
4896
5218
  }
4897
5219
  onUpdateRepeatableStage(repeatableData, fieldGroup) {
4898
- this.repeatableFormValueEntity[fieldGroup.dataKey || fieldGroup.id] =
4899
- repeatableData;
4900
- const dataValues = this.#getDataValue();
4901
- this.formUpdate.emit(dataValues);
5220
+ if (!isEmpty(repeatableData)) {
5221
+ this.repeatableFormValueEntity[fieldGroup.dataKey || fieldGroup.id] =
5222
+ repeatableData;
5223
+ this.inValid.set(this.checkIfInValid());
5224
+ const dataValues = this.#getDataValue();
5225
+ this.formUpdate.emit(dataValues);
5226
+ }
4902
5227
  }
4903
5228
  onFormUpdate(formValue, fieldGroupId) {
4904
5229
  this.formValueEntity[fieldGroupId] = formValue;
5230
+ this.inValid.set(this.checkIfInValid());
4905
5231
  const dataValues = this.#getDataValue();
4906
5232
  this.ruleActions = new ProgramRuleEngine()
4907
5233
  .setRules(this.formMetaData().rules)
@@ -4909,13 +5235,12 @@ class SectionFormComponent {
4909
5235
  .execute();
4910
5236
  this.formUpdate.emit(dataValues);
4911
5237
  }
4912
- onSubmit(event) {
4913
- event.stopPropagation();
5238
+ onSubmit() {
4914
5239
  const dataValues = this.#getDataValue();
4915
5240
  this.save.emit(dataValues);
4916
5241
  }
4917
5242
  onCancel(event) {
4918
- event.stopPropagation();
5243
+ event?.stopPropagation();
4919
5244
  this.cancel.emit();
4920
5245
  }
4921
5246
  #getDataValue() {
@@ -4934,21 +5259,28 @@ class SectionFormComponent {
4934
5259
  }, {});
4935
5260
  return { ...dataValues, ...repeatableValues };
4936
5261
  }
5262
+ checkIfInValid() {
5263
+ const valueValidity = Object.keys(this.formValueEntity)
5264
+ .map((key) => {
5265
+ return (this.formValueEntity[key] || {}).isValid;
5266
+ })
5267
+ .some((validity) => !validity);
5268
+ const repeatableDataValidity = Object.keys(this.repeatableFormValueEntity)
5269
+ .map((key) => {
5270
+ return Object.keys(this.repeatableFormValueEntity[key]).some((valueIndex) => {
5271
+ return ((this.repeatableFormValueEntity[key] || {})[+valueIndex] || {}).isValid;
5272
+ });
5273
+ })
5274
+ .some((validity) => !validity);
5275
+ return valueValidity || repeatableDataValidity;
5276
+ }
4937
5277
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: SectionFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4938
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.8", type: SectionFormComponent, isStandalone: false, selector: "ng-dhis2-ui-section-form", inputs: { loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, isLab: { classPropertyName: "isLab", publicName: "isLab", isSignal: false, isRequired: false, transformFunction: null }, isLabResulst: { classPropertyName: "isLabResulst", publicName: "isLabResulst", isSignal: false, isRequired: false, transformFunction: null }, clientId: { classPropertyName: "clientId", publicName: "clientId", isSignal: false, isRequired: false, transformFunction: null }, labNumber: { classPropertyName: "labNumber", publicName: "labNumber", isSignal: false, isRequired: false, transformFunction: null }, formMetaData: { classPropertyName: "formMetaData", publicName: "formMetaData", isSignal: true, isRequired: true, transformFunction: null }, dataValueEntities: { classPropertyName: "dataValueEntities", publicName: "dataValueEntities", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { save: "save", formUpdate: "formUpdate", cancel: "cancel" }, ngImport: i0, template: "<ng-container *ngIf=\"formMetaData()\">\n <ng-container *ngFor=\"let formSection of formMetaData().sections\">\n @if(formSection?.name; as sectionName) {\n <div class=\"pt-3 pb-3 font-weight-bold text-left\">\n {{ sectionName }}\n </div>\n }\n <div class=\"p-2\">\n <ng-container *ngIf=\"formSection\">\n <div class=\"row\" *ngFor=\"let fieldGroup of formSection?.fieldGroups\">\n <ng-container *ngIf=\"formGroups[fieldGroup.id] as formGroup\">\n <div\n *ngIf=\"fieldGroup.name && !fieldGroup.repeatableStage\"\n class=\"col-12\"\n >\n <div class=\"pt-2 pb-3 font-weight-bold text-left\">\n {{ fieldGroup?.name }}\n </div>\n </div>\n <div class=\"col-12\" *ngIf=\"fieldGroup.fields\">\n <!-- Single stage form section -->\n <ng-container *ngIf=\"!fieldGroup.repeatableStage\">\n <ng-dhis2-ui-form\n *ngIf=\"fieldGroup.fields.length > 0\"\n [fields]=\"fieldGroup.fields\"\n [form]=\"formGroup\"\n [dataEntities]=\"dataValueEntities()\"\n [programRuleActions]=\"ruleActions\"\n [isFormHorizontal]=\"fieldGroup.isFormHorizontal || false\"\n (formUpdate)=\"onFormUpdate($event, fieldGroup.id)\"\n />\n </ng-container>\n\n <!-- Repeatable stage form section -->\n <ng-container *ngIf=\"fieldGroup.repeatableStage\">\n @if(fieldGroup.repeatDependentField) {\n\n <ng-container *ngIf=\"fieldGroup.repeatDependentField\">\n <ng-container\n *ngIf=\"{\n numberOfRows:\n dataValueEntities()[fieldGroup.repeatDependentField]\n } as dataParams\"\n >\n <ng-dhis2-ui-repeatable-form\n *ngIf=\"\n dataParams.numberOfRows &&\n dataParams.numberOfRows !== '0'\n \"\n [fieldGroup]=\"fieldGroup\"\n [dataEntities]=\"dataValueEntities()\"\n [form]=\"formGroup\"\n [program]=\"formSection.program || ''\"\n [programStage]=\"fieldGroup.repeatableStage\"\n [programRuleActions]=\"ruleActions\"\n [numberOfRows]=\"+dataParams.numberOfRows\"\n [repeatDependentField]=\"\n fieldGroup.repeatDependentField || ''\n \"\n [events]=\"dataValueEntities()[fieldGroup.dataKey!]\"\n (repeatableStageUpdate)=\"\n onUpdateRepeatableStage($event, fieldGroup)\n \"\n /></ng-container>\n </ng-container>\n } @else { Normal event form }\n </ng-container>\n </div>\n </ng-container>\n </div>\n </ng-container>\n </div>\n </ng-container>\n\n <div class=\"flex gap-2 m-2\">\n <button mat-stroked-button (click)=\"onCancel($event)\">\n {{ 'cancel' }}\n </button>\n <button\n mat-flat-button\n color=\"primary\"\n [disabled]=\"inValid\"\n (click)=\"onSubmit($event)\"\n *ngIf=\"!isLab || isLabResulst\"\n >\n <div *ngIf=\"isloading\" class=\"p-1\">\n <!-- <mat-spinner diameter=\"30\" strokeWidth=\"2\"></mat-spinner> -->\n </div>\n <span *ngIf=\"!loading()\">{{ 'submit' }}</span>\n <div class=\"p-1\" *ngIf=\"loading()\">\n <!-- <mat-spinner diameter=\"30\" strokeWidth=\"2\"></mat-spinner> -->\n </div>\n </button>\n <button\n mat-flat-button\n color=\"primary\"\n [disabled]=\"inValid\"\n (click)=\"onSubmit($event)\"\n *ngIf=\"isLab && !isLabResulst\"\n >\n <span *ngIf=\"!loading()\">{{ 'Save & Add sample' }}</span>\n <div class=\"p-1\" *ngIf=\"loading()\">\n <!-- <mat-spinner diameter=\"30\" strokeWidth=\"2\"></mat-spinner> -->\n </div>\n </button>\n <button\n mat-flat-button\n color=\"primary\"\n [disabled]=\"inValid\"\n (click)=\"onSubmit($event)\"\n *ngIf=\"isLab && !isLabResulst\"\n >\n <span *ngIf=\"!loading()\">{{ 'Save & Exit' }}</span>\n <div class=\"p-1\" *ngIf=\"loading()\">\n <!-- <mat-spinner diameter=\"30\" strokeWidth=\"2\"></mat-spinner> -->\n </div>\n </button>\n </div>\n</ng-container>\n", dependencies: [{ kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: FormComponent, selector: "ng-dhis2-ui-form", inputs: ["formConfig", "fields", "form", "isFormHorizontal", "showSaveButton", "fieldsData", "fieldClass", "shouldRenderAsCheckBoxesButton", "programRuleActions", "dataEntities"], outputs: ["formUpdate"] }, { kind: "component", type: RepeatableFormComponent, selector: "ng-dhis2-ui-repeatable-form", inputs: ["formObject", "formData", "fieldGroup", "form", "numberOfRows", "programRuleActions", "events", "program", "programStage", "repeatDependentField", "dataEntities"], outputs: ["repeatableStageUpdate"] }] }); }
5278
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.8", type: SectionFormComponent, isStandalone: false, selector: "ng-dhis2-ui-section-form", inputs: { loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, formMetaData: { classPropertyName: "formMetaData", publicName: "formMetaData", isSignal: true, isRequired: true, transformFunction: null }, dataValueEntities: { classPropertyName: "dataValueEntities", publicName: "dataValueEntities", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { save: "save", formUpdate: "formUpdate", cancel: "cancel" }, ngImport: i0, template: "<ng-container *ngIf=\"formMetaData()\">\n <ng-container *ngFor=\"let formSection of formMetaData().sections\">\n @if(formSection?.name; as sectionName) {\n <div class=\"form__section-name\">\n {{ sectionName }}\n </div>\n }\n <div class=\"form__section-content\">\n <ng-container *ngIf=\"formSection\">\n <div *ngFor=\"let fieldGroup of formSection?.fieldGroups\">\n <ng-container *ngIf=\"formGroups[fieldGroup.id] as formGroup\">\n <div\n *ngIf=\"fieldGroup.name && !fieldGroup.repeatableStage\"\n class=\"form__field-group-name\"\n >\n {{ fieldGroup?.name }}\n </div>\n <div *ngIf=\"fieldGroup.fields\">\n <!-- Single stage form section -->\n <ng-container *ngIf=\"!fieldGroup.repeatableStage\">\n <ng-dhis2-ui-form\n *ngIf=\"fieldGroup.fields.length > 0\"\n [fields]=\"fieldGroup.fields\"\n [form]=\"formGroup\"\n [dataEntities]=\"dataValueEntities()\"\n [programRuleActions]=\"ruleActions\"\n [isFormHorizontal]=\"fieldGroup.isFormHorizontal || false\"\n (formUpdate)=\"onFormUpdate($event, fieldGroup.id)\"\n ></ng-dhis2-ui-form>\n </ng-container>\n\n <!-- Repeatable stage form section -->\n <ng-container *ngIf=\"fieldGroup.repeatableStage\">\n @if(fieldGroup.repeatDependentField) {\n\n <ng-container *ngIf=\"fieldGroup.repeatDependentField\">\n <ng-container\n *ngIf=\"{\n numberOfRows:\n dataValueEntities()[fieldGroup.repeatDependentField]\n } as dataParams\"\n >\n <ng-dhis2-ui-repeatable-form\n *ngIf=\"\n dataParams.numberOfRows &&\n dataParams.numberOfRows !== '0'\n \"\n [fieldGroup]=\"fieldGroup\"\n [dataEntities]=\"dataValueEntities()\"\n [form]=\"formGroup\"\n [program]=\"formSection.program || ''\"\n [programStage]=\"fieldGroup.repeatableStage\"\n [programRuleActions]=\"ruleActions\"\n [numberOfRows]=\"+dataParams.numberOfRows\"\n [repeatDependentField]=\"\n fieldGroup.repeatDependentField || ''\n \"\n [events]=\"dataValueEntities()[fieldGroup.dataKey!]\"\n (repeatableStageUpdate)=\"\n onUpdateRepeatableStage($event, fieldGroup)\n \"\n ></ng-dhis2-ui-repeatable-form\n ></ng-container>\n </ng-container>\n } @else {\n <ng-dhis2-ui-repeatable-form\n [fieldGroup]=\"fieldGroup\"\n [dataEntities]=\"dataValueEntities()\"\n [form]=\"formGroup\"\n [program]=\"formSection.program || ''\"\n [programStage]=\"fieldGroup.repeatableStage\"\n [programRuleActions]=\"ruleActions\"\n [numberOfRows]=\"1\"\n [repeatDependentField]=\"fieldGroup.repeatDependentField || ''\"\n [events]=\"dataValueEntities()[fieldGroup.dataKey!]\"\n (repeatableStageUpdate)=\"\n onUpdateRepeatableStage($event, fieldGroup)\n \"\n ></ng-dhis2-ui-repeatable-form>\n }\n </ng-container>\n </div>\n </ng-container>\n </div>\n </ng-container>\n </div>\n </ng-container>\n</ng-container>\n", styles: [".form__section-name{font-size:16px;font-weight:600;margin-bottom:16px}.form__section-content{margin-bottom:24px}.form__field-group-name{font-size:14px;font-weight:500;padding-bottom:8px;border-bottom:solid 1px rgb(232,237,242);margin-bottom:16px}\n"], dependencies: [{ kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: FormComponent, selector: "ng-dhis2-ui-form", inputs: ["formConfig", "fields", "form", "isFormHorizontal", "showSaveButton", "fieldsData", "fieldClass", "shouldRenderAsCheckBoxesButton", "programRuleActions", "dataEntities"], outputs: ["formUpdate"] }, { kind: "component", type: RepeatableFormComponent, selector: "ng-dhis2-ui-repeatable-form", inputs: ["formObject", "formData", "fieldGroup", "form", "numberOfRows", "programRuleActions", "events", "program", "programStage", "repeatDependentField", "dataEntities"], outputs: ["eventsChange", "repeatableStageUpdate"] }] }); }
4939
5279
  }
4940
5280
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: SectionFormComponent, decorators: [{
4941
5281
  type: Component,
4942
- args: [{ selector: 'ng-dhis2-ui-section-form', standalone: false, template: "<ng-container *ngIf=\"formMetaData()\">\n <ng-container *ngFor=\"let formSection of formMetaData().sections\">\n @if(formSection?.name; as sectionName) {\n <div class=\"pt-3 pb-3 font-weight-bold text-left\">\n {{ sectionName }}\n </div>\n }\n <div class=\"p-2\">\n <ng-container *ngIf=\"formSection\">\n <div class=\"row\" *ngFor=\"let fieldGroup of formSection?.fieldGroups\">\n <ng-container *ngIf=\"formGroups[fieldGroup.id] as formGroup\">\n <div\n *ngIf=\"fieldGroup.name && !fieldGroup.repeatableStage\"\n class=\"col-12\"\n >\n <div class=\"pt-2 pb-3 font-weight-bold text-left\">\n {{ fieldGroup?.name }}\n </div>\n </div>\n <div class=\"col-12\" *ngIf=\"fieldGroup.fields\">\n <!-- Single stage form section -->\n <ng-container *ngIf=\"!fieldGroup.repeatableStage\">\n <ng-dhis2-ui-form\n *ngIf=\"fieldGroup.fields.length > 0\"\n [fields]=\"fieldGroup.fields\"\n [form]=\"formGroup\"\n [dataEntities]=\"dataValueEntities()\"\n [programRuleActions]=\"ruleActions\"\n [isFormHorizontal]=\"fieldGroup.isFormHorizontal || false\"\n (formUpdate)=\"onFormUpdate($event, fieldGroup.id)\"\n />\n </ng-container>\n\n <!-- Repeatable stage form section -->\n <ng-container *ngIf=\"fieldGroup.repeatableStage\">\n @if(fieldGroup.repeatDependentField) {\n\n <ng-container *ngIf=\"fieldGroup.repeatDependentField\">\n <ng-container\n *ngIf=\"{\n numberOfRows:\n dataValueEntities()[fieldGroup.repeatDependentField]\n } as dataParams\"\n >\n <ng-dhis2-ui-repeatable-form\n *ngIf=\"\n dataParams.numberOfRows &&\n dataParams.numberOfRows !== '0'\n \"\n [fieldGroup]=\"fieldGroup\"\n [dataEntities]=\"dataValueEntities()\"\n [form]=\"formGroup\"\n [program]=\"formSection.program || ''\"\n [programStage]=\"fieldGroup.repeatableStage\"\n [programRuleActions]=\"ruleActions\"\n [numberOfRows]=\"+dataParams.numberOfRows\"\n [repeatDependentField]=\"\n fieldGroup.repeatDependentField || ''\n \"\n [events]=\"dataValueEntities()[fieldGroup.dataKey!]\"\n (repeatableStageUpdate)=\"\n onUpdateRepeatableStage($event, fieldGroup)\n \"\n /></ng-container>\n </ng-container>\n } @else { Normal event form }\n </ng-container>\n </div>\n </ng-container>\n </div>\n </ng-container>\n </div>\n </ng-container>\n\n <div class=\"flex gap-2 m-2\">\n <button mat-stroked-button (click)=\"onCancel($event)\">\n {{ 'cancel' }}\n </button>\n <button\n mat-flat-button\n color=\"primary\"\n [disabled]=\"inValid\"\n (click)=\"onSubmit($event)\"\n *ngIf=\"!isLab || isLabResulst\"\n >\n <div *ngIf=\"isloading\" class=\"p-1\">\n <!-- <mat-spinner diameter=\"30\" strokeWidth=\"2\"></mat-spinner> -->\n </div>\n <span *ngIf=\"!loading()\">{{ 'submit' }}</span>\n <div class=\"p-1\" *ngIf=\"loading()\">\n <!-- <mat-spinner diameter=\"30\" strokeWidth=\"2\"></mat-spinner> -->\n </div>\n </button>\n <button\n mat-flat-button\n color=\"primary\"\n [disabled]=\"inValid\"\n (click)=\"onSubmit($event)\"\n *ngIf=\"isLab && !isLabResulst\"\n >\n <span *ngIf=\"!loading()\">{{ 'Save & Add sample' }}</span>\n <div class=\"p-1\" *ngIf=\"loading()\">\n <!-- <mat-spinner diameter=\"30\" strokeWidth=\"2\"></mat-spinner> -->\n </div>\n </button>\n <button\n mat-flat-button\n color=\"primary\"\n [disabled]=\"inValid\"\n (click)=\"onSubmit($event)\"\n *ngIf=\"isLab && !isLabResulst\"\n >\n <span *ngIf=\"!loading()\">{{ 'Save & Exit' }}</span>\n <div class=\"p-1\" *ngIf=\"loading()\">\n <!-- <mat-spinner diameter=\"30\" strokeWidth=\"2\"></mat-spinner> -->\n </div>\n </button>\n </div>\n</ng-container>\n" }]
4943
- }], propDecorators: { isLab: [{
4944
- type: Input
4945
- }], isLabResulst: [{
4946
- type: Input
4947
- }], clientId: [{
4948
- type: Input
4949
- }], labNumber: [{
4950
- type: Input
4951
- }], save: [{
5282
+ args: [{ selector: 'ng-dhis2-ui-section-form', standalone: false, template: "<ng-container *ngIf=\"formMetaData()\">\n <ng-container *ngFor=\"let formSection of formMetaData().sections\">\n @if(formSection?.name; as sectionName) {\n <div class=\"form__section-name\">\n {{ sectionName }}\n </div>\n }\n <div class=\"form__section-content\">\n <ng-container *ngIf=\"formSection\">\n <div *ngFor=\"let fieldGroup of formSection?.fieldGroups\">\n <ng-container *ngIf=\"formGroups[fieldGroup.id] as formGroup\">\n <div\n *ngIf=\"fieldGroup.name && !fieldGroup.repeatableStage\"\n class=\"form__field-group-name\"\n >\n {{ fieldGroup?.name }}\n </div>\n <div *ngIf=\"fieldGroup.fields\">\n <!-- Single stage form section -->\n <ng-container *ngIf=\"!fieldGroup.repeatableStage\">\n <ng-dhis2-ui-form\n *ngIf=\"fieldGroup.fields.length > 0\"\n [fields]=\"fieldGroup.fields\"\n [form]=\"formGroup\"\n [dataEntities]=\"dataValueEntities()\"\n [programRuleActions]=\"ruleActions\"\n [isFormHorizontal]=\"fieldGroup.isFormHorizontal || false\"\n (formUpdate)=\"onFormUpdate($event, fieldGroup.id)\"\n ></ng-dhis2-ui-form>\n </ng-container>\n\n <!-- Repeatable stage form section -->\n <ng-container *ngIf=\"fieldGroup.repeatableStage\">\n @if(fieldGroup.repeatDependentField) {\n\n <ng-container *ngIf=\"fieldGroup.repeatDependentField\">\n <ng-container\n *ngIf=\"{\n numberOfRows:\n dataValueEntities()[fieldGroup.repeatDependentField]\n } as dataParams\"\n >\n <ng-dhis2-ui-repeatable-form\n *ngIf=\"\n dataParams.numberOfRows &&\n dataParams.numberOfRows !== '0'\n \"\n [fieldGroup]=\"fieldGroup\"\n [dataEntities]=\"dataValueEntities()\"\n [form]=\"formGroup\"\n [program]=\"formSection.program || ''\"\n [programStage]=\"fieldGroup.repeatableStage\"\n [programRuleActions]=\"ruleActions\"\n [numberOfRows]=\"+dataParams.numberOfRows\"\n [repeatDependentField]=\"\n fieldGroup.repeatDependentField || ''\n \"\n [events]=\"dataValueEntities()[fieldGroup.dataKey!]\"\n (repeatableStageUpdate)=\"\n onUpdateRepeatableStage($event, fieldGroup)\n \"\n ></ng-dhis2-ui-repeatable-form\n ></ng-container>\n </ng-container>\n } @else {\n <ng-dhis2-ui-repeatable-form\n [fieldGroup]=\"fieldGroup\"\n [dataEntities]=\"dataValueEntities()\"\n [form]=\"formGroup\"\n [program]=\"formSection.program || ''\"\n [programStage]=\"fieldGroup.repeatableStage\"\n [programRuleActions]=\"ruleActions\"\n [numberOfRows]=\"1\"\n [repeatDependentField]=\"fieldGroup.repeatDependentField || ''\"\n [events]=\"dataValueEntities()[fieldGroup.dataKey!]\"\n (repeatableStageUpdate)=\"\n onUpdateRepeatableStage($event, fieldGroup)\n \"\n ></ng-dhis2-ui-repeatable-form>\n }\n </ng-container>\n </div>\n </ng-container>\n </div>\n </ng-container>\n </div>\n </ng-container>\n</ng-container>\n", styles: [".form__section-name{font-size:16px;font-weight:600;margin-bottom:16px}.form__section-content{margin-bottom:24px}.form__field-group-name{font-size:14px;font-weight:500;padding-bottom:8px;border-bottom:solid 1px rgb(232,237,242);margin-bottom:16px}\n"] }]
5283
+ }], ctorParameters: () => [], propDecorators: { save: [{
4952
5284
  type: Output
4953
5285
  }], formUpdate: [{
4954
5286
  type: Output
@@ -4962,11 +5294,16 @@ class D2FormModule {
4962
5294
  FormComponent,
4963
5295
  RepeatableFormComponent,
4964
5296
  SectionFormComponent,
4965
- FormFieldItemComponent], imports: [CommonModule, ReactiveFormsModule, OrganisationUnitSelectorModule], exports: [FormFieldComponent,
5297
+ FormFieldItemComponent], imports: [CommonModule,
5298
+ ReactiveFormsModule,
5299
+ ReactWrapperModule,
5300
+ OrganisationUnitSelectorModule], exports: [FormFieldComponent,
4966
5301
  FormComponent,
4967
5302
  RepeatableFormComponent,
4968
5303
  SectionFormComponent] }); }
4969
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: D2FormModule, imports: [CommonModule, ReactiveFormsModule, OrganisationUnitSelectorModule] }); }
5304
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: D2FormModule, imports: [CommonModule,
5305
+ ReactiveFormsModule,
5306
+ OrganisationUnitSelectorModule] }); }
4970
5307
  }
4971
5308
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: D2FormModule, decorators: [{
4972
5309
  type: NgModule,
@@ -4978,7 +5315,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImpor
4978
5315
  SectionFormComponent,
4979
5316
  FormFieldItemComponent,
4980
5317
  ],
4981
- imports: [CommonModule, ReactiveFormsModule, OrganisationUnitSelectorModule],
5318
+ imports: [
5319
+ CommonModule,
5320
+ ReactiveFormsModule,
5321
+ ReactWrapperModule,
5322
+ OrganisationUnitSelectorModule,
5323
+ ],
4982
5324
  exports: [
4983
5325
  FormFieldComponent,
4984
5326
  FormComponent,
@@ -4992,9 +5334,221 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImpor
4992
5334
  // Use of this source code is governed by a BSD-style
4993
5335
  // license that can be found in the LICENSE file.
4994
5336
 
5337
+ class SelectionFiltersComponent extends ReactWrapperModule {
5338
+ constructor() {
5339
+ super(...arguments);
5340
+ this.actionOptions = [];
5341
+ this.attributeFilters = [];
5342
+ this.dataElementFilters = [];
5343
+ this.actionSelected = new EventEmitter();
5344
+ this.SelectionFiltersUI = () => {
5345
+ const [filters, setFilters] = useState({
5346
+ attributeFilters: this.attributeFilters || [],
5347
+ dataElementFilters: this.dataElementFilters || [],
5348
+ });
5349
+ useEffect(() => {
5350
+ setFilters({
5351
+ attributeFilters: this.attributeFilters,
5352
+ dataElementFilters: this.dataElementFilters,
5353
+ });
5354
+ }, [this.attributeFilters, this.dataElementFilters]);
5355
+ const handleAttributeChange = (index, selectedValue) => {
5356
+ setFilters((prevFilters) => {
5357
+ const updatedFilters = [...prevFilters.attributeFilters];
5358
+ updatedFilters[index] = { ...updatedFilters[index], value: selectedValue };
5359
+ return { ...prevFilters, attributeFilters: updatedFilters };
5360
+ });
5361
+ };
5362
+ const handleDataElementChange = (index, selectedValue) => {
5363
+ setFilters((prevFilters) => {
5364
+ const updatedFilters = [...prevFilters.dataElementFilters];
5365
+ updatedFilters[index] = { ...updatedFilters[index], value: selectedValue };
5366
+ return { ...prevFilters, dataElementFilters: updatedFilters };
5367
+ });
5368
+ };
5369
+ const handleSearch = () => {
5370
+ this.actionSelected.emit(filters);
5371
+ };
5372
+ // Grid Column Span Logic for Attribute Filters
5373
+ const getAttributeColumnSpan = (index) => {
5374
+ const totalItems = filters.attributeFilters.length;
5375
+ if (totalItems <= 4) {
5376
+ // If 1 to 4 items, place them in a single row (span all columns if there's only one item)
5377
+ if (totalItems === 1) {
5378
+ return 'span 4'; // One item spans all four columns
5379
+ }
5380
+ if (totalItems === 2) {
5381
+ return 'span 2'; // Two items, each spans 2 columns
5382
+ }
5383
+ if (totalItems === 3) {
5384
+ return 'span 1'; // Three items, each spans one column
5385
+ }
5386
+ if (totalItems === 4) {
5387
+ return 'span 1'; // Four items, each spans one column
5388
+ }
5389
+ }
5390
+ else {
5391
+ // More than 4 items, recursively adjust the placement
5392
+ const rowIndex = Math.floor(index / 2); // Calculate row by pairs
5393
+ if (index % 2 === 0) {
5394
+ // For first item in each row, span 2 columns
5395
+ return 'span 2';
5396
+ }
5397
+ else if (index === totalItems - 1) {
5398
+ // Last item, spans the full row (4 columns)
5399
+ return 'span 4';
5400
+ }
5401
+ else {
5402
+ // For other items, span 2 columns
5403
+ return 'span 2';
5404
+ }
5405
+ }
5406
+ return 'span 1'; // Default behavior
5407
+ };
5408
+ // Grid Column Span Logic for Data Element Filters
5409
+ const getDataElementColumnSpan = (index) => {
5410
+ const totalItems = filters.dataElementFilters.length;
5411
+ if (totalItems <= 4) {
5412
+ // If 1 to 4 items, place them in a single row (span all columns if there's only one item)
5413
+ if (totalItems === 1) {
5414
+ return 'span 4'; // One item spans all four columns
5415
+ }
5416
+ if (totalItems === 2) {
5417
+ return 'span 2'; // Two items, each spans 2 columns
5418
+ }
5419
+ if (totalItems === 3) {
5420
+ return 'span 1'; // Three items, each spans one column
5421
+ }
5422
+ if (totalItems === 4) {
5423
+ return 'span 1'; // Four items, each spans one column
5424
+ }
5425
+ }
5426
+ else {
5427
+ // More than 4 items, recursively adjust the placement
5428
+ const rowIndex = Math.floor(index / 2); // Calculate row by pairs
5429
+ if (index % 2 === 0) {
5430
+ // For first item in each row, span 2 columns
5431
+ return 'span 2';
5432
+ }
5433
+ else if (index === totalItems - 1) {
5434
+ // Last item, spans the full row (4 columns)
5435
+ return 'span 4';
5436
+ }
5437
+ else {
5438
+ // For other items, span 2 columns
5439
+ return 'span 2';
5440
+ }
5441
+ }
5442
+ return 'span 1'; // Default behavior
5443
+ };
5444
+ return (React__default.createElement("div", { style: {
5445
+ fontFamily: 'Arial, sans-serif',
5446
+ padding: '20px',
5447
+ backgroundColor: '#f9f9f9',
5448
+ borderRadius: '8px',
5449
+ boxShadow: '0 4px 8px rgba(0, 0, 0, 0.1)',
5450
+ } },
5451
+ React__default.createElement("div", { style: {
5452
+ display: 'grid',
5453
+ gridTemplateColumns: 'repeat(4, 1fr)',
5454
+ gap: '16px',
5455
+ } }, filters.attributeFilters.map((filter, index) => (React__default.createElement("div", { key: index, style: { gridColumn: getAttributeColumnSpan(index) } }, filter.hasOptions && filter.options.length > 0 ? (React__default.createElement(SingleSelectField, { className: "single-select", label: filter.name || 'Select Option', selected: filter.value, onChange: (event) => handleAttributeChange(index, event.selected) }, filter.options.map((option, i) => (React__default.createElement(SingleSelectOption, { key: i, label: option.name, value: option.id }))))) : (React__default.createElement(InputField$1, { className: "input-field", label: filter.name || 'Program name', value: filter.value, onChange: (event) => handleAttributeChange(index, event.value) })))))),
5456
+ React__default.createElement("div", { style: {
5457
+ display: 'grid',
5458
+ gridTemplateColumns: 'repeat(4, 1fr)',
5459
+ gap: '16px',
5460
+ } }, filters.dataElementFilters.map((filter, index) => (React__default.createElement("div", { key: index, style: { gridColumn: getDataElementColumnSpan(index) } }, filter.hasOptions && filter.options.length > 0 ? (React__default.createElement(SingleSelectField, { className: "single-select", label: filter.name || 'Aggregation type', selected: filter.value, onChange: (event) => handleDataElementChange(index, event.selected) }, filter.options.map((option, i) => (React__default.createElement(SingleSelectOption, { key: i, label: option.name, value: option.id }))))) : (React__default.createElement(InputField$1, { className: "input-field", label: filter.name || 'Program name', value: filter.value, onChange: (event) => handleDataElementChange(index, event.value) })))))),
5461
+ React__default.createElement("div", { style: { textAlign: 'right', marginTop: '16px' } },
5462
+ React__default.createElement(Button$1, { onClick: handleSearch }, "Search"))));
5463
+ };
5464
+ }
5465
+ async ngAfterViewInit() {
5466
+ if (!this.elementRef)
5467
+ throw new Error('No element ref');
5468
+ this.reactDomRoot = ReactDOM.createRoot(this.elementRef.nativeElement);
5469
+ this.component = this.SelectionFiltersUI;
5470
+ this.render();
5471
+ }
5472
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: SelectionFiltersComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
5473
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.8", type: SelectionFiltersComponent, isStandalone: false, selector: "app-selection-filters-ui", inputs: { actionOptions: "actionOptions", attributeFilters: "attributeFilters", dataElementFilters: "dataElementFilters", startDate: "startDate", endDate: "endDate" }, outputs: { actionSelected: "actionSelected" }, usesInheritance: true, ngImport: i0, template: '<ng-content></ng-content>', isInline: true, styles: [".react-filters-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:20px;margin-bottom:20px}.input-field,.single-select{width:100%}\n"] }); }
5474
+ }
5475
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: SelectionFiltersComponent, decorators: [{
5476
+ type: Component,
5477
+ args: [{ selector: 'app-selection-filters-ui', template: '<ng-content></ng-content>', standalone: false, styles: [".react-filters-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:20px;margin-bottom:20px}.input-field,.single-select{width:100%}\n"] }]
5478
+ }], propDecorators: { actionOptions: [{
5479
+ type: Input
5480
+ }], attributeFilters: [{
5481
+ type: Input
5482
+ }], dataElementFilters: [{
5483
+ type: Input
5484
+ }], startDate: [{
5485
+ type: Input
5486
+ }], endDate: [{
5487
+ type: Input
5488
+ }], actionSelected: [{
5489
+ type: Output
5490
+ }] } });
5491
+
5492
+ class SelectionFiltersUiModule {
5493
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: SelectionFiltersUiModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
5494
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.1.8", ngImport: i0, type: SelectionFiltersUiModule, declarations: [SelectionFiltersComponent], imports: [CommonModule, SharedDhis2UiModule, ReactWrapperModule], exports: [SelectionFiltersComponent] }); }
5495
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: SelectionFiltersUiModule, imports: [CommonModule, SharedDhis2UiModule] }); }
5496
+ }
5497
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: SelectionFiltersUiModule, decorators: [{
5498
+ type: NgModule,
5499
+ args: [{
5500
+ declarations: [SelectionFiltersComponent],
5501
+ imports: [CommonModule, SharedDhis2UiModule, ReactWrapperModule],
5502
+ exports: [SelectionFiltersComponent],
5503
+ }]
5504
+ }] });
5505
+
5506
+ class TrackerFormComponent {
5507
+ constructor() {
5508
+ this.program = input.required();
5509
+ this.d2 = window.d2Web;
5510
+ }
5511
+ async ngOnInit() {
5512
+ this.trackerQuery = this.d2.trackerModule.trackedEntity.setProgram(this.program());
5513
+ const program = await this.trackerQuery.getMetaData();
5514
+ const instance = await this.trackerQuery.create();
5515
+ if (program) {
5516
+ this.formMetaData = new FormMetaData({
5517
+ programs: [program],
5518
+ }).toJson();
5519
+ }
5520
+ }
5521
+ onSave(event) { }
5522
+ onCancel() { }
5523
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: TrackerFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
5524
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.8", type: TrackerFormComponent, isStandalone: false, selector: "ng-dhis2-ui-tracker-form", inputs: { program: { classPropertyName: "program", publicName: "program", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "@if(formMetaData) {\n<ng-dhis2-ui-section-form\n [formMetaData]=\"formMetaData\"\n [dataValueEntities]=\"{}\"\n (save)=\"onSave($event)\"\n (cancel)=\"onCancel()\"\n/>\n}\n", dependencies: [{ kind: "component", type: SectionFormComponent, selector: "ng-dhis2-ui-section-form", inputs: ["loading", "formMetaData", "dataValueEntities"], outputs: ["save", "formUpdate", "cancel"] }] }); }
5525
+ }
5526
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: TrackerFormComponent, decorators: [{
5527
+ type: Component,
5528
+ args: [{ selector: 'ng-dhis2-ui-tracker-form', standalone: false, template: "@if(formMetaData) {\n<ng-dhis2-ui-section-form\n [formMetaData]=\"formMetaData\"\n [dataValueEntities]=\"{}\"\n (save)=\"onSave($event)\"\n (cancel)=\"onCancel()\"\n/>\n}\n" }]
5529
+ }] });
5530
+
5531
+ class TrackerFormModule {
5532
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: TrackerFormModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
5533
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.1.8", ngImport: i0, type: TrackerFormModule, declarations: [TrackerFormComponent], imports: [CommonModule, D2FormModule], exports: [TrackerFormComponent] }); }
5534
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: TrackerFormModule, imports: [CommonModule, D2FormModule] }); }
5535
+ }
5536
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: TrackerFormModule, decorators: [{
5537
+ type: NgModule,
5538
+ args: [{
5539
+ imports: [CommonModule, D2FormModule],
5540
+ declarations: [TrackerFormComponent],
5541
+ exports: [TrackerFormComponent],
5542
+ }]
5543
+ }] });
5544
+
5545
+ // Copyright 2025 UDSM DHIS2 Lab. All rights reserved.
5546
+ // Use of this source code is governed by a BSD-style
5547
+ // license that can be found in the LICENSE file.
5548
+
4995
5549
  /**
4996
5550
  * Generated bundle index. Do not edit.
4997
5551
  */
4998
5552
 
4999
- export { Boolean$1 as Boolean, ButtonComponent, ButtonModule, CheckBox, D2FormModule, DateField, DateRangeValue, Dropdown, FieldConfig, FieldControlTypeUtil, FieldDropdown, FieldType, FieldUtil, FormComponent, FormConfig, FormField, FormFieldComponent, FormFieldGroup, FormFieldTypeUtil, FormMetaData, FormMetadataSection, FormUtil, FormValue, FormValueUtil, HeaderBarComponent, HeaderBarModule, LineListModule, LineListTableComponent, MetadataRule, MetadataRuleAction, OrganisationUnitSelectionConfig, OrganisationUnitSelectorComponent, OrganisationUnitSelectorModalComponent, OrganisationUnitSelectorModule, PeriodSelectorComponent, PeriodSelectorModalComponent, PeriodSelectorModule, ReactWrapperComponent, ReactWrapperModule, RepeatableFormComponent, SectionFormComponent };
5553
+ export { Boolean$1 as Boolean, ButtonComponent, ButtonModule, CheckBox, D2FormModule, DataTableUIComponent, DataTableUIModule, DateField, DateRangeValue, Dropdown, FieldConfig, FieldControlTypeUtil, FieldDropdown, FieldType, FieldUtil, FormComponent, FormConfig, FormField, FormFieldComponent, FormFieldGroup, FormFieldTypeUtil, FormMetaData, FormMetadataSection, FormUtil, FormValue, FormValueUtil, HeaderBarComponent, HeaderBarModule, LineListModule, LineListTableComponent, MetadataRule, MetadataRuleAction, OrganisationUnitSelectionConfig, OrganisationUnitSelectorComponent, OrganisationUnitSelectorModalComponent, OrganisationUnitSelectorModule, PeriodSelectorComponent, PeriodSelectorModalComponent, PeriodSelectorModule, ReactWrapperModule, RepeatableFormComponent, SectionFormComponent, SelectionFiltersComponent, SelectionFiltersUiModule, TrackerFormComponent, TrackerFormModule, TranslationUtil };
5000
5554
  //# sourceMappingURL=iapps-ng-dhis2-ui.mjs.map