@iapps/ng-dhis2-ui 1.1.46 → 1.1.48
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.
- package/fesm2022/iapps-ng-dhis2-ui.mjs +360 -97
- package/fesm2022/iapps-ng-dhis2-ui.mjs.map +1 -1
- package/lib/modules/form/components/org-unit-form-field.component.d.ts +14 -0
- package/lib/modules/form/hooks/field-validation.hook.d.ts +11 -0
- package/lib/modules/form/hooks/index.d.ts +1 -0
- package/lib/modules/form/utils/field-type.util.d.ts +1 -1
- package/lib/modules/form/utils/field.util.d.ts +1 -1
- package/lib/modules/line-list/containers/line-list.component.d.ts +2 -1
- package/lib/shared/hooks/dynamic-styles.hook.d.ts +1 -0
- package/lib/shared/hooks/index.d.ts +1 -0
- package/lib/shared/index.d.ts +1 -0
- package/package.json +1 -1
|
@@ -25,9 +25,9 @@ import { Layer } from '@dhis2-ui/layer';
|
|
|
25
25
|
import { CircularLoader } from '@dhis2-ui/loader';
|
|
26
26
|
import { MenuItem, MenuDivider } from '@dhis2-ui/menu';
|
|
27
27
|
import parse from 'html-react-parser';
|
|
28
|
-
import { Button as Button$1, IconDimensionData16, IconClock16, IconDimensionOrgUnit16, spacers as spacers$1, colors as colors$1, IconEdit16, theme as theme$1, Tooltip, SingleSelectField, SingleSelectOption, InputField as InputField$1, TabBar, Tab, Transfer, Modal as Modal$1, ModalTitle as ModalTitle$1, ModalContent as ModalContent$1, ModalActions as ModalActions$1, ButtonStrip as ButtonStrip$1, Checkbox, OrganisationUnitTree, MultiSelect, MultiSelectOption, IconWarningFilled16, Layer as Layer$1, Popper, FlyoutMenu, MenuItem as MenuItem$1, IconMore24, CircularLoader as CircularLoader$1, IconFilter16, DataTable, TableHead, DataTableRow, DataTableColumnHeader, TableBody, DataTableCell, TableFoot, Pagination, FileInputField, FileListItem, MultiSelectField, TextAreaField } from '@dhis2/ui';
|
|
28
|
+
import { Button as Button$1, IconDimensionData16, IconClock16, IconDimensionOrgUnit16, spacers as spacers$1, colors as colors$1, IconEdit16, theme as theme$1, Tooltip, SingleSelectField, SingleSelectOption, InputField as InputField$1, TabBar, Tab, Transfer, Modal as Modal$1, ModalTitle as ModalTitle$1, ModalContent as ModalContent$1, ModalActions as ModalActions$1, ButtonStrip as ButtonStrip$1, Checkbox, OrganisationUnitTree, MultiSelect, MultiSelectOption, IconWarningFilled16, Layer as Layer$1, Popper, FlyoutMenu, MenuItem as MenuItem$1, IconMore24, CircularLoader as CircularLoader$1, IconFilter16, DataTable, TableHead, DataTableRow, DataTableColumnHeader, TableBody, DataTableCell, TableFoot, Pagination, Chip, FileInputField, FileListItem, MultiSelectField, TextAreaField } from '@dhis2/ui';
|
|
29
29
|
import { getNowInCalendar, generateFixedPeriods } from '@dhis2/multi-calendar-dates';
|
|
30
|
-
import { isObject, isString, sortBy, isArray, find, camelCase, flatten, head, isEmpty } from 'lodash';
|
|
30
|
+
import { isObject, isString, sortBy, isArray, find, camelCase, flatten, debounce, 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';
|
|
@@ -1564,6 +1564,62 @@ TransferOption.propTypes = {
|
|
|
1564
1564
|
// Use of this source code is governed by a BSD-style
|
|
1565
1565
|
// license that can be found in the LICENSE file.
|
|
1566
1566
|
|
|
1567
|
+
// Helper function to generate a unique class name
|
|
1568
|
+
const generateClassName$2 = (base) => `${base}-${Math.random().toString(36).substr(2, 9)}`;
|
|
1569
|
+
// Helper function to convert camelCased properties to hyphenated CSS properties
|
|
1570
|
+
const convertStylesToCSS$2 = (className, styles) => {
|
|
1571
|
+
let cssString = `.${className} {`;
|
|
1572
|
+
for (const key in styles) {
|
|
1573
|
+
if (typeof styles[key] === 'object' && key.startsWith('@media')) {
|
|
1574
|
+
const mediaStyles = convertStylesToCSS$2(className, styles[key]);
|
|
1575
|
+
cssString += `${key} { ${mediaStyles} }`;
|
|
1576
|
+
}
|
|
1577
|
+
else if (key.startsWith('&:')) {
|
|
1578
|
+
const pseudoClass = key.replace('&', '');
|
|
1579
|
+
cssString += `${pseudoClass} { ${convertStylesToCSS$2('', styles[key])} }`;
|
|
1580
|
+
}
|
|
1581
|
+
else {
|
|
1582
|
+
const cssKey = key.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
|
|
1583
|
+
cssString += `${cssKey}: ${styles[key]}; `;
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
cssString += '}';
|
|
1587
|
+
return cssString;
|
|
1588
|
+
};
|
|
1589
|
+
// Custom hook for dynamic styles with generics
|
|
1590
|
+
const useDynamicStyles$2 = (stylesObj) => {
|
|
1591
|
+
const [classNames, setClassNames] = useState({});
|
|
1592
|
+
useEffect(() => {
|
|
1593
|
+
const convertedStyles = Object.keys(stylesObj).map((key) => {
|
|
1594
|
+
const className = generateClassName$2(key);
|
|
1595
|
+
const styleElement = document.createElement('style');
|
|
1596
|
+
styleElement.innerHTML = convertStylesToCSS$2(className, stylesObj[key]);
|
|
1597
|
+
document.head.appendChild(styleElement);
|
|
1598
|
+
return {
|
|
1599
|
+
key,
|
|
1600
|
+
className,
|
|
1601
|
+
styleElement,
|
|
1602
|
+
};
|
|
1603
|
+
});
|
|
1604
|
+
setClassNames(convertedStyles.reduce((classNameEntity, convertedStyle) => {
|
|
1605
|
+
return {
|
|
1606
|
+
...classNameEntity,
|
|
1607
|
+
[convertedStyle.key]: convertedStyle.className,
|
|
1608
|
+
};
|
|
1609
|
+
}, {}));
|
|
1610
|
+
return () => {
|
|
1611
|
+
convertedStyles.forEach((convertedStyle) => {
|
|
1612
|
+
document.head.removeChild(convertedStyle.styleElement);
|
|
1613
|
+
});
|
|
1614
|
+
};
|
|
1615
|
+
}, []);
|
|
1616
|
+
return classNames;
|
|
1617
|
+
};
|
|
1618
|
+
|
|
1619
|
+
// Copyright 2025 UDSM DHIS2 Lab. All rights reserved.
|
|
1620
|
+
// Use of this source code is governed by a BSD-style
|
|
1621
|
+
// license that can be found in the LICENSE file.
|
|
1622
|
+
|
|
1567
1623
|
// Copyright 2023 UDSM DHIS2 Lab. All rights reserved.
|
|
1568
1624
|
// Use of this source code is governed by a BSD-style
|
|
1569
1625
|
// license that can be found in the LICENSE file.
|
|
@@ -3141,7 +3197,7 @@ class LineListService {
|
|
|
3141
3197
|
const filterParams = buildFilters(filters);
|
|
3142
3198
|
const dateFilter = startDate && endDate ? `&programStartDate=${startDate}&programEndDate=${endDate}` : '';
|
|
3143
3199
|
const ouModeIdentifier = ouMode ? `&ouMode=${ouMode}` : ``;
|
|
3144
|
-
return this.httpClient.get(`trackedEntityInstances.json?program=${programId}&ou=${orgUnit}${ouModeIdentifier}&page=${page}&pageSize=${pageSize}&fields=trackedEntityInstance,attributes[*,displayInList],enrollments[*]&totalPages=true&${filterParams}${dateFilter}&order=created:desc`).pipe(map$1((response) => {
|
|
3200
|
+
return this.httpClient.get(`trackedEntityInstances.json?program=${programId}&ou=${orgUnit}${ouModeIdentifier}&page=${page}&pageSize=${pageSize}&fields=trackedEntityInstance,orgUnit,attributes[*,displayInList],enrollments[*]&totalPages=true&${filterParams}${dateFilter}&order=created:desc`).pipe(map$1((response) => {
|
|
3145
3201
|
//TODO: use the api to to order by desc
|
|
3146
3202
|
// response.trackedEntityInstances.reverse();
|
|
3147
3203
|
return response;
|
|
@@ -3217,20 +3273,21 @@ const getTrackedEntityData = (response, programId, pager, filters) => {
|
|
|
3217
3273
|
let teis = response.data
|
|
3218
3274
|
.trackedEntityInstances;
|
|
3219
3275
|
let programMetaData = response.metadata.programTrackedEntityAttributes;
|
|
3220
|
-
//
|
|
3276
|
+
//organisation units from metadata
|
|
3277
|
+
let orgUnitsFromMetaData = response.metadata.organisationUnits;
|
|
3278
|
+
//a Map to efficiently look up orgUnit names by ID
|
|
3279
|
+
const orgUnitMap = new Map(orgUnitsFromMetaData.map((ou) => [ou.id, ou.name]));
|
|
3221
3280
|
const mappedProgramMetadataAttributes = programMetaData.map((attr) => ({
|
|
3222
3281
|
displayInList: attr.displayInList,
|
|
3223
3282
|
searchable: attr.searchable,
|
|
3224
3283
|
id: attr.trackedEntityAttribute.id,
|
|
3225
3284
|
}));
|
|
3226
|
-
console.log('the mapped attributes', mappedProgramMetadataAttributes);
|
|
3227
3285
|
const programAttributesMap = programMetaData.reduce((acc, attribute) => {
|
|
3228
3286
|
if (attribute.displayInList) {
|
|
3229
3287
|
acc[attribute.id] = attribute.displayName;
|
|
3230
3288
|
}
|
|
3231
3289
|
return acc;
|
|
3232
3290
|
}, {});
|
|
3233
|
-
console.log('metadat attributes', programMetaData);
|
|
3234
3291
|
if (filters) {
|
|
3235
3292
|
teis = getFilteredTrackedEntityInstances(teis, filters);
|
|
3236
3293
|
}
|
|
@@ -3242,11 +3299,6 @@ const getTrackedEntityData = (response, programId, pager, filters) => {
|
|
|
3242
3299
|
: tei.attributes;
|
|
3243
3300
|
attributes.forEach((attr) => allAttributes.add(attr.attribute));
|
|
3244
3301
|
});
|
|
3245
|
-
console.log('all of the attributes', allAttributes);
|
|
3246
|
-
// const filteredAttributes = new Set(
|
|
3247
|
-
// [...allAttributes].filter((attributeId) => programAttributesMap[attributeId])
|
|
3248
|
-
// );
|
|
3249
|
-
// console.log('Filtered All Attributes:', filteredAttributes);
|
|
3250
3302
|
let entityColumns = Array.from(allAttributes).map((attrId) => {
|
|
3251
3303
|
const foundAttribute = teis
|
|
3252
3304
|
.flatMap((tei) => {
|
|
@@ -3265,6 +3317,15 @@ const getTrackedEntityData = (response, programId, pager, filters) => {
|
|
|
3265
3317
|
// Check if the column label is part of any value in programAttributesMap
|
|
3266
3318
|
return Object.values(programAttributesMap).some((value) => value.includes(column.label));
|
|
3267
3319
|
});
|
|
3320
|
+
// entityColumns.push({
|
|
3321
|
+
// label: 'Location',
|
|
3322
|
+
// key: 'orgUnit',
|
|
3323
|
+
// });
|
|
3324
|
+
// Add orgUnit as the first column
|
|
3325
|
+
entityColumns.unshift({
|
|
3326
|
+
label: 'Location',
|
|
3327
|
+
key: 'orgUnit',
|
|
3328
|
+
});
|
|
3268
3329
|
const searchableAttributes = mappedProgramMetadataAttributes
|
|
3269
3330
|
.filter((attr) => attr.searchable && attr.displayInList)
|
|
3270
3331
|
.map((attr) => ({
|
|
@@ -3275,8 +3336,6 @@ const getTrackedEntityData = (response, programId, pager, filters) => {
|
|
|
3275
3336
|
const searchableKeys = new Set(searchableAttributes.map((attr) => attr.key));
|
|
3276
3337
|
// Filter entityColumns to keep only those whose key exists in searchableAttributes
|
|
3277
3338
|
const filteredEntityColumns = entityColumns.filter((column) => searchableKeys.has(column.key));
|
|
3278
|
-
console.log('show the filtered values', filteredEntityColumns);
|
|
3279
|
-
console.log('the answer is ', searchableAttributes);
|
|
3280
3339
|
const attributesData = teis.map((tei, idx) => {
|
|
3281
3340
|
let row = {
|
|
3282
3341
|
trackedEntityInstance: tei.trackedEntityInstance,
|
|
@@ -3288,9 +3347,10 @@ const getTrackedEntityData = (response, programId, pager, filters) => {
|
|
|
3288
3347
|
? matchingEnrollment.attributes
|
|
3289
3348
|
: tei.attributes;
|
|
3290
3349
|
attributesToUse.forEach((attr) => (row[attr.attribute] = attr.value));
|
|
3350
|
+
// Access the name of the orgUnit using the Map
|
|
3351
|
+
row['orgUnit'] = orgUnitMap.get(tei.orgUnit) || tei.orgUnit || 'N/A';
|
|
3291
3352
|
return row;
|
|
3292
3353
|
});
|
|
3293
|
-
console.log('attributes to use', entityColumns);
|
|
3294
3354
|
return { columns: entityColumns, data: attributesData, filteredEntityColumns: filteredEntityColumns };
|
|
3295
3355
|
};
|
|
3296
3356
|
const getEventData = (response, pager) => {
|
|
@@ -3360,6 +3420,9 @@ class LineListTableComponent extends ReactWrapperModule {
|
|
|
3360
3420
|
const [filteredColumns, setFilteredColumns] = useState();
|
|
3361
3421
|
const [inputValues, setInputValues] = useState({});
|
|
3362
3422
|
const [filters, setFilters] = useState(false);
|
|
3423
|
+
//TODO: this will be migrated on the parent component
|
|
3424
|
+
const [checkValue, setCheckValue] = useState([]);
|
|
3425
|
+
const [valueMatch, setValuesMatch] = useState(false);
|
|
3363
3426
|
// Store updaters in refs for Angular to access
|
|
3364
3427
|
const updateRefs = useRef({
|
|
3365
3428
|
setProgramIdState,
|
|
@@ -3409,10 +3472,16 @@ class LineListTableComponent extends ReactWrapperModule {
|
|
|
3409
3472
|
const { columns, data, filteredEntityColumns } = getTrackedEntityData(response, this.programId, pager, this.filters);
|
|
3410
3473
|
entityColumns = columns;
|
|
3411
3474
|
entityData = data;
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3475
|
+
//TODO: Should be done on the parent
|
|
3476
|
+
let checkValues = [
|
|
3477
|
+
...new Set(response.data?.trackedEntityInstances?.[0]?.enrollments?.[0]?.events?.flatMap((event) => event.dataValues
|
|
3478
|
+
.filter((dataValue) => /^[A-Za-z]{3}$/.test(dataValue.value))
|
|
3479
|
+
.map((dataValue) => dataValue.value))),
|
|
3480
|
+
];
|
|
3481
|
+
if (checkValues) {
|
|
3482
|
+
// this.firstValue.emit(firstTei);
|
|
3483
|
+
setCheckValue(checkValues);
|
|
3484
|
+
setValuesMatch(!checkValues.includes(this.buttonFilter));
|
|
3416
3485
|
}
|
|
3417
3486
|
// setFilteredColumns(filteredEntityColumns);
|
|
3418
3487
|
// Ensure filter inputs do not disappear when no data is returned
|
|
@@ -3504,9 +3573,12 @@ class LineListTableComponent extends ReactWrapperModule {
|
|
|
3504
3573
|
padding: 8,
|
|
3505
3574
|
marginBottom: 16,
|
|
3506
3575
|
} },
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3576
|
+
valueMatch &&
|
|
3577
|
+
this.dispatchTeis &&
|
|
3578
|
+
(isButtonLoading ? (React__default.createElement(CircularLoader$1, { small: true })) : (
|
|
3579
|
+
//TODO: this implementation should be done where the library will be consumed
|
|
3580
|
+
React__default.createElement(Button$1, { style: {
|
|
3581
|
+
backgroundColor: '#3b82f6',
|
|
3510
3582
|
color: 'white',
|
|
3511
3583
|
padding: '8px 16px',
|
|
3512
3584
|
borderRadius: '4px',
|
|
@@ -3555,7 +3627,7 @@ class LineListTableComponent extends ReactWrapperModule {
|
|
|
3555
3627
|
React__default.createElement(DataTableRow, null, columns.map((col) => (React__default.createElement(DataTableColumnHeader, { key: col.key }, col.label))))),
|
|
3556
3628
|
React__default.createElement(TableBody, null, data.length > 0 ? (data.map((row) => (React__default.createElement(DataTableRow, { key: row.index }, columns.map((col) => (React__default.createElement(DataTableCell, { key: col.key }, col.key === 'actions' ? (React__default.createElement(DropdownMenu$1, { dropdownOptions: getDropdownOptions(row), onClick: (option) => option.onClick?.() })) : (row[col.key] || '--' // Display '--' if value is undefined or null
|
|
3557
3629
|
)))))))) : (React__default.createElement(DataTableRow, null,
|
|
3558
|
-
React__default.createElement(DataTableCell, { colSpan: columns.length, style: {
|
|
3630
|
+
React__default.createElement(DataTableCell, { colSpan: columns.length?.toString(), style: {
|
|
3559
3631
|
textAlign: 'center',
|
|
3560
3632
|
fontWeight: 'bold',
|
|
3561
3633
|
color: 'grey',
|
|
@@ -3608,7 +3680,7 @@ class LineListTableComponent extends ReactWrapperModule {
|
|
|
3608
3680
|
this.render();
|
|
3609
3681
|
}
|
|
3610
3682
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: LineListTableComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
3611
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.8", type: LineListTableComponent, isStandalone: false, selector: "app-line-list", inputs: { programId: "programId", orgUnit: "orgUnit", programStageId: "programStageId", actionOptions: "actionOptions", attributeFilters: "attributeFilters", startDate: "startDate", endDate: "endDate", filters: "filters", ouMode: "ouMode", dispatchTeis: "dispatchTeis", showFilterButton: "showFilterButton", isButtonLoading: "isButtonLoading", buttonLabel: "buttonLabel" }, outputs: { actionSelected: "actionSelected", approvalSelected: "approvalSelected", firstValue: "firstValue" }, usesInheritance: true, usesOnChanges: true, ngImport: i0, template: '<ng-content></ng-content>', isInline: true, styles: ["[data-test=dhis2-uiwidgets-pagination]{display:flex!important;flex-direction:row!important;justify-content:space-between!important;align-items:center!important}\n"] }); }
|
|
3683
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.1.8", type: LineListTableComponent, isStandalone: false, selector: "app-line-list", inputs: { programId: "programId", orgUnit: "orgUnit", programStageId: "programStageId", actionOptions: "actionOptions", attributeFilters: "attributeFilters", startDate: "startDate", endDate: "endDate", filters: "filters", ouMode: "ouMode", dispatchTeis: "dispatchTeis", showFilterButton: "showFilterButton", isButtonLoading: "isButtonLoading", buttonLabel: "buttonLabel", buttonFilter: "buttonFilter" }, outputs: { actionSelected: "actionSelected", approvalSelected: "approvalSelected", firstValue: "firstValue" }, usesInheritance: true, usesOnChanges: true, ngImport: i0, template: '<ng-content></ng-content>', isInline: true, styles: ["[data-test=dhis2-uiwidgets-pagination]{display:flex!important;flex-direction:row!important;justify-content:space-between!important;align-items:center!important}\n"] }); }
|
|
3612
3684
|
}
|
|
3613
3685
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImport: i0, type: LineListTableComponent, decorators: [{
|
|
3614
3686
|
type: Component,
|
|
@@ -3645,6 +3717,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.8", ngImpor
|
|
|
3645
3717
|
type: Input
|
|
3646
3718
|
}], firstValue: [{
|
|
3647
3719
|
type: Output
|
|
3720
|
+
}], buttonFilter: [{
|
|
3721
|
+
type: Input
|
|
3648
3722
|
}] } });
|
|
3649
3723
|
|
|
3650
3724
|
class LineListModule {
|
|
@@ -3814,7 +3888,7 @@ class DataTableUIComponent extends ReactWrapperModule {
|
|
|
3814
3888
|
React__default.createElement(DropdownMenu, { dropdownOptions: getDropdownOptions(row), onClick: (option) => option.onClick?.(row) }))))))),
|
|
3815
3889
|
React__default.createElement(TableFoot, null,
|
|
3816
3890
|
React__default.createElement(DataTableRow, null,
|
|
3817
|
-
React__default.createElement(DataTableCell, { colSpan: columns.length + 1 })))))));
|
|
3891
|
+
React__default.createElement(DataTableCell, { colSpan: (columns.length || 0 + 1).toString() })))))));
|
|
3818
3892
|
};
|
|
3819
3893
|
}
|
|
3820
3894
|
async ngAfterViewInit() {
|
|
@@ -4797,6 +4871,230 @@ class FormValue {
|
|
|
4797
4871
|
// Use of this source code is governed by a BSD-style
|
|
4798
4872
|
// license that can be found in the LICENSE file.
|
|
4799
4873
|
|
|
4874
|
+
// Copyright 2025 UDSM DHIS2 Lab. All rights reserved.
|
|
4875
|
+
// Use of this source code is governed by a BSD-style
|
|
4876
|
+
// license that can be found in the LICENSE file.
|
|
4877
|
+
const useFieldValidation = (props) => {
|
|
4878
|
+
const { form, touched, field, value } = props;
|
|
4879
|
+
const hasError = useMemo(() => {
|
|
4880
|
+
return touched && (form.get(field.id) || form.get(field.key))?.invalid;
|
|
4881
|
+
}, [value, touched]);
|
|
4882
|
+
const validationError = useMemo(() => {
|
|
4883
|
+
if (!touched) {
|
|
4884
|
+
return undefined;
|
|
4885
|
+
}
|
|
4886
|
+
const error = (form.get(field.id) || form.get(field.key))?.errors;
|
|
4887
|
+
if (!error) {
|
|
4888
|
+
return undefined;
|
|
4889
|
+
}
|
|
4890
|
+
if (error['min']) {
|
|
4891
|
+
return `${field.label || 'Value'} should not be less than ${error['min'].min}!`;
|
|
4892
|
+
}
|
|
4893
|
+
else if (error['max']) {
|
|
4894
|
+
return `${field.label || 'Value'} should not be greater than ${error['max'].max}!`;
|
|
4895
|
+
}
|
|
4896
|
+
else if (error['pattern']) {
|
|
4897
|
+
if (field.type === 'email') {
|
|
4898
|
+
return `The email address provided is not valid`;
|
|
4899
|
+
}
|
|
4900
|
+
else if (field.type === 'tel') {
|
|
4901
|
+
return 'Phone number provided is not valid';
|
|
4902
|
+
}
|
|
4903
|
+
else {
|
|
4904
|
+
return `${field.label || 'Value'} should have appropriate format`;
|
|
4905
|
+
}
|
|
4906
|
+
}
|
|
4907
|
+
return error['required']
|
|
4908
|
+
? `${field.label || 'Value'} is required`
|
|
4909
|
+
: undefined;
|
|
4910
|
+
}, [hasError]);
|
|
4911
|
+
return { hasError, validationError };
|
|
4912
|
+
};
|
|
4913
|
+
|
|
4914
|
+
// Copyright 2025 UDSM DHIS2 Lab. All rights reserved.
|
|
4915
|
+
// Use of this source code is governed by a BSD-style
|
|
4916
|
+
// license that can be found in the LICENSE file.
|
|
4917
|
+
|
|
4918
|
+
// Copyright 2025 UDSM DHIS2 Lab. All rights reserved.
|
|
4919
|
+
// Use of this source code is governed by a BSD-style
|
|
4920
|
+
// license that can be found in the LICENSE file.
|
|
4921
|
+
// @flow
|
|
4922
|
+
const orgUnitFieldStyles = {
|
|
4923
|
+
container: {
|
|
4924
|
+
border: '1px solid',
|
|
4925
|
+
borderColor: colors$1.grey400,
|
|
4926
|
+
borderRadius: '3px',
|
|
4927
|
+
height: '100%',
|
|
4928
|
+
width: '100%',
|
|
4929
|
+
zIndex: 0,
|
|
4930
|
+
backgroundColor: 'white',
|
|
4931
|
+
},
|
|
4932
|
+
searchField: {
|
|
4933
|
+
height: '40px',
|
|
4934
|
+
overflow: 'hidden',
|
|
4935
|
+
borderBottomLeftRadius: 0,
|
|
4936
|
+
borderBottomRightRadius: 0,
|
|
4937
|
+
boxShadow: 'none',
|
|
4938
|
+
border: 'none',
|
|
4939
|
+
},
|
|
4940
|
+
debounceFieldContainer: {
|
|
4941
|
+
padding: '8px',
|
|
4942
|
+
background: colors$1.grey100,
|
|
4943
|
+
borderTopLeftRadius: '3px',
|
|
4944
|
+
borderTopRightRadius: '3px',
|
|
4945
|
+
},
|
|
4946
|
+
orgUnitTreeContainer: {
|
|
4947
|
+
borderBottomLeftRadius: '3px',
|
|
4948
|
+
borderBottomRightRadius: '3px',
|
|
4949
|
+
overflow: 'auto',
|
|
4950
|
+
},
|
|
4951
|
+
orgUnitTreeLoader: {
|
|
4952
|
+
padding: '8px',
|
|
4953
|
+
},
|
|
4954
|
+
orgUnitFieldLabel: {
|
|
4955
|
+
marginBottom: '8px',
|
|
4956
|
+
display: 'block',
|
|
4957
|
+
boxSizing: 'border-box',
|
|
4958
|
+
fontSize: '14px',
|
|
4959
|
+
lineHeight: '19px',
|
|
4960
|
+
color: 'rgb(33, 41, 52)',
|
|
4961
|
+
padding: '0',
|
|
4962
|
+
},
|
|
4963
|
+
orgUnitFieldRequiredLabel: {
|
|
4964
|
+
paddingInlineStart: '4px',
|
|
4965
|
+
},
|
|
4966
|
+
};
|
|
4967
|
+
const OrgUnitFormField = (props) => {
|
|
4968
|
+
const { onSelectOrgUnit, label, required, selected, disabled, key } = props;
|
|
4969
|
+
const d2 = window?.d2Web;
|
|
4970
|
+
const classes = useDynamicStyles$2(orgUnitFieldStyles);
|
|
4971
|
+
const config = useMemo(() => {
|
|
4972
|
+
return d2.systemInfo?.toInitObject();
|
|
4973
|
+
}, []);
|
|
4974
|
+
const rootOrgUnits = useMemo(() => {
|
|
4975
|
+
return d2.currentUser?.organisationUnits || [];
|
|
4976
|
+
}, []);
|
|
4977
|
+
const getExpandedItems = () => {
|
|
4978
|
+
if (rootOrgUnits && rootOrgUnits.length === 1) {
|
|
4979
|
+
return [`/${rootOrgUnits[0].id}`];
|
|
4980
|
+
}
|
|
4981
|
+
else if (rootOrgUnits?.length > 1) {
|
|
4982
|
+
return rootOrgUnits.map((root) => root.path);
|
|
4983
|
+
}
|
|
4984
|
+
return undefined;
|
|
4985
|
+
};
|
|
4986
|
+
const initiallyExpanded = getExpandedItems();
|
|
4987
|
+
const [searchText, setSearchText] = useState(undefined);
|
|
4988
|
+
const [loading, setLoading] = useState(true);
|
|
4989
|
+
const [searchLoading, setSearchLoading] = useState();
|
|
4990
|
+
const [searchData, setSearchData] = useState();
|
|
4991
|
+
const [selectedOrgUnit, setSelectedOrgUnit] = React__default.useState();
|
|
4992
|
+
const [expanded, setExpanded] = React__default.useState(initiallyExpanded);
|
|
4993
|
+
const [showOrgUnitTree, setShowOrgUnitTree] = useState(!selected);
|
|
4994
|
+
useEffect(() => {
|
|
4995
|
+
setLoading(true);
|
|
4996
|
+
if (selected) {
|
|
4997
|
+
d2.httpInstance
|
|
4998
|
+
.get(`organisationUnits/${selected}.json?fields=id,name,path,code,ancestors[id,name]`)
|
|
4999
|
+
.then((response) => {
|
|
5000
|
+
if (response.data) {
|
|
5001
|
+
setSelectedOrgUnit(response.data);
|
|
5002
|
+
handleExpand({ path: response.data['path'] });
|
|
5003
|
+
setLoading(false);
|
|
5004
|
+
}
|
|
5005
|
+
});
|
|
5006
|
+
}
|
|
5007
|
+
else {
|
|
5008
|
+
setLoading(false);
|
|
5009
|
+
}
|
|
5010
|
+
}, [selected]);
|
|
5011
|
+
const highlighted = useMemo(() => {
|
|
5012
|
+
if (selectedOrgUnit) {
|
|
5013
|
+
return [selectedOrgUnit['path']];
|
|
5014
|
+
}
|
|
5015
|
+
return undefined;
|
|
5016
|
+
}, [selectedOrgUnit]);
|
|
5017
|
+
const selectedOrgUnitLabel = useMemo(() => {
|
|
5018
|
+
if (selectedOrgUnit) {
|
|
5019
|
+
return [
|
|
5020
|
+
...(selectedOrgUnit['ancestors'] || []),
|
|
5021
|
+
selectedOrgUnit,
|
|
5022
|
+
]
|
|
5023
|
+
.map((orgUnit) => orgUnit['name'])
|
|
5024
|
+
.join(' / ');
|
|
5025
|
+
}
|
|
5026
|
+
return '';
|
|
5027
|
+
}, [selectedOrgUnit]);
|
|
5028
|
+
const handleExpand = ({ path }) => {
|
|
5029
|
+
if (expanded && !expanded.includes(path)) {
|
|
5030
|
+
setExpanded([...expanded, path]);
|
|
5031
|
+
}
|
|
5032
|
+
};
|
|
5033
|
+
const handleCollapse = ({ path }) => {
|
|
5034
|
+
const pathIndex = expanded?.indexOf(path);
|
|
5035
|
+
if (pathIndex && pathIndex !== -1 && expanded) {
|
|
5036
|
+
const updatedExpanded = pathIndex === 0
|
|
5037
|
+
? expanded.slice(1)
|
|
5038
|
+
: [...expanded.slice(0, pathIndex), ...expanded.slice(pathIndex + 1)];
|
|
5039
|
+
setExpanded(updatedExpanded);
|
|
5040
|
+
}
|
|
5041
|
+
};
|
|
5042
|
+
const handleOrgUnitSearch = async (query) => {
|
|
5043
|
+
setSearchLoading(true);
|
|
5044
|
+
try {
|
|
5045
|
+
const searchResponse = await d2.httpInstance.get(`organisationUnits.json?fields=id,displayName,path,publicAccess,access,lastUpdated,children[id,displayName,publicAccess,access,path,children::isNotEmpty]&paging=true&query=${query}&withinUserSearchHierarchy=true&pageSize=15`);
|
|
5046
|
+
setSearchData((searchResponse.data || {})['organisationUnits']);
|
|
5047
|
+
setSearchLoading(false);
|
|
5048
|
+
}
|
|
5049
|
+
catch (e) {
|
|
5050
|
+
setSearchLoading(false);
|
|
5051
|
+
}
|
|
5052
|
+
};
|
|
5053
|
+
const debouncedSearch = useCallback(debounce((value) => {
|
|
5054
|
+
handleOrgUnitSearch(value);
|
|
5055
|
+
}, 500), []);
|
|
5056
|
+
const handleFilterChange = (event) => {
|
|
5057
|
+
setSearchText(event.value);
|
|
5058
|
+
debouncedSearch(event.value);
|
|
5059
|
+
};
|
|
5060
|
+
const ready = useMemo(() => {
|
|
5061
|
+
return searchText?.length ? !searchLoading : !loading;
|
|
5062
|
+
}, [searchText, searchLoading, loading]);
|
|
5063
|
+
const renderOrgUnitTree = () => {
|
|
5064
|
+
if (searchText && searchText?.length > 0) {
|
|
5065
|
+
if (searchLoading) {
|
|
5066
|
+
return (React__default.createElement("div", { className: classes.orgUnitTreeLoader },
|
|
5067
|
+
React__default.createElement(CircularLoader$1, { small: true })));
|
|
5068
|
+
}
|
|
5069
|
+
return (ready && (React__default.createElement(OrganisationUnitTree, { key: `${key}-search`, roots: searchData?.map((orgUnit) => orgUnit.id) || [], singleSelection: true, expanded: expanded, handleExpand: handleExpand, handleCollapse: handleCollapse, selected: highlighted, onChange: (event) => {
|
|
5070
|
+
setSelectedOrgUnit(event);
|
|
5071
|
+
onSelectOrgUnit(event.id);
|
|
5072
|
+
} })));
|
|
5073
|
+
}
|
|
5074
|
+
return (React__default.createElement(OrganisationUnitTree, { key: key, roots: rootOrgUnits?.map((orgUnit) => orgUnit.id) || [], singleSelection: true, expanded: expanded, handleExpand: handleExpand, handleCollapse: handleCollapse, selected: highlighted, onChange: (event) => {
|
|
5075
|
+
setSelectedOrgUnit(event);
|
|
5076
|
+
onSelectOrgUnit(event.id);
|
|
5077
|
+
} }));
|
|
5078
|
+
};
|
|
5079
|
+
const handleBlur = () => {
|
|
5080
|
+
// onBlur && onBlur(null);
|
|
5081
|
+
};
|
|
5082
|
+
return (config && (React__default.createElement(Provider, { config: config, plugin: false, parentAlertsAdd: undefined, showAlertsInPlugin: false },
|
|
5083
|
+
React__default.createElement("div", null,
|
|
5084
|
+
label && (React__default.createElement("div", { className: classes.orgUnitFieldLabel },
|
|
5085
|
+
React__default.createElement("span", null, label),
|
|
5086
|
+
required ? (React__default.createElement("span", { className: classes.orgUnitFieldRequiredLabel }, "*")) : (React__default.createElement(React__default.Fragment, null)))),
|
|
5087
|
+
selected && !showOrgUnitTree ? (selectedOrgUnit ? (React__default.createElement(Tooltip, { content: selectedOrgUnitLabel },
|
|
5088
|
+
React__default.createElement(Chip, { onRemove: () => {
|
|
5089
|
+
setShowOrgUnitTree(true);
|
|
5090
|
+
} }, selectedOrgUnit.name))) : (React__default.createElement("div", { className: classes.orgUnitTreeLoader },
|
|
5091
|
+
React__default.createElement(CircularLoader$1, { small: true })))) : (React__default.createElement("div", { className: classes.container },
|
|
5092
|
+
React__default.createElement("div", { className: classes.debounceFieldContainer },
|
|
5093
|
+
React__default.createElement(InputField$1, { placeholder: "Search", value: searchText, disabled: disabled, onChange: handleFilterChange })),
|
|
5094
|
+
loading ? (React__default.createElement("div", { className: classes.orgUnitTreeLoader },
|
|
5095
|
+
React__default.createElement(CircularLoader$1, { small: true }))) : (React__default.createElement("div", { className: classes.orgUnitTreeContainer, style: { maxHeight: '200px', overflowY: 'auto' } }, renderOrgUnitTree()))))))));
|
|
5096
|
+
};
|
|
5097
|
+
|
|
4800
5098
|
// Copyright 2024 UDSM DHIS2 Lab. All rights reserved.
|
|
4801
5099
|
// Use of this source code is governed by a BSD-style
|
|
4802
5100
|
// license that can be found in the LICENSE file.
|
|
@@ -4886,45 +5184,15 @@ class BaseFormFieldComponent extends ReactWrapperModule {
|
|
|
4886
5184
|
}
|
|
4887
5185
|
return [];
|
|
4888
5186
|
}, [value]);
|
|
4889
|
-
const hasError =
|
|
4890
|
-
|
|
4891
|
-
|
|
4892
|
-
|
|
4893
|
-
|
|
4894
|
-
|
|
4895
|
-
if (!touched) {
|
|
4896
|
-
return undefined;
|
|
4897
|
-
}
|
|
4898
|
-
const field = this.field();
|
|
4899
|
-
const error = (this.form().get(field.id) || this.form().get(field.key))
|
|
4900
|
-
?.errors;
|
|
4901
|
-
if (!error) {
|
|
4902
|
-
return undefined;
|
|
4903
|
-
}
|
|
4904
|
-
if (error['min']) {
|
|
4905
|
-
return `${this.label() || 'Value'} should not be less than ${error['min'].min}!`;
|
|
4906
|
-
}
|
|
4907
|
-
else if (error['max']) {
|
|
4908
|
-
return `${this.label() || 'Value'} should not be greater than ${error['max'].max}!`;
|
|
4909
|
-
}
|
|
4910
|
-
else if (error['pattern']) {
|
|
4911
|
-
if (field.type === 'email') {
|
|
4912
|
-
return `The email address provided is not valid`;
|
|
4913
|
-
}
|
|
4914
|
-
else if (field.type === 'tel') {
|
|
4915
|
-
return 'Phone number provided is not valid';
|
|
4916
|
-
}
|
|
4917
|
-
else {
|
|
4918
|
-
return `${this.label() || 'Value'} should have appropriate format`;
|
|
4919
|
-
}
|
|
4920
|
-
}
|
|
4921
|
-
return error['required']
|
|
4922
|
-
? `${this.label() || 'Value'} is required`
|
|
4923
|
-
: undefined;
|
|
4924
|
-
}, [hasError]);
|
|
5187
|
+
const { hasError, validationError } = useFieldValidation({
|
|
5188
|
+
field: this.field(),
|
|
5189
|
+
form: this.form(),
|
|
5190
|
+
value,
|
|
5191
|
+
touched,
|
|
5192
|
+
});
|
|
4925
5193
|
switch (this.field().controlType) {
|
|
4926
5194
|
case 'textarea':
|
|
4927
|
-
return (React__default.createElement(TextAreaField, { error: hasError, validationText: validationError,
|
|
5195
|
+
return (React__default.createElement(TextAreaField, { error: hasError, validationText: validationError, inputWidth: this.fieldConfig()?.inputWidth, required: this.field().required, name: this.field().id, label: this.label(), rows: 5, placeholder: this.placeholder(), value: value, onChange: (event) => {
|
|
4928
5196
|
this.ngZone.run(() => {
|
|
4929
5197
|
(this.form().get(this.field().id) ||
|
|
4930
5198
|
this.form().get(this.field().key))?.setValue(event.value);
|
|
@@ -4941,34 +5209,14 @@ class BaseFormFieldComponent extends ReactWrapperModule {
|
|
|
4941
5209
|
});
|
|
4942
5210
|
} }));
|
|
4943
5211
|
case 'org-unit':
|
|
4944
|
-
return (React__default.createElement(
|
|
4945
|
-
|
|
4946
|
-
|
|
4947
|
-
|
|
4948
|
-
|
|
4949
|
-
|
|
4950
|
-
});
|
|
4951
|
-
setTouched(true);
|
|
4952
|
-
} }),
|
|
4953
|
-
showOrgUnit && (React__default.createElement(this.FieldOrgUnitSelector, { selectedOrgUnits: [], onSelectOrgUnit: (selectedOrgUnits) => {
|
|
4954
|
-
if ((selectedOrgUnits || [])[0]) {
|
|
4955
|
-
const selectedOrgUnit = selectedOrgUnits[0];
|
|
4956
|
-
setDisplayValue(selectedOrgUnit.name);
|
|
4957
|
-
setValue(selectedOrgUnit.id);
|
|
4958
|
-
setShowOrgUnit(false);
|
|
4959
|
-
setTouched(true);
|
|
4960
|
-
this.ngZone.run(() => {
|
|
4961
|
-
(this.form().get(this.field().id) ||
|
|
4962
|
-
this.form().get(this.field().key))?.setValue(selectedOrgUnit.id);
|
|
4963
|
-
this.immediateUpdate.emit({
|
|
4964
|
-
form: this.form(),
|
|
4965
|
-
value: selectedOrgUnit.id,
|
|
4966
|
-
});
|
|
4967
|
-
});
|
|
4968
|
-
}
|
|
4969
|
-
} }))));
|
|
5212
|
+
return (React__default.createElement(OrgUnitFormField, { label: this.label(), key: this.field().id, required: this.field().required, onSelectOrgUnit: (selectedOrgUnit) => {
|
|
5213
|
+
setValue(selectedOrgUnit);
|
|
5214
|
+
this.ngZone.run(() => {
|
|
5215
|
+
this.update.emit({ form: this.form(), value });
|
|
5216
|
+
});
|
|
5217
|
+
}, selected: value, onBlur: (event) => { } }));
|
|
4970
5218
|
case 'transfer':
|
|
4971
|
-
return (React__default.createElement(Transfer, { filterable: true, filterPlaceholder: "Search", selected: selected,
|
|
5219
|
+
return (React__default.createElement(Transfer, { filterable: true, filterPlaceholder: "Search", selected: selected, leftHeader: React__default.createElement("div", { style: {
|
|
4972
5220
|
fontSize: 14,
|
|
4973
5221
|
padding: '8px 4px',
|
|
4974
5222
|
} }, this.field().availableOptionsLabel), rightHeader: React__default.createElement("div", { style: {
|
|
@@ -4985,7 +5233,10 @@ class BaseFormFieldComponent extends ReactWrapperModule {
|
|
|
4985
5233
|
this.update.emit({ form: this.form(), value });
|
|
4986
5234
|
} }));
|
|
4987
5235
|
case 'checkbox':
|
|
4988
|
-
return (React__default.createElement(Checkbox, { checked: Boolean(value), error: hasError, label: this.label(), name: this.field().id, disabled: this.field()?.disabled ||
|
|
5236
|
+
return (React__default.createElement(Checkbox, { checked: Boolean(value), error: hasError, label: this.label(), name: this.field().id, disabled: this.field()?.disabled ||
|
|
5237
|
+
this.field()?.generated ||
|
|
5238
|
+
this.field()?.unique ||
|
|
5239
|
+
false, onChange: (event) => {
|
|
4989
5240
|
this.ngZone.run(() => {
|
|
4990
5241
|
(this.form().get(this.field().id) ||
|
|
4991
5242
|
this.form().get(this.field().key))?.setValue(event.checked);
|
|
@@ -4998,7 +5249,10 @@ class BaseFormFieldComponent extends ReactWrapperModule {
|
|
|
4998
5249
|
});
|
|
4999
5250
|
} }));
|
|
5000
5251
|
case 'dropdown':
|
|
5001
|
-
return (React__default.createElement(SingleSelectField, { filterable: (this.field().options || []).length > 5, clearable: true, error: hasError, validationText: validationError, inputWidth: this.fieldConfig()?.inputWidth, disabled: this.field()?.disabled ||
|
|
5252
|
+
return (React__default.createElement(SingleSelectField, { filterable: (this.field().options || []).length > 5, clearable: true, error: hasError, validationText: validationError, inputWidth: this.fieldConfig()?.inputWidth, disabled: this.field()?.disabled ||
|
|
5253
|
+
this.field()?.generated ||
|
|
5254
|
+
this.field()?.unique ||
|
|
5255
|
+
false, required: this.field().required, className: "select", label: this.label(), selected: value, onChange: (event) => {
|
|
5002
5256
|
this.ngZone.run(() => {
|
|
5003
5257
|
(this.form().get(this.field().id) ||
|
|
5004
5258
|
this.form().get(this.field().key))?.setValue(event.selected);
|
|
@@ -5011,7 +5265,10 @@ class BaseFormFieldComponent extends ReactWrapperModule {
|
|
|
5011
5265
|
setTouched(true);
|
|
5012
5266
|
} }, (this.field().options || []).map((option) => (React__default.createElement(SingleSelectOption, { key: crypto.randomUUID() || option.key, label: option.label, value: option.value })))));
|
|
5013
5267
|
case 'multi-dropdown':
|
|
5014
|
-
return (React__default.createElement(MultiSelectField, { clearText: "Clear", clearable: true, empty: "No data found", filterable: (this.field().options || []).length > 5, filterPlaceholder: "Type to filter options", error: hasError, validationText: validationError, inputWidth: this.fieldConfig()?.inputWidth, disabled: this.field()?.disabled ||
|
|
5268
|
+
return (React__default.createElement(MultiSelectField, { clearText: "Clear", clearable: true, empty: "No data found", filterable: (this.field().options || []).length > 5, filterPlaceholder: "Type to filter options", error: hasError, validationText: validationError, inputWidth: this.fieldConfig()?.inputWidth, disabled: this.field()?.disabled ||
|
|
5269
|
+
this.field()?.generated ||
|
|
5270
|
+
this.field()?.unique ||
|
|
5271
|
+
false, label: this.label(), required: this.field().required, loadingText: "Loading options", noMatchText: "No options found", onChange: (event) => {
|
|
5015
5272
|
const selectedValue = (event.selected || []).join(',');
|
|
5016
5273
|
this.ngZone.run(() => {
|
|
5017
5274
|
(this.form().get(this.field().id) ||
|
|
@@ -5025,7 +5282,7 @@ class BaseFormFieldComponent extends ReactWrapperModule {
|
|
|
5025
5282
|
setTouched(true);
|
|
5026
5283
|
}, selected: arrayValue }, (this.field().options || []).map((option) => (React__default.createElement(MultiSelectOption, { key: option.key, label: option.label, value: option.value })))));
|
|
5027
5284
|
case 'file':
|
|
5028
|
-
return (React__default.createElement(FileInputField, { accept: "*", buttonLabel: "Upload a file", label: this.label(), name: this.field().id,
|
|
5285
|
+
return (React__default.createElement(FileInputField, { accept: "*", buttonLabel: "Upload a file", label: this.label(), name: this.field().id, onChange: (event) => {
|
|
5029
5286
|
this.uploadedFiles.push((event?.files || [])[0]);
|
|
5030
5287
|
this.ngZone.run(() => {
|
|
5031
5288
|
this.form().get(this.field().id) ||
|
|
@@ -5047,7 +5304,13 @@ class BaseFormFieldComponent extends ReactWrapperModule {
|
|
|
5047
5304
|
});
|
|
5048
5305
|
}, removeText: "Remove" })))));
|
|
5049
5306
|
default:
|
|
5050
|
-
return (React__default.createElement(InputField$1, { error: hasError, validationText: validationError, type: this.field().type, inputWidth: this.fieldConfig()?.inputWidth, required: this.field().required, name: this.field().id, label: this.label(), min: this.field().min?.toString(), max: this.field().max?.toString(), placeholder: this.placeholder(), value: value, disabled: this.field()?.disabled ||
|
|
5307
|
+
return (React__default.createElement(InputField$1, { error: hasError, validationText: validationError, type: this.field().type, inputWidth: this.fieldConfig()?.inputWidth, required: this.field().required, name: this.field().id, label: this.label(), min: this.field().min?.toString(), max: this.field().max?.toString(), placeholder: this.placeholder(), value: value, disabled: this.field()?.disabled ||
|
|
5308
|
+
this.field()?.generated ||
|
|
5309
|
+
this.field()?.unique ||
|
|
5310
|
+
false, readOnly: this.field()?.disabled ||
|
|
5311
|
+
this.field()?.generated ||
|
|
5312
|
+
this.field()?.unique ||
|
|
5313
|
+
false, onChange: (event) => {
|
|
5051
5314
|
this.ngZone.run(() => {
|
|
5052
5315
|
(this.form().get(this.field().id) ||
|
|
5053
5316
|
this.form().get(this.field().key))?.setValue(event.value);
|
|
@@ -5877,8 +6140,8 @@ class SelectionFiltersComponent extends ReactWrapperModule {
|
|
|
5877
6140
|
setTouched(true);
|
|
5878
6141
|
}
|
|
5879
6142
|
} }))),
|
|
5880
|
-
React__default.createElement(InputField$1, { className: "input-field", label: "Start Date", type: "
|
|
5881
|
-
React__default.createElement(InputField$1, { className: "input-field", label: "End Date", type: "
|
|
6143
|
+
React__default.createElement(InputField$1, { className: "input-field", label: "Start Date", type: "date", value: filters.startDate, onChange: (event) => setFilters({ ...filters, startDate: event.value }) }),
|
|
6144
|
+
React__default.createElement(InputField$1, { className: "input-field", label: "End Date", type: "date", value: filters.endDate, onChange: (event) => setFilters({ ...filters, endDate: event.value }) }),
|
|
5882
6145
|
React__default.createElement("div", { style: {
|
|
5883
6146
|
display: 'flex',
|
|
5884
6147
|
flexDirection: 'column',
|
|
@@ -5897,12 +6160,12 @@ class SelectionFiltersComponent extends ReactWrapperModule {
|
|
|
5897
6160
|
display: 'grid',
|
|
5898
6161
|
gridTemplateColumns: 'repeat(4, 1fr)',
|
|
5899
6162
|
gap: '16px',
|
|
5900
|
-
} }, filters.programAttributesFilters.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',
|
|
6163
|
+
} }, filters.programAttributesFilters.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: crypto.randomUUID() || i, label: option.name, value: option.code }))))) : (React__default.createElement(InputField$1, { className: "input-field", label: filter.name || 'Program name', type: filter.valueType, value: filter.value, onChange: (event) => handleAttributeChange(index, event.value) })))))),
|
|
5901
6164
|
React__default.createElement("div", { style: {
|
|
5902
6165
|
display: 'grid',
|
|
5903
6166
|
gridTemplateColumns: 'repeat(4, 1fr)',
|
|
5904
6167
|
gap: '16px',
|
|
5905
|
-
} }, filters.programStageDataElementFilters.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',
|
|
6168
|
+
} }, filters.programStageDataElementFilters.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: crypto.randomUUID() || i, label: option.name, value: option.code }))))) : (React__default.createElement(InputField$1, { className: "input-field", type: filter.valueType, label: filter.name || 'Program name', value: filter.value, onChange: (event) => handleDataElementChange(index, event.value) })))))),
|
|
5906
6169
|
React__default.createElement("div", { style: { textAlign: 'right', marginTop: '16px' } },
|
|
5907
6170
|
React__default.createElement(Button$1, { onClick: handleSearch }, "Search"))))));
|
|
5908
6171
|
};
|