@iapps/ng-dhis2-ui 1.2.137 → 1.2.138

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.
@@ -1,4 +1,4 @@
1
- import * as i1 from '@angular/common';
1
+ import * as i1$1 from '@angular/common';
2
2
  import { CommonModule } from '@angular/common';
3
3
  import * as i0 from '@angular/core';
4
4
  import { NgModule, ContentChild, Input, Directive, inject, ElementRef, Component, EventEmitter, Output, NgZone, input, ChangeDetectionStrategy, Injectable, model, computed, signal, effect, ViewChildren } from '@angular/core';
@@ -23,7 +23,7 @@ import { Divider } from '@dhis2-ui/divider';
23
23
  import { Layer } from '@dhis2-ui/layer';
24
24
  import { CircularLoader } from '@dhis2-ui/loader';
25
25
  import { MenuItem, MenuDivider } from '@dhis2-ui/menu';
26
- import { Button as Button$1, IconDimensionOrgUnit16, IconClock16, IconDimensionData16, spacers as spacers$1, colors as colors$1, IconEdit16, theme as theme$1, Tooltip, IconChevronRight16, SingleSelectField, SingleSelectOption, InputField as InputField$1, TabBar, Tab, Transfer, Modal as Modal$1, ModalTitle as ModalTitle$1, ModalContent as ModalContent$1, ModalActions as ModalActions$1, ButtonStrip as ButtonStrip$1, Checkbox, OrganisationUnitTree, MultiSelect, MultiSelectOption, IconWarningFilled16, CircularLoader as CircularLoader$1, Chip, DataTableToolbar, DropdownButton, FlyoutMenu, CalendarInput, TableHead, DataTableRow, DataTableColumnHeader, Layer as Layer$1, Popper, MenuItem as MenuItem$1, IconMore24, DataTableCell, TableBody as TableBody$1, Pagination as Pagination$1, TableFoot, DataTable, FileInputField, FileListItem, Field, Help, MultiSelectField, TextAreaField, NoticeBox } from '@dhis2/ui';
26
+ import { Button as Button$1, IconDimensionOrgUnit16, IconClock16, IconDimensionData16, spacers as spacers$1, colors as colors$1, IconEdit16, theme as theme$1, Tooltip, IconChevronRight16, SingleSelectField, SingleSelectOption, InputField as InputField$1, TabBar, Tab, Transfer, Modal as Modal$1, ModalTitle as ModalTitle$1, ModalContent as ModalContent$1, ModalActions as ModalActions$1, ButtonStrip as ButtonStrip$1, Checkbox, OrganisationUnitTree, MultiSelect, MultiSelectOption, IconWarningFilled16, CircularLoader as CircularLoader$1, Chip, DataTableToolbar, DropdownButton, FlyoutMenu, CalendarInput, TableHead, DataTableRow, DataTableColumnHeader, Layer as Layer$1, Popper, MenuItem as MenuItem$1, IconMore24, DataTableCell, TableBody as TableBody$1, Pagination as Pagination$1, TableFoot, DataTable, Field, NoticeBox, FileInputField, FileListItem, MultiSelectField, TextAreaField } from '@dhis2/ui';
27
27
  import { isObject, isString, debounce, isUndefined, find, sortBy, camelCase, flatten, isArray, isEmpty } from 'lodash';
28
28
  import cx from 'classnames';
29
29
  import { getNowInCalendar, generateFixedPeriods } from '@dhis2/multi-calendar-dates';
@@ -31,10 +31,10 @@ import { Pager, DataOrderCriteria, DataQueryFilter, DataFilterCondition, Program
31
31
  import { parseISO, isValid, format, addDays } from 'date-fns';
32
32
  import { map as map$1 } from 'rxjs/operators';
33
33
  import * as XLSX from 'xlsx';
34
- import * as i1$1 from '@angular/forms';
34
+ import * as i1 from '@angular/forms';
35
35
  import { FormControl, Validators, UntypedFormControl, UntypedFormGroup, FormGroup, ReactiveFormsModule } from '@angular/forms';
36
36
  import { toObservable } from '@angular/core/rxjs-interop';
37
- import { useMapEvents, useMap, MapContainer, TileLayer, Marker } from 'react-leaflet';
37
+ import { useMapEvents, useMap, MapContainer, TileLayer, GeoJSON, Marker } from 'react-leaflet';
38
38
  import moment from 'moment';
39
39
 
40
40
  class SharedDhis2UiModule {
@@ -5328,6 +5328,1121 @@ const useFieldValidation = (props) => {
5328
5328
  // Use of this source code is governed by a BSD-style
5329
5329
  // license that can be found in the LICENSE file.
5330
5330
 
5331
+ /** Default focus: Zanzibar (Unguja) */
5332
+ const DEFAULT_CENTER = [-6.1659, 39.2026];
5333
+ const DEFAULT_ZOOM = 8;
5334
+ /** ---------------- Coordinate parsing/format ---------------- */
5335
+ function normalizeCoordinate(lat, lng) {
5336
+ if (Number.isNaN(lat) || Number.isNaN(lng))
5337
+ return null;
5338
+ if (lat < -90 || lat > 90 || lng < -180 || lng > 180)
5339
+ return null;
5340
+ if (lat === 0 && lng === 0)
5341
+ return null;
5342
+ return { lat, lng };
5343
+ }
5344
+ function parseCoordinate(value) {
5345
+ if (!value || typeof value !== 'string')
5346
+ return null;
5347
+ const trimmed = value.trim();
5348
+ if (!trimmed)
5349
+ return null;
5350
+ let lat;
5351
+ let lng;
5352
+ if (trimmed.startsWith('[') && trimmed.endsWith(']')) {
5353
+ try {
5354
+ const arr = JSON.parse(trimmed);
5355
+ if (!Array.isArray(arr) || arr.length < 2)
5356
+ return null;
5357
+ lng = Number(arr[0]);
5358
+ lat = Number(arr[1]);
5359
+ }
5360
+ catch {
5361
+ return null;
5362
+ }
5363
+ }
5364
+ else {
5365
+ const parts = trimmed.split(',').map((p) => p.trim());
5366
+ if (parts.length !== 2)
5367
+ return null;
5368
+ lat = Number(parts[0]);
5369
+ lng = Number(parts[1]);
5370
+ }
5371
+ return normalizeCoordinate(lat, lng);
5372
+ }
5373
+ function formatCoordinate(coordinate) {
5374
+ if (!coordinate)
5375
+ return null;
5376
+ return `[${coordinate.lng.toFixed(6)},${coordinate.lat.toFixed(6)}]`;
5377
+ }
5378
+ function toNumber(v) {
5379
+ const n = typeof v === 'string' ? Number(v) : typeof v === 'number' ? v : Number.NaN;
5380
+ return Number.isFinite(n) ? n : null;
5381
+ }
5382
+ function looksLikeLatLngPair(a, b) {
5383
+ return a >= -90 && a <= 90 && b >= -180 && b <= 180;
5384
+ }
5385
+ function looksLikeLngLatPair(a, b) {
5386
+ return a >= -180 && a <= 180 && b >= -90 && b <= 90;
5387
+ }
5388
+ function normalizeLngLatPair(pair) {
5389
+ if (!Array.isArray(pair) || pair.length < 2)
5390
+ return null;
5391
+ const a = toNumber(pair[0]);
5392
+ const b = toNumber(pair[1]);
5393
+ if (a == null || b == null)
5394
+ return null;
5395
+ // GeoJSON expected: [lng, lat]
5396
+ if (looksLikeLngLatPair(a, b))
5397
+ return [a, b];
5398
+ // If provided as [lat, lng], swap
5399
+ if (looksLikeLatLngPair(a, b))
5400
+ return [b, a];
5401
+ return null;
5402
+ }
5403
+ function ensureClosedRing(ring) {
5404
+ if (ring.length < 3)
5405
+ return ring;
5406
+ const first = ring[0];
5407
+ const last = ring[ring.length - 1];
5408
+ if (first[0] === last[0] && first[1] === last[1])
5409
+ return ring;
5410
+ return [...ring, [first[0], first[1]]];
5411
+ }
5412
+ /**
5413
+ * ✅ FIXED: supports BOTH shapes:
5414
+ * - proper GeoJSON Polygon coords: [ [ [lng,lat], ... ] , [hole], ... ]
5415
+ * - single-ring coords (your payload): [ [lng,lat], [lng,lat], ... ]
5416
+ */
5417
+ function sanitizePolygonCoordinates(coords) {
5418
+ if (!Array.isArray(coords) || coords.length === 0)
5419
+ return null;
5420
+ const isSingleRing = Array.isArray(coords[0]) &&
5421
+ typeof coords[0][0] === 'number' &&
5422
+ typeof coords[0][1] === 'number';
5423
+ const ringsCandidate = isSingleRing ? [coords] : coords;
5424
+ const cleanRings = [];
5425
+ for (const ring of ringsCandidate) {
5426
+ if (!Array.isArray(ring) || ring.length < 3)
5427
+ continue;
5428
+ const cleanRing = [];
5429
+ for (const pt of ring) {
5430
+ const pair = normalizeLngLatPair(pt);
5431
+ if (pair)
5432
+ cleanRing.push(pair);
5433
+ }
5434
+ if (cleanRing.length < 3)
5435
+ continue;
5436
+ cleanRings.push(ensureClosedRing(cleanRing));
5437
+ }
5438
+ return cleanRings.length ? cleanRings : null;
5439
+ }
5440
+ function sanitizeMultiPolygonCoordinates(coords) {
5441
+ if (!Array.isArray(coords) || coords.length === 0)
5442
+ return null;
5443
+ const polys = [];
5444
+ for (const poly of coords) {
5445
+ const cleaned = sanitizePolygonCoordinates(poly);
5446
+ if (cleaned)
5447
+ polys.push(cleaned);
5448
+ }
5449
+ return polys.length ? polys : null;
5450
+ }
5451
+ /**
5452
+ * ✅ FIXED: strict unwrap so we only return real GeoJSON geometry objects.
5453
+ */
5454
+ function unwrapToGeometry(input) {
5455
+ if (!input)
5456
+ return null;
5457
+ if (typeof input === 'string') {
5458
+ try {
5459
+ return unwrapToGeometry(JSON.parse(input));
5460
+ }
5461
+ catch {
5462
+ return null;
5463
+ }
5464
+ }
5465
+ if (input.type === 'FeatureCollection') {
5466
+ const fc = input;
5467
+ const first = fc.features?.find((f) => !!f?.geometry);
5468
+ return first?.geometry ?? null;
5469
+ }
5470
+ if (input.type === 'Feature') {
5471
+ return input.geometry ?? null;
5472
+ }
5473
+ const maybeType = input.type;
5474
+ const maybeCoords = input.coordinates;
5475
+ const isGeometryLike = (maybeType === 'Polygon' || maybeType === 'MultiPolygon') &&
5476
+ Array.isArray(maybeCoords);
5477
+ if (isGeometryLike)
5478
+ return input;
5479
+ return null;
5480
+ }
5481
+ function sanitizeAllowedArea(input) {
5482
+ const geom = unwrapToGeometry(input);
5483
+ if (!geom)
5484
+ return null;
5485
+ if (geom.type === 'Polygon') {
5486
+ const coordsRaw = geom.coordinates;
5487
+ // Optional debug (safe to remove):
5488
+ // console.log('Polygon coords shape:', {
5489
+ // isArray0: Array.isArray(coordsRaw),
5490
+ // isArray1: Array.isArray(coordsRaw?.[0]),
5491
+ // isArray2: Array.isArray(coordsRaw?.[0]?.[0]),
5492
+ // sample0: coordsRaw?.[0],
5493
+ // });
5494
+ const coords = sanitizePolygonCoordinates(coordsRaw);
5495
+ if (!coords)
5496
+ return null;
5497
+ return { type: 'Polygon', coordinates: coords };
5498
+ }
5499
+ if (geom.type === 'MultiPolygon') {
5500
+ const coords = sanitizeMultiPolygonCoordinates(geom.coordinates);
5501
+ if (!coords)
5502
+ return null;
5503
+ return {
5504
+ type: 'MultiPolygon',
5505
+ coordinates: coords,
5506
+ };
5507
+ }
5508
+ return null;
5509
+ }
5510
+ /**
5511
+ * Point-in-polygon (ray casting).
5512
+ * Works with [lng, lat] coordinates.
5513
+ */
5514
+ function isPointInsideGeoJsonArea(point, area) {
5515
+ if (!area)
5516
+ return true;
5517
+ const pt = [point.lng, point.lat];
5518
+ const inRing = (ring, p) => {
5519
+ let inside = false;
5520
+ for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
5521
+ const xi = ring[i][0], yi = ring[i][1];
5522
+ const xj = ring[j][0], yj = ring[j][1];
5523
+ const intersect = yi > p[1] !== yj > p[1] &&
5524
+ p[0] < ((xj - xi) * (p[1] - yi)) / (yj - yi + 0.0) + xi;
5525
+ if (intersect)
5526
+ inside = !inside;
5527
+ }
5528
+ return inside;
5529
+ };
5530
+ const inPolygon = (polyCoords) => {
5531
+ const [outer, ...holes] = polyCoords;
5532
+ if (!outer || outer.length < 3)
5533
+ return false;
5534
+ if (!inRing(outer, pt))
5535
+ return false;
5536
+ for (const hole of holes) {
5537
+ if (hole && hole.length >= 3 && inRing(hole, pt))
5538
+ return false;
5539
+ }
5540
+ return true;
5541
+ };
5542
+ if (area.type === 'Polygon')
5543
+ return inPolygon(area.coordinates);
5544
+ for (const poly of area.coordinates) {
5545
+ if (inPolygon(poly))
5546
+ return true;
5547
+ }
5548
+ return false;
5549
+ }
5550
+ function metersToKmRadius(m) {
5551
+ if (typeof m !== 'number' || Number.isNaN(m) || m <= 0)
5552
+ return null;
5553
+ return Math.max(0.01, m / 1000);
5554
+ }
5555
+ const MapClickListener = ({ disabled, onCoordinateSelected, }) => {
5556
+ useMapEvents({
5557
+ click(event) {
5558
+ if (disabled)
5559
+ return;
5560
+ const { lat, lng } = event.latlng;
5561
+ onCoordinateSelected({ lat, lng });
5562
+ },
5563
+ });
5564
+ return null;
5565
+ };
5566
+ const RecenterOnCoordinate = ({ coordinate }) => {
5567
+ const map = useMap();
5568
+ React__default.useEffect(() => {
5569
+ if (coordinate) {
5570
+ map.flyTo([coordinate.lat, coordinate.lng], map.getZoom(), {
5571
+ duration: 0.4,
5572
+ });
5573
+ }
5574
+ }, [coordinate, map]);
5575
+ return null;
5576
+ };
5577
+ /** Auto-fits the map to the polygon bounds when loaded */
5578
+ const AutoFitToBoundary = ({ boundary }) => {
5579
+ const map = useMap();
5580
+ React__default.useEffect(() => {
5581
+ if (boundary) {
5582
+ try {
5583
+ const layer = window.L?.geoJSON?.(boundary);
5584
+ if (layer) {
5585
+ map.fitBounds(layer.getBounds(), { padding: [20, 20] });
5586
+ }
5587
+ }
5588
+ catch (e) {
5589
+ console.warn('Auto-fit failed:', e);
5590
+ }
5591
+ }
5592
+ }, [boundary, map]);
5593
+ return null;
5594
+ };
5595
+ const CoordinateMapContainer = MapContainer;
5596
+ /** ---------------- Component ---------------- */
5597
+ const CoordinatePickerField = ({ label, name, value, required, disabled, error, validationText, onChange, onBlur, geoConfig, }) => {
5598
+ const parsedCoordinate = React__default.useMemo(() => parseCoordinate(value), [value]);
5599
+ const rawAllowedArea = geoConfig?.allowedAreaGeoJson ?? null;
5600
+ // ✅ never pass raw geojson to Leaflet
5601
+ const safeAllowedAreaGeoJson = React__default.useMemo(() => sanitizeAllowedArea(rawAllowedArea), [rawAllowedArea]);
5602
+ const allowedAreaName = geoConfig?.allowedAreaName;
5603
+ const requireWithinArea = geoConfig?.requireWithinArea ?? false;
5604
+ const captureAccuracy = geoConfig?.captureAccuracy ?? true;
5605
+ const accuracyKmValue = geoConfig?.accuracyKmValue ?? null;
5606
+ const onAccuracyKmChange = geoConfig?.onAccuracyKmChange;
5607
+ const accuracySource = geoConfig?.accuracySource ?? 'UNKNOWN';
5608
+ const onAccuracySourceChange = geoConfig?.onAccuracySourceChange;
5609
+ const maxAccuracyKm = geoConfig?.maxAccuracyKm ?? 50;
5610
+ const outsideAreaPolicyText = geoConfig?.outsideAreaPolicyText;
5611
+ const onOutsideAreaSelected = geoConfig?.onOutsideAreaSelected;
5612
+ const [latitudeInput, setLatitudeInput] = React__default.useState(parsedCoordinate ? String(parsedCoordinate.lat) : '');
5613
+ const [longitudeInput, setLongitudeInput] = React__default.useState(parsedCoordinate ? String(parsedCoordinate.lng) : '');
5614
+ const [validationMessage, setValidationMessage] = React__default.useState(null);
5615
+ const [isMapDialogOpen, setIsMapDialogOpen] = React__default.useState(false);
5616
+ const [pendingCoordinate, setPendingCoordinate] = React__default.useState(parsedCoordinate ?? null);
5617
+ const [mapCenterPosition, setMapCenterPosition] = React__default.useState(parsedCoordinate
5618
+ ? [parsedCoordinate.lat, parsedCoordinate.lng]
5619
+ : DEFAULT_CENTER);
5620
+ const [outsideAreaAcknowledged, setOutsideAreaAcknowledged] = React__default.useState(false);
5621
+ React__default.useEffect(() => {
5622
+ const updated = parseCoordinate(value);
5623
+ if (updated) {
5624
+ setLatitudeInput(String(updated.lat));
5625
+ setLongitudeInput(String(updated.lng));
5626
+ setPendingCoordinate(updated);
5627
+ setMapCenterPosition([updated.lat, updated.lng]);
5628
+ }
5629
+ else {
5630
+ setLatitudeInput('');
5631
+ setLongitudeInput('');
5632
+ setPendingCoordinate(null);
5633
+ setMapCenterPosition(DEFAULT_CENTER);
5634
+ }
5635
+ setOutsideAreaAcknowledged(false);
5636
+ }, [value]);
5637
+ const currentCoordinate = React__default.useMemo(() => {
5638
+ const lat = Number(latitudeInput);
5639
+ const lng = Number(longitudeInput);
5640
+ return normalizeCoordinate(lat, lng);
5641
+ }, [latitudeInput, longitudeInput]);
5642
+ const markerCoordinate = pendingCoordinate || currentCoordinate || null;
5643
+ const allowedAreaDisplayName = allowedAreaName ?? 'the required boundary area';
5644
+ const policyText = outsideAreaPolicyText ??
5645
+ `The selected point is outside ${allowedAreaDisplayName}.
5646
+ Saving an out-of-area location can lead to incorrect case assignment, wrong administrative-unit reporting, and unreliable spatial analysis (maps, coverage, response targeting).
5647
+ Only proceed if you are certain this is intentional and acceptable according to your reporting guidelines.`;
5648
+ const isOutsideAllowedArea = React__default.useMemo(() => {
5649
+ if (!markerCoordinate)
5650
+ return false;
5651
+ if (!safeAllowedAreaGeoJson)
5652
+ return false;
5653
+ return !isPointInsideGeoJsonArea(markerCoordinate, safeAllowedAreaGeoJson);
5654
+ }, [markerCoordinate, safeAllowedAreaGeoJson]);
5655
+ const applyCoordinateChange = React__default.useCallback((coordinate) => {
5656
+ if (!coordinate) {
5657
+ setLatitudeInput('');
5658
+ setLongitudeInput('');
5659
+ setValidationMessage(null);
5660
+ onChange(null);
5661
+ return;
5662
+ }
5663
+ const normalized = normalizeCoordinate(coordinate.lat, coordinate.lng);
5664
+ if (!normalized) {
5665
+ setValidationMessage('Please enter a valid coordinate within the allowed latitude/longitude range.');
5666
+ onChange(null);
5667
+ return;
5668
+ }
5669
+ setLatitudeInput(String(normalized.lat));
5670
+ setLongitudeInput(String(normalized.lng));
5671
+ setValidationMessage(null);
5672
+ onChange(formatCoordinate(normalized));
5673
+ }, [onChange]);
5674
+ const validateLat = (raw) => {
5675
+ if (raw === '')
5676
+ return null;
5677
+ const n = Number(raw);
5678
+ if (Number.isNaN(n))
5679
+ return 'Latitude must be a number.';
5680
+ if (n < -90 || n > 90)
5681
+ return 'Latitude must be between -90 and 90.';
5682
+ return null;
5683
+ };
5684
+ const validateLng = (raw) => {
5685
+ if (raw === '')
5686
+ return null;
5687
+ const n = Number(raw);
5688
+ if (Number.isNaN(n))
5689
+ return 'Longitude must be a number.';
5690
+ if (n < -180 || n > 180)
5691
+ return 'Longitude must be between -180 and 180.';
5692
+ return null;
5693
+ };
5694
+ const handleLatitudeChange = (event) => {
5695
+ const raw = event.value;
5696
+ setLatitudeInput(raw);
5697
+ setOutsideAreaAcknowledged(false);
5698
+ const latErr = validateLat(raw);
5699
+ if (latErr) {
5700
+ setValidationMessage(latErr);
5701
+ return;
5702
+ }
5703
+ if (raw === '' || longitudeInput === '') {
5704
+ applyCoordinateChange(null);
5705
+ return;
5706
+ }
5707
+ const lngErr = validateLng(longitudeInput);
5708
+ if (lngErr) {
5709
+ setValidationMessage(lngErr);
5710
+ return;
5711
+ }
5712
+ const updated = { lat: Number(raw), lng: Number(longitudeInput) };
5713
+ setPendingCoordinate(updated);
5714
+ applyCoordinateChange(updated);
5715
+ };
5716
+ const handleLongitudeChange = (event) => {
5717
+ const raw = event.value;
5718
+ setLongitudeInput(raw);
5719
+ setOutsideAreaAcknowledged(false);
5720
+ const lngErr = validateLng(raw);
5721
+ if (lngErr) {
5722
+ setValidationMessage(lngErr);
5723
+ return;
5724
+ }
5725
+ if (latitudeInput === '' || raw === '') {
5726
+ applyCoordinateChange(null);
5727
+ return;
5728
+ }
5729
+ const latErr = validateLat(latitudeInput);
5730
+ if (latErr) {
5731
+ setValidationMessage(latErr);
5732
+ return;
5733
+ }
5734
+ const updated = { lat: Number(latitudeInput), lng: Number(raw) };
5735
+ setPendingCoordinate(updated);
5736
+ applyCoordinateChange(updated);
5737
+ };
5738
+ const handleAccuracyChange = (event) => {
5739
+ const raw = event.value.trim();
5740
+ if (!onAccuracyKmChange)
5741
+ return;
5742
+ if (raw === '') {
5743
+ onAccuracyKmChange(null);
5744
+ onAccuracySourceChange?.('MANUAL');
5745
+ return;
5746
+ }
5747
+ const n = Number(raw);
5748
+ if (Number.isNaN(n) || n <= 0) {
5749
+ setValidationMessage('Accuracy radius must be a positive number (KM).');
5750
+ return;
5751
+ }
5752
+ if (n > maxAccuracyKm) {
5753
+ setValidationMessage(`Accuracy radius should not exceed ${maxAccuracyKm} km.`);
5754
+ return;
5755
+ }
5756
+ setValidationMessage(null);
5757
+ onAccuracyKmChange(n);
5758
+ onAccuracySourceChange?.('MANUAL');
5759
+ };
5760
+ const handleOpenMapDialog = () => {
5761
+ if (disabled)
5762
+ return;
5763
+ const base = currentCoordinate ?? pendingCoordinate ?? null;
5764
+ if (base) {
5765
+ setPendingCoordinate(base);
5766
+ setMapCenterPosition([base.lat, base.lng]);
5767
+ }
5768
+ else {
5769
+ setMapCenterPosition(DEFAULT_CENTER);
5770
+ }
5771
+ setIsMapDialogOpen(true);
5772
+ setOutsideAreaAcknowledged(false);
5773
+ if (!base && navigator.geolocation) {
5774
+ navigator.geolocation.getCurrentPosition((position) => {
5775
+ const coordinate = normalizeCoordinate(position.coords.latitude, position.coords.longitude);
5776
+ const km = metersToKmRadius(position.coords.accuracy);
5777
+ if (captureAccuracy && km != null && onAccuracyKmChange) {
5778
+ const boundedKm = Math.min(km, maxAccuracyKm);
5779
+ onAccuracyKmChange(boundedKm);
5780
+ onAccuracySourceChange?.('DEVICE');
5781
+ }
5782
+ if (coordinate) {
5783
+ setPendingCoordinate(coordinate);
5784
+ setMapCenterPosition([coordinate.lat, coordinate.lng]);
5785
+ }
5786
+ else {
5787
+ setMapCenterPosition(DEFAULT_CENTER);
5788
+ }
5789
+ }, () => {
5790
+ setValidationMessage((prev) => prev ??
5791
+ 'We could not detect your location. Please move the map and click on the correct place.');
5792
+ }, { enableHighAccuracy: true, timeout: 12000, maximumAge: 30000 });
5793
+ }
5794
+ };
5795
+ const handleCloseMapDialog = () => {
5796
+ setIsMapDialogOpen(false);
5797
+ setOutsideAreaAcknowledged(false);
5798
+ };
5799
+ const handleMapClick = (coordinate) => {
5800
+ const normalized = normalizeCoordinate(coordinate.lat, coordinate.lng);
5801
+ if (!normalized)
5802
+ return;
5803
+ setPendingCoordinate(normalized);
5804
+ setMapCenterPosition([normalized.lat, normalized.lng]);
5805
+ setOutsideAreaAcknowledged(false);
5806
+ };
5807
+ const canConfirm = !!pendingCoordinate &&
5808
+ (!isOutsideAllowedArea || outsideAreaAcknowledged) &&
5809
+ (!requireWithinArea || !isOutsideAllowedArea);
5810
+ const handleConfirmFromMap = () => {
5811
+ if (!pendingCoordinate)
5812
+ return;
5813
+ const boundary = safeAllowedAreaGeoJson;
5814
+ const outside = boundary
5815
+ ? !isPointInsideGeoJsonArea(pendingCoordinate, boundary)
5816
+ : false;
5817
+ if (outside) {
5818
+ onOutsideAreaSelected?.({
5819
+ lat: pendingCoordinate.lat,
5820
+ lng: pendingCoordinate.lng,
5821
+ allowedAreaName,
5822
+ requireWithinArea,
5823
+ accuracyKm: accuracyKmValue,
5824
+ });
5825
+ if (requireWithinArea) {
5826
+ setValidationMessage(`Selected point is outside ${allowedAreaDisplayName}. Please pick a location within the boundary.`);
5827
+ return;
5828
+ }
5829
+ if (!outsideAreaAcknowledged) {
5830
+ setOutsideAreaAcknowledged(true);
5831
+ return;
5832
+ }
5833
+ }
5834
+ applyCoordinateChange(pendingCoordinate);
5835
+ setIsMapDialogOpen(false);
5836
+ setOutsideAreaAcknowledged(false);
5837
+ };
5838
+ const combinedErrorMessage = validationMessage || (error ? validationText : null);
5839
+ const selectedLocationText = markerCoordinate
5840
+ ? `Selected location: Lat ${markerCoordinate.lat.toFixed(5)}, Lon ${markerCoordinate.lng.toFixed(5)}`
5841
+ : 'No location selected yet. Click on the street map to drop a marker.';
5842
+ const outsideNoticeTitle = requireWithinArea
5843
+ ? `Location outside allowed area (not permitted)`
5844
+ : `Location outside allowed area (review required)`;
5845
+ // Optional debug logs (keep outside JSX)
5846
+ console.log('rawAllowedArea:', rawAllowedArea);
5847
+ console.log('safeAllowedAreaGeoJson:', safeAllowedAreaGeoJson);
5848
+ return (React__default.createElement(React__default.Fragment, null,
5849
+ React__default.createElement(Field, { label: label, name: name, required: required, error: Boolean(combinedErrorMessage), validationText: combinedErrorMessage ?? undefined },
5850
+ React__default.createElement("div", { style: {
5851
+ display: 'grid',
5852
+ gridTemplateColumns: captureAccuracy
5853
+ ? 'minmax(0, 1.2fr) minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr)'
5854
+ : 'minmax(0, 1.2fr) minmax(0, 1fr) minmax(0, 1fr)',
5855
+ gap: 8,
5856
+ alignItems: 'flex-end',
5857
+ } },
5858
+ React__default.createElement("div", { style: { display: 'flex', flexDirection: 'column', gap: 4 } },
5859
+ React__default.createElement(Button$1, { name: `${name}-open-map`, disabled: disabled, onClick: handleOpenMapDialog, secondary: true }, currentCoordinate
5860
+ ? 'Update location on map'
5861
+ : 'Pick location on map')),
5862
+ React__default.createElement(InputField$1, { label: "Latitude (\u00B0)", name: `${name}-lat`, type: "number", step: "0.000001",
5863
+ // disabled={disabled}
5864
+ disabled: true, value: latitudeInput, onChange: handleLatitudeChange, onBlur: onBlur, placeholder: "-6.814527" }),
5865
+ React__default.createElement(InputField$1, { label: "Longitude (\u00B0)", name: `${name}-lng`, type: "number", step: "0.000001",
5866
+ // disabled={disabled}
5867
+ disabled: true, value: longitudeInput, onChange: handleLongitudeChange, onBlur: onBlur, placeholder: "39.279557" }),
5868
+ captureAccuracy && (React__default.createElement(InputField$1, { label: "Accuracy radius (km)", name: `${name}-accuracy-km`, type: "number", step: "0.1", min: "0",
5869
+ // disabled={disabled}
5870
+ disabled: true, value: accuracyKmValue == null ? '' : String(accuracyKmValue), onChange: handleAccuracyChange, onBlur: onBlur, placeholder: "e.g. 0.1" })))),
5871
+ isMapDialogOpen && (
5872
+ // <Modal
5873
+ // onClose={handleCloseMapDialog}
5874
+ // position="middle"
5875
+ // className="coordinate-modal"
5876
+ // >
5877
+ // <ModalTitle>Select location on street map</ModalTitle>
5878
+ // <ModalContent>
5879
+ // <div
5880
+ // style={{
5881
+ // display: 'flex',
5882
+ // flexDirection: 'row',
5883
+ // flexWrap: 'wrap',
5884
+ // width: '100%',
5885
+ // height: '70vh',
5886
+ // gap: 16,
5887
+ // overflow: 'hidden',
5888
+ // }}
5889
+ // >
5890
+ // {/* ------------------ MAP AREA (flex: 3) ------------------ */}
5891
+ // <div
5892
+ // style={{
5893
+ // flex: '3 1 60%',
5894
+ // borderRadius: 8,
5895
+ // overflow: 'hidden',
5896
+ // boxShadow: '0 1px 4px rgba(0,0,0,0.15)',
5897
+ // minWidth: '320px',
5898
+ // }}
5899
+ // >
5900
+ // <CoordinateMapContainer
5901
+ // center={mapCenterPosition}
5902
+ // zoom={markerCoordinate ? 12 : DEFAULT_ZOOM}
5903
+ // style={{ width: '100%', height: '100%' }}
5904
+ // scrollWheelZoom={!disabled}
5905
+ // >
5906
+ // <TileLayer
5907
+ // attribution="© OpenStreetMap contributors"
5908
+ // url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
5909
+ // />
5910
+ // {safeAllowedAreaGeoJson && (
5911
+ // <>
5912
+ // <LeafletGeoJSON
5913
+ // data={safeAllowedAreaGeoJson as any}
5914
+ // style={(feature: any) => {
5915
+ // const isMulti =
5916
+ // feature?.geometry?.type === 'MultiPolygon' ||
5917
+ // safeAllowedAreaGeoJson.type === 'MultiPolygon';
5918
+ // // Consistent DHIS2-like palette
5919
+ // const strokeColor = isMulti ? '#E67E22' : '#1976D2';
5920
+ // const fillColor = isMulti ? '#FAD7A0' : '#BBDEFB';
5921
+ // return {
5922
+ // color: strokeColor,
5923
+ // weight: 2,
5924
+ // opacity: 0.9,
5925
+ // fillColor,
5926
+ // fillOpacity: 0.3,
5927
+ // dashArray: '4 4',
5928
+ // };
5929
+ // }}
5930
+ // />
5931
+ // <AutoFitToBoundary boundary={safeAllowedAreaGeoJson} />
5932
+ // </>
5933
+ // )}
5934
+ // <RecenterOnCoordinate coordinate={markerCoordinate} />
5935
+ // {markerCoordinate && (
5936
+ // <Marker
5937
+ // position={[markerCoordinate.lat, markerCoordinate.lng]}
5938
+ // />
5939
+ // )}
5940
+ // <MapClickListener
5941
+ // disabled={disabled}
5942
+ // onCoordinateSelected={handleMapClick}
5943
+ // />
5944
+ // </CoordinateMapContainer>
5945
+ // </div>
5946
+ // {/* ------------------ INFO PANEL (flex: 1) ------------------ */}
5947
+ // <div
5948
+ // style={{
5949
+ // flex: '1 1 30%',
5950
+ // display: 'flex',
5951
+ // flexDirection: 'column',
5952
+ // gap: 12,
5953
+ // minWidth: '280px',
5954
+ // overflowY: 'auto',
5955
+ // maxHeight: '70vh',
5956
+ // }}
5957
+ // >
5958
+ // {markerCoordinate && (
5959
+ // <>
5960
+ // {safeAllowedAreaGeoJson ? (
5961
+ // isOutsideAllowedArea ? (
5962
+ // requireWithinArea ? (
5963
+ // // 🟥 ERROR: Outside & not permitted
5964
+ // <NoticeBox
5965
+ // error
5966
+ // title="Outside Allowed Area (Not Permitted)"
5967
+ // >
5968
+ // <p>
5969
+ // The selected location is outside{' '}
5970
+ // <b>{allowedAreaDisplayName}</b>. You must pick a
5971
+ // point <b>within</b> the boundary to continue.
5972
+ // </p>
5973
+ // </NoticeBox>
5974
+ // ) : (
5975
+ // // 🟧 WARNING: Outside but allowed
5976
+ // <NoticeBox title="Outside Allowed Area (Review Required)">
5977
+ // <p>
5978
+ // The selected point is outside{' '}
5979
+ // <b>{allowedAreaDisplayName}</b>. Click{' '}
5980
+ // <b>Use Selected Location</b> again to confirm this
5981
+ // is intentional.
5982
+ // </p>
5983
+ // <p>
5984
+ // Saving out-of-boundary data may cause reporting
5985
+ // inconsistencies.
5986
+ // </p>
5987
+ // </NoticeBox>
5988
+ // )
5989
+ // ) : (
5990
+ // // 🟩 VALID: Inside allowed area
5991
+ // <NoticeBox valid title="Valid Location within Boundary">
5992
+ // <p>
5993
+ // <strong>Selected Location:</strong>
5994
+ // <br />
5995
+ // Lat {markerCoordinate.lat.toFixed(5)}, Lon{' '}
5996
+ // {markerCoordinate.lng.toFixed(5)}
5997
+ // </p>
5998
+ // {captureAccuracy && (
5999
+ // <p>
6000
+ // <strong>Accuracy Info:</strong>
6001
+ // <br />
6002
+ // Radius: {accuracyKmValue ?? 'N/A'} km (
6003
+ // {accuracySource === 'DEVICE'
6004
+ // ? 'device-derived'
6005
+ // : accuracySource === 'MANUAL'
6006
+ // ? 'manual'
6007
+ // : 'unknown'}
6008
+ // )<br />
6009
+ // Max allowed: {maxAccuracyKm} km
6010
+ // </p>
6011
+ // )}
6012
+ // <p>
6013
+ // Pan or zoom to find the correct point. Click once to
6014
+ // drop the marker. Ensure it's within{' '}
6015
+ // {allowedAreaDisplayName}.
6016
+ // </p>
6017
+ // </NoticeBox>
6018
+ // )
6019
+ // ) : (
6020
+ // // ℹ️ INFO: When no boundary provided
6021
+ // <NoticeBox title="Selected Location">
6022
+ // <p>
6023
+ // <strong>Selected Location:</strong>
6024
+ // <br />
6025
+ // Lat {markerCoordinate.lat.toFixed(5)}, Lon{' '}
6026
+ // {markerCoordinate.lng.toFixed(5)}
6027
+ // </p>
6028
+ // {captureAccuracy && (
6029
+ // <p>
6030
+ // <strong>Accuracy Info:</strong>
6031
+ // <br />
6032
+ // Radius: {accuracyKmValue ?? 'N/A'} km (
6033
+ // {accuracySource === 'DEVICE'
6034
+ // ? 'device-derived'
6035
+ // : accuracySource === 'MANUAL'
6036
+ // ? 'manual'
6037
+ // : 'unknown'}
6038
+ // )<br />
6039
+ // Max allowed: {maxAccuracyKm} km
6040
+ // </p>
6041
+ // )}
6042
+ // <p>
6043
+ // Pan or zoom to find the correct point. Click once to
6044
+ // drop the marker.
6045
+ // </p>
6046
+ // </NoticeBox>
6047
+ // )}
6048
+ // </>
6049
+ // )}
6050
+ // </div>
6051
+ // </div>
6052
+ // </ModalContent>
6053
+ // <ModalActions>
6054
+ // <div style={{ display: 'flex', gap: 12 }}>
6055
+ // <Button onClick={handleCloseMapDialog} secondary>
6056
+ // Cancel
6057
+ // </Button>
6058
+ // <Button
6059
+ // primary
6060
+ // onClick={handleConfirmFromMap}
6061
+ // disabled={!pendingCoordinate || disabled || !canConfirm}
6062
+ // >
6063
+ // {requireWithinArea && isOutsideAllowedArea
6064
+ // ? 'Pick a point inside boundary'
6065
+ // : !requireWithinArea &&
6066
+ // isOutsideAllowedArea &&
6067
+ // !outsideAreaAcknowledged
6068
+ // ? 'Review & Acknowledge'
6069
+ // : 'Use Selected Location'}
6070
+ // </Button>
6071
+ // </div>
6072
+ // </ModalActions>
6073
+ // </Modal>
6074
+ // <Modal
6075
+ // onClose={handleCloseMapDialog}
6076
+ // position="middle"
6077
+ // className="coordinate-modal"
6078
+ // >
6079
+ // <ModalTitle>
6080
+ // <div
6081
+ // style={{
6082
+ // display: 'flex',
6083
+ // justifyContent: 'space-between',
6084
+ // alignItems: 'center',
6085
+ // padding: '0 8px',
6086
+ // }}
6087
+ // >
6088
+ // <span style={{ fontWeight: 600, fontSize: 16 }}>
6089
+ // 🗺️ Select Location on Street Map
6090
+ // </span>
6091
+ // <span style={{ fontSize: 12, color: '#555' }}>
6092
+ // Click or tap on the map to choose coordinates
6093
+ // </span>
6094
+ // </div>
6095
+ // </ModalTitle>
6096
+ // <ModalContent>
6097
+ // <div
6098
+ // style={{
6099
+ // display: 'flex',
6100
+ // flexDirection: 'row',
6101
+ // flexWrap: 'wrap',
6102
+ // width: '100%',
6103
+ // height: '70vh',
6104
+ // gap: 16,
6105
+ // overflow: 'hidden',
6106
+ // }}
6107
+ // >
6108
+ // {/* ------------------ MAP AREA ------------------ */}
6109
+ // <div
6110
+ // style={{
6111
+ // flex: '3 1 60%',
6112
+ // borderRadius: 8,
6113
+ // overflow: 'hidden',
6114
+ // boxShadow: '0 1px 4px rgba(0,0,0,0.15)',
6115
+ // minWidth: '320px',
6116
+ // }}
6117
+ // >
6118
+ // <CoordinateMapContainer
6119
+ // center={mapCenterPosition}
6120
+ // zoom={markerCoordinate ? 12 : DEFAULT_ZOOM}
6121
+ // style={{ width: '100%', height: '100%' }}
6122
+ // scrollWheelZoom={!disabled}
6123
+ // >
6124
+ // <TileLayer
6125
+ // attribution="© OpenStreetMap contributors"
6126
+ // url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
6127
+ // />
6128
+ // {safeAllowedAreaGeoJson && (
6129
+ // <>
6130
+ // <LeafletGeoJSON
6131
+ // data={safeAllowedAreaGeoJson as any}
6132
+ // style={(feature: any) => {
6133
+ // const isMulti =
6134
+ // feature?.geometry?.type === 'MultiPolygon' ||
6135
+ // safeAllowedAreaGeoJson.type === 'MultiPolygon';
6136
+ // const strokeColor = isMulti ? '#E67E22' : '#1976D2';
6137
+ // const fillColor = isMulti ? '#FAD7A0' : '#BBDEFB';
6138
+ // return {
6139
+ // color: strokeColor,
6140
+ // weight: 2,
6141
+ // opacity: 0.9,
6142
+ // fillColor,
6143
+ // fillOpacity: 0.3,
6144
+ // dashArray: '4 4',
6145
+ // };
6146
+ // }}
6147
+ // />
6148
+ // <AutoFitToBoundary boundary={safeAllowedAreaGeoJson} />
6149
+ // </>
6150
+ // )}
6151
+ // <RecenterOnCoordinate coordinate={markerCoordinate} />
6152
+ // {markerCoordinate && (
6153
+ // <Marker
6154
+ // position={[markerCoordinate.lat, markerCoordinate.lng]}
6155
+ // />
6156
+ // )}
6157
+ // <MapClickListener
6158
+ // disabled={disabled}
6159
+ // onCoordinateSelected={handleMapClick}
6160
+ // />
6161
+ // </CoordinateMapContainer>
6162
+ // </div>
6163
+ // {/* ------------------ SIDE INFO PANEL ------------------ */}
6164
+ // <div
6165
+ // style={{
6166
+ // flex: '1 1 30%',
6167
+ // display: 'flex',
6168
+ // flexDirection: 'column',
6169
+ // gap: 12,
6170
+ // minWidth: '280px',
6171
+ // overflowY: 'auto',
6172
+ // maxHeight: '70vh',
6173
+ // }}
6174
+ // >
6175
+ // {/* 🟦 Top Info Box (always visible) */}
6176
+ // <NoticeBox title="Selected Location Info">
6177
+ // {markerCoordinate ? (
6178
+ // <div
6179
+ // style={{
6180
+ // display: 'flex',
6181
+ // flexDirection: 'column',
6182
+ // gap: 6,
6183
+ // }}
6184
+ // >
6185
+ // <div>
6186
+ // <strong>Selected Location:</strong>
6187
+ // <br />
6188
+ // Lat {markerCoordinate.lat.toFixed(5)}, Lon{' '}
6189
+ // {markerCoordinate.lng.toFixed(5)}
6190
+ // </div>
6191
+ // {captureAccuracy && (
6192
+ // <div>
6193
+ // <strong>Accuracy Info:</strong>
6194
+ // <br />
6195
+ // Radius: {accuracyKmValue ?? 'N/A'} km (
6196
+ // {accuracySource === 'DEVICE'
6197
+ // ? 'device-derived'
6198
+ // : accuracySource === 'MANUAL'
6199
+ // ? 'manual'
6200
+ // : 'unknown'}
6201
+ // )<br />
6202
+ // Max allowed: {maxAccuracyKm} km
6203
+ // </div>
6204
+ // )}
6205
+ // </div>
6206
+ // ) : (
6207
+ // <p>
6208
+ // No location selected yet. Click on the map to drop a
6209
+ // marker.
6210
+ // </p>
6211
+ // )}
6212
+ // </NoticeBox>
6213
+ // {/* ✅ Valid or ❌ Error */}
6214
+ // {markerCoordinate &&
6215
+ // safeAllowedAreaGeoJson &&
6216
+ // (isOutsideAllowedArea ? (
6217
+ // <NoticeBox
6218
+ // error
6219
+ // title="Outside Allowed Area (Not Permitted)"
6220
+ // >
6221
+ // <p>
6222
+ // The selected location is <strong>outside</strong> the
6223
+ // required boundary (<b>{allowedAreaDisplayName}</b>).
6224
+ // </p>
6225
+ // <p>
6226
+ // Please pick a point <b>within</b> the Shehia boundary.
6227
+ // </p>
6228
+ // </NoticeBox>
6229
+ // ) : (
6230
+ // <NoticeBox valid title="Valid Location within Boundary">
6231
+ // <p>
6232
+ // ✅ You have successfully selected a valid location
6233
+ // inside {allowedAreaDisplayName}.
6234
+ // </p>
6235
+ // </NoticeBox>
6236
+ // ))}
6237
+ // {/* 🟦 Bottom Instructions (always visible) */}
6238
+ // <NoticeBox title="Instructions">
6239
+ // <p style={{ marginBottom: 0, lineHeight: 1.5 }}>
6240
+ // Pan or zoom to find the correct point. Click once to drop
6241
+ // the marker. Ensure it's within <b>Shehia boundary</b>.
6242
+ // </p>
6243
+ // </NoticeBox>
6244
+ // </div>
6245
+ // </div>
6246
+ // </ModalContent>
6247
+ // <ModalActions>
6248
+ // <div
6249
+ // style={{
6250
+ // display: 'flex',
6251
+ // justifyContent: 'space-between',
6252
+ // alignItems: 'center',
6253
+ // width: '100%',
6254
+ // }}
6255
+ // >
6256
+ // <div style={{ fontSize: 13, color: '#666' }}>
6257
+ // <span>💡 Tip:</span> You can click again to reposition your
6258
+ // marker.
6259
+ // </div>
6260
+ // <div style={{ display: 'flex', gap: 12 }}>
6261
+ // <Button onClick={handleCloseMapDialog} secondary>
6262
+ // Cancel
6263
+ // </Button>
6264
+ // <Button
6265
+ // primary
6266
+ // onClick={handleConfirmFromMap}
6267
+ // disabled={!pendingCoordinate || disabled || !canConfirm}
6268
+ // >
6269
+ // {requireWithinArea && isOutsideAllowedArea
6270
+ // ? 'Pick a point inside boundary'
6271
+ // : !requireWithinArea &&
6272
+ // isOutsideAllowedArea &&
6273
+ // !outsideAreaAcknowledged
6274
+ // ? 'Review & Acknowledge'
6275
+ // : 'Use Selected Location'}
6276
+ // </Button>
6277
+ // </div>
6278
+ // </div>
6279
+ // </ModalActions>
6280
+ // </Modal>
6281
+ React__default.createElement(Modal$1, { onClose: handleCloseMapDialog, position: "middle", className: "coordinate-modal" },
6282
+ React__default.createElement(ModalTitle$1, null,
6283
+ React__default.createElement("div", { style: {
6284
+ display: 'flex',
6285
+ justifyContent: 'space-between',
6286
+ alignItems: 'center',
6287
+ padding: '0.25rem 0.5rem',
6288
+ } },
6289
+ React__default.createElement("span", { style: {
6290
+ fontWeight: 600,
6291
+ fontSize: 16,
6292
+ display: 'flex',
6293
+ alignItems: 'center',
6294
+ gap: 6,
6295
+ } }, "\uD83D\uDDFA\uFE0F Select Location on Map"),
6296
+ React__default.createElement("span", { style: { fontSize: 12, color: '#666' } }, "Click or tap on the map to choose coordinates"))),
6297
+ React__default.createElement(ModalContent$1, null,
6298
+ React__default.createElement("div", { style: {
6299
+ display: 'flex',
6300
+ flexDirection: 'row',
6301
+ width: '100%',
6302
+ height: '72vh',
6303
+ overflow: 'hidden',
6304
+ gap: 16,
6305
+ } },
6306
+ React__default.createElement("div", { style: {
6307
+ flex: '0 0 75%',
6308
+ position: 'relative',
6309
+ borderRadius: 10,
6310
+ overflow: 'hidden',
6311
+ boxShadow: '0 2px 6px rgba(0,0,0,0.1)',
6312
+ } },
6313
+ React__default.createElement(CoordinateMapContainer, { center: mapCenterPosition, zoom: markerCoordinate ? 12 : DEFAULT_ZOOM, style: { width: '100%', height: '100%' }, scrollWheelZoom: !disabled },
6314
+ React__default.createElement(TileLayer, { attribution: "\u00A9 OpenStreetMap contributors", url: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" }),
6315
+ safeAllowedAreaGeoJson && (React__default.createElement(React__default.Fragment, null,
6316
+ React__default.createElement(GeoJSON, { data: safeAllowedAreaGeoJson, style: (feature) => {
6317
+ const isMulti = feature?.geometry?.type === 'MultiPolygon' ||
6318
+ safeAllowedAreaGeoJson.type === 'MultiPolygon';
6319
+ const strokeColor = isMulti ? '#F39C12' : '#1565C0';
6320
+ const fillColor = isMulti ? '#FDEBD0' : '#E3F2FD';
6321
+ return {
6322
+ color: strokeColor,
6323
+ weight: 3,
6324
+ opacity: 0.95,
6325
+ fillColor,
6326
+ fillOpacity: 0.35,
6327
+ dashArray: '6 4',
6328
+ lineJoin: 'round',
6329
+ lineCap: 'round',
6330
+ };
6331
+ } }),
6332
+ React__default.createElement(AutoFitToBoundary, { boundary: safeAllowedAreaGeoJson }))),
6333
+ React__default.createElement(RecenterOnCoordinate, { coordinate: markerCoordinate }),
6334
+ markerCoordinate && (React__default.createElement(Marker, { position: [markerCoordinate.lat, markerCoordinate.lng] })),
6335
+ React__default.createElement(MapClickListener, { disabled: disabled, onCoordinateSelected: handleMapClick })),
6336
+ React__default.createElement("div", { style: {
6337
+ position: 'absolute',
6338
+ top: 12,
6339
+ right: 12,
6340
+ background: !markerCoordinate
6341
+ ? '#0288D1'
6342
+ : isOutsideAllowedArea
6343
+ ? '#C62828'
6344
+ : '#2E7D32',
6345
+ color: '#fff',
6346
+ borderRadius: 6,
6347
+ padding: '5px 12px',
6348
+ fontSize: 13,
6349
+ fontWeight: 600,
6350
+ boxShadow: '0 1px 4px rgba(0,0,0,0.25)',
6351
+ transition: 'background 0.3s ease',
6352
+ zIndex: 999,
6353
+ letterSpacing: 0.3,
6354
+ } }, !markerCoordinate
6355
+ ? 'No location selected'
6356
+ : isOutsideAllowedArea
6357
+ ? 'Outside boundary'
6358
+ : 'Valid location')),
6359
+ React__default.createElement("div", { style: {
6360
+ flex: '0 0 25%',
6361
+ display: 'flex',
6362
+ flexDirection: 'column',
6363
+ justifyContent: 'space-between',
6364
+ height: '100%',
6365
+ overflowY: 'auto',
6366
+ borderLeft: '1px solid #e0e0e0',
6367
+ padding: '0 12px',
6368
+ } },
6369
+ React__default.createElement("div", { style: {
6370
+ display: 'flex',
6371
+ flexDirection: 'column',
6372
+ gap: 12,
6373
+ paddingTop: 2,
6374
+ paddingRight: 6,
6375
+ } },
6376
+ React__default.createElement(NoticeBox, { title: "Selected Location Info" }, markerCoordinate ? (React__default.createElement("div", { style: {
6377
+ display: 'flex',
6378
+ flexDirection: 'column',
6379
+ gap: 6,
6380
+ } },
6381
+ React__default.createElement("div", null,
6382
+ React__default.createElement("strong", null, "Selected Location:"),
6383
+ React__default.createElement("br", null),
6384
+ "Lat ",
6385
+ markerCoordinate.lat.toFixed(5),
6386
+ ", Lon",
6387
+ ' ',
6388
+ markerCoordinate.lng.toFixed(5)),
6389
+ captureAccuracy && (React__default.createElement("div", null,
6390
+ React__default.createElement("strong", null, "Accuracy Info:"),
6391
+ React__default.createElement("br", null),
6392
+ "Radius: ",
6393
+ accuracyKmValue ?? 'N/A',
6394
+ " km (",
6395
+ accuracySource === 'DEVICE'
6396
+ ? 'device-derived'
6397
+ : accuracySource === 'MANUAL'
6398
+ ? 'manual'
6399
+ : 'unknown',
6400
+ ")",
6401
+ React__default.createElement("br", null),
6402
+ "Max allowed: ",
6403
+ maxAccuracyKm,
6404
+ " km")))) : (React__default.createElement("p", null, "No location selected yet. Click on the map to drop a marker."))),
6405
+ markerCoordinate &&
6406
+ safeAllowedAreaGeoJson &&
6407
+ (isOutsideAllowedArea ? (React__default.createElement(NoticeBox, { error: true, title: "Outside Allowed Area (Not Permitted)" },
6408
+ React__default.createElement("p", null,
6409
+ "The selected location is ",
6410
+ React__default.createElement("strong", null, "outside"),
6411
+ " the required boundary (",
6412
+ React__default.createElement("b", null, allowedAreaDisplayName),
6413
+ ")."),
6414
+ React__default.createElement("p", null,
6415
+ "Please pick a point ",
6416
+ React__default.createElement("b", null, "within"),
6417
+ " the Shehia boundary."))) : (React__default.createElement(NoticeBox, { valid: true, title: "Valid Location within Boundary" },
6418
+ React__default.createElement("p", null,
6419
+ "\u2705 You have successfully selected a valid location inside ",
6420
+ allowedAreaDisplayName,
6421
+ "."))))),
6422
+ React__default.createElement("div", { style: { paddingBottom: 8 } },
6423
+ React__default.createElement(NoticeBox, { title: "Instructions" },
6424
+ React__default.createElement("p", { style: { margin: 0, lineHeight: 1.6 } },
6425
+ "Pan or zoom to find the correct point. Click once to drop the marker. Ensure it's within ",
6426
+ React__default.createElement("b", null, "Shehia boundary"),
6427
+ ".")))))),
6428
+ React__default.createElement(ModalActions$1, null,
6429
+ React__default.createElement("div", { style: {
6430
+ display: 'flex',
6431
+ justifyContent: 'flex-end',
6432
+ alignItems: 'center',
6433
+ width: '100%',
6434
+ gap: 12,
6435
+ } },
6436
+ React__default.createElement(Button$1, { onClick: handleCloseMapDialog, secondary: true }, "Cancel"),
6437
+ React__default.createElement(Button$1, { primary: true, onClick: handleConfirmFromMap, disabled: !pendingCoordinate || disabled || !canConfirm }, requireWithinArea && isOutsideAllowedArea
6438
+ ? 'Pick a point inside boundary'
6439
+ : !requireWithinArea &&
6440
+ isOutsideAllowedArea &&
6441
+ !outsideAreaAcknowledged
6442
+ ? 'Review & Acknowledge'
6443
+ : 'Use Selected Location')))))));
6444
+ };
6445
+
5331
6446
  // Copyright 2025 UDSM DHIS2 Lab. All rights reserved.
5332
6447
  // Use of this source code is governed by a BSD-style
5333
6448
  // license that can be found in the LICENSE file.
@@ -5410,6 +6525,157 @@ const FileUploadField = (props) => {
5410
6525
  } })))));
5411
6526
  };
5412
6527
 
6528
+ const ALL_COUNTRIES = [
6529
+ // East Africa first (for convenience)
6530
+ { isoCode: 'TZ', dialCode: '+255', name: 'Tanzania', flag: '🇹🇿' },
6531
+ { isoCode: 'KE', dialCode: '+254', name: 'Kenya', flag: '🇰🇪' },
6532
+ { isoCode: 'UG', dialCode: '+256', name: 'Uganda', flag: '🇺🇬' },
6533
+ { isoCode: 'RW', dialCode: '+250', name: 'Rwanda', flag: '🇷🇼' },
6534
+ { isoCode: 'BI', dialCode: '+257', name: 'Burundi', flag: '🇧🇮' },
6535
+ { isoCode: 'SS', dialCode: '+211', name: 'South Sudan', flag: '🇸🇸' },
6536
+ { isoCode: 'ET', dialCode: '+251', name: 'Ethiopia', flag: '🇪🇹' },
6537
+ // A few examples from other regions:
6538
+ { isoCode: 'GB', dialCode: '+44', name: 'United Kingdom', flag: '🇬🇧' },
6539
+ { isoCode: 'US', dialCode: '+1', name: 'United States', flag: '🇺🇸' },
6540
+ { isoCode: 'CA', dialCode: '+1', name: 'Canada', flag: '🇨🇦' },
6541
+ { isoCode: 'DE', dialCode: '+49', name: 'Germany', flag: '🇩🇪' },
6542
+ { isoCode: 'IN', dialCode: '+91', name: 'India', flag: '🇮🇳' },
6543
+ { isoCode: 'CN', dialCode: '+86', name: 'China', flag: '🇨🇳' },
6544
+ { isoCode: 'BR', dialCode: '+55', name: 'Brazil', flag: '🇧🇷' },
6545
+ // 👉 Here you add the rest of the world.
6546
+ // You can load a standard JSON of all countries (isoCode, dialCode, name, flag)
6547
+ // and generate this array at build time if you prefer.
6548
+ ];
6549
+
6550
+ /* eslint-disable @typescript-eslint/no-non-null-assertion */
6551
+ const DEFAULT_COUNTRY_ISO = 'TZ';
6552
+ const FilterableSingleSelectField = SingleSelectField;
6553
+ function normalizeTanzaniaLocal(raw) {
6554
+ const digits = (raw || '').replace(/\D/g, '');
6555
+ if (!digits)
6556
+ return '';
6557
+ if (digits.startsWith('255')) {
6558
+ let sub = digits.slice(3);
6559
+ if (sub.startsWith('0'))
6560
+ sub = sub.slice(1);
6561
+ return ('0' + sub).slice(0, 10);
6562
+ }
6563
+ if (digits.startsWith('0')) {
6564
+ return digits.slice(0, 10);
6565
+ }
6566
+ if (/^[67]\d{7,9}$/.test(digits)) {
6567
+ return ('0' + digits).slice(0, 10);
6568
+ }
6569
+ if (digits.length >= 9 && !digits.startsWith('0')) {
6570
+ return ('0' + digits.slice(0, 9)).slice(0, 10);
6571
+ }
6572
+ return digits.slice(0, 10);
6573
+ }
6574
+ const InternationalPhoneField = ({ name, label, placeholder, value, required, disabled, error, validationText, inputWidth, defaultCountryIsoCode = DEFAULT_COUNTRY_ISO, onChange, onBlur, }) => {
6575
+ const [selectedIsoCode, setSelectedIsoCode] = React__default.useState(defaultCountryIsoCode);
6576
+ const [filterText, setFilterText] = React__default.useState('');
6577
+ const [leadingZeroWarning, setLeadingZeroWarning] = React__default.useState(null);
6578
+ const selectedCountry = ALL_COUNTRIES.find((c) => c.isoCode === selectedIsoCode) ??
6579
+ ALL_COUNTRIES.find((c) => c.isoCode === DEFAULT_COUNTRY_ISO);
6580
+ const [localNumber, setLocalNumber] = React__default.useState('');
6581
+ React__default.useEffect(() => {
6582
+ const raw = value ?? '';
6583
+ if (selectedCountry.isoCode === 'TZ') {
6584
+ const normalizedStored = normalizeTanzaniaLocal(raw);
6585
+ if (!normalizedStored) {
6586
+ setLocalNumber('');
6587
+ return;
6588
+ }
6589
+ const digits = normalizedStored.replace(/\D/g, '');
6590
+ const ui = digits.startsWith('0') ? digits.slice(1) : digits;
6591
+ setLocalNumber(ui);
6592
+ }
6593
+ else {
6594
+ const digits = raw.replace(/\D/g, '').slice(0, 15);
6595
+ setLocalNumber(digits);
6596
+ }
6597
+ setLeadingZeroWarning(null);
6598
+ }, [value, selectedCountry.isoCode]);
6599
+ const filteredCountries = React__default.useMemo(() => {
6600
+ const term = filterText.trim().toLowerCase();
6601
+ if (!term)
6602
+ return ALL_COUNTRIES;
6603
+ return ALL_COUNTRIES.filter((c) => {
6604
+ const haystack = `${c.name} ${c.dialCode} ${c.isoCode}`.toLowerCase();
6605
+ return haystack.includes(term);
6606
+ });
6607
+ }, [filterText]);
6608
+ const handleCountryChange = ({ selected }) => {
6609
+ setSelectedIsoCode(selected);
6610
+ };
6611
+ const handleLocalChange = ({ value }) => {
6612
+ const digitsOnly = (value || '').replace(/\D/g, '');
6613
+ if (selectedCountry.isoCode === 'TZ') {
6614
+ let ui = digitsOnly;
6615
+ if (ui.startsWith('0')) {
6616
+ setLeadingZeroWarning('For Tanzania, do not start the number with 0. Enter it without the leading 0 (e.g. 767000000).');
6617
+ ui = ui.slice(1);
6618
+ }
6619
+ else {
6620
+ setLeadingZeroWarning(null);
6621
+ }
6622
+ ui = ui.slice(0, 9);
6623
+ const stored = ui ? '0' + ui : '';
6624
+ setLocalNumber(ui);
6625
+ onChange(stored);
6626
+ }
6627
+ else {
6628
+ const ui = digitsOnly.slice(0, 15);
6629
+ setLocalNumber(ui);
6630
+ onChange(ui);
6631
+ setLeadingZeroWarning(null);
6632
+ }
6633
+ };
6634
+ const effectiveValidationText = leadingZeroWarning ??
6635
+ validationText ??
6636
+ 'Enter the phone number without the leading 0 (e.g. 767000000). The country code is already applied, and the system will store it as 0767000000 for Tanzania.';
6637
+ const hasError = Boolean(error || leadingZeroWarning);
6638
+ const wrapperStyle = {
6639
+ maxWidth: typeof inputWidth === 'number' ? inputWidth : inputWidth || 480,
6640
+ display: 'flex',
6641
+ flexDirection: 'column',
6642
+ gap: '0.5rem',
6643
+ };
6644
+ return (React__default.createElement("div", { style: wrapperStyle },
6645
+ label && (React__default.createElement("label", { htmlFor: name, style: {
6646
+ fontSize: '0.875rem',
6647
+ fontWeight: 500,
6648
+ color: '#1f2933',
6649
+ } },
6650
+ label,
6651
+ required ? (React__default.createElement("span", { style: { color: '#e53935', marginLeft: 4 } }, "*")) : null)),
6652
+ React__default.createElement("div", { style: {
6653
+ display: 'flex',
6654
+ width: '100%',
6655
+ gap: '0.75rem',
6656
+ alignItems: 'stretch',
6657
+ } },
6658
+ React__default.createElement("div", { style: {
6659
+ flex: '0 0 auto',
6660
+ width: 260,
6661
+ } },
6662
+ React__default.createElement(FilterableSingleSelectField, { selected: selectedIsoCode, onChange: handleCountryChange, disabled: disabled, dense: true, filterable: true, onFilterChange: ({ value }) => setFilterText(value), noMatchText: "No matching country" }, filteredCountries.map((country) => (React__default.createElement(SingleSelectOption, { disabled: disabled, key: country.isoCode, value: country.isoCode, label: `${country.flag} ${country.name} (${country.dialCode})` }))))),
6663
+ React__default.createElement("div", { style: { flex: '1 1 0', minWidth: 0 } },
6664
+ React__default.createElement(InputField$1, { type: "tel", name: name, placeholder: placeholder ?? '767000000', value: localNumber, required: required, disabled: disabled, error: hasError, validationText: effectiveValidationText, autoComplete: "tel", max: selectedCountry.isoCode === 'TZ' ? '9' : '15', onChange: handleLocalChange, onBlur: () => {
6665
+ if (selectedCountry.isoCode === 'TZ') {
6666
+ const digits = (localNumber || '')
6667
+ .replace(/\D/g, '')
6668
+ .slice(0, 9);
6669
+ const stored = digits ? '0' + digits : '';
6670
+ if (digits !== localNumber) {
6671
+ setLocalNumber(digits);
6672
+ onChange(stored);
6673
+ }
6674
+ }
6675
+ onBlur?.();
6676
+ } })))));
6677
+ };
6678
+
5413
6679
  var OrgUnitLevel;
5414
6680
  (function (OrgUnitLevel) {
5415
6681
  OrgUnitLevel["SHEHIA"] = "SHEHIA";
@@ -6155,6 +7421,7 @@ const OrgUnitFormField = (props) => {
6155
7421
  const [selectedOrgUnit, setSelectedOrgUnit] = useState();
6156
7422
  const [expanded, setExpanded] = useState(initiallyExpanded);
6157
7423
  const [showOrgUnitTree, setShowOrgUnitTree] = useState(!selected);
7424
+ const [showRequiredNotice, setShowRequiredNotice] = useState(false);
6158
7425
  useEffect(() => {
6159
7426
  setLoading(true);
6160
7427
  if (selected) {
@@ -6195,498 +7462,944 @@ const OrgUnitFormField = (props) => {
6195
7462
  setExpanded([...expanded, path]);
6196
7463
  }
6197
7464
  };
6198
- const handleCollapse = ({ path }) => {
6199
- const pathIndex = expanded?.indexOf(path);
6200
- if (pathIndex && pathIndex !== -1 && expanded) {
6201
- const updatedExpanded = pathIndex === 0
6202
- ? expanded.slice(1)
6203
- : [...expanded.slice(0, pathIndex), ...expanded.slice(pathIndex + 1)];
6204
- setExpanded(updatedExpanded);
6205
- }
6206
- };
6207
- const handleOrgUnitSearch = async (query) => {
6208
- setSearchLoading(true);
6209
- try {
6210
- 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`);
6211
- setSearchData((searchResponse.data || {})['organisationUnits']);
6212
- setSearchLoading(false);
6213
- }
6214
- catch (e) {
6215
- setSearchLoading(false);
6216
- }
6217
- };
6218
- const debouncedSearch = useCallback(debounce((value) => {
6219
- handleOrgUnitSearch(value);
6220
- }, 500), []);
6221
- const handleFilterChange = (event) => {
6222
- setSearchText(event.value);
6223
- debouncedSearch(event.value);
6224
- };
6225
- const ready = useMemo(() => {
6226
- return searchText?.length ? !searchLoading : !loading;
6227
- }, [searchText, searchLoading, loading]);
6228
- const renderOrgUnitTree = () => {
6229
- if (searchText && searchText?.length > 0) {
6230
- if (searchLoading) {
6231
- return (React__default.createElement("div", { className: classes.orgUnitTreeLoader },
6232
- React__default.createElement(CircularLoader$1, { small: true })));
6233
- }
6234
- 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) => {
6235
- setSelectedOrgUnit(event);
6236
- setShowOrgUnitTree(false);
6237
- onSelectOrgUnit(event.id);
6238
- } })));
6239
- }
6240
- return (rootOrgUnits.length > 0 && (React__default.createElement(OrganisationUnitTree, { key: key, roots: rootOrgUnits?.map((orgUnit) => orgUnit.id) || [], singleSelection: true, expanded: expanded, handleExpand: handleExpand, handleCollapse: handleCollapse, selected: highlighted, onChange: (event) => {
6241
- setSelectedOrgUnit(event);
6242
- setShowOrgUnitTree(false);
6243
- onSelectOrgUnit(event.id);
6244
- } })));
6245
- };
6246
- return (config && (React__default.createElement(Provider, { config: config, plugin: false, parentAlertsAdd: undefined, showAlertsInPlugin: false },
6247
- React__default.createElement("div", null,
6248
- label && (React__default.createElement("div", { className: classes.orgUnitFieldLabel },
6249
- React__default.createElement("span", null, label),
6250
- required ? (React__default.createElement("span", { className: classes.orgUnitFieldRequiredLabel }, "*")) : (React__default.createElement(React__default.Fragment, null)))),
6251
- !showOrgUnitTree ? (selectedOrgUnit ? (React__default.createElement(React__default.Fragment, null,
6252
- React__default.createElement(Tooltip, { content: selectedOrgUnitLabel }, disabled ? (React__default.createElement(Chip, null, selectedOrgUnit.displayName)) : (React__default.createElement(Chip, { onRemove: () => {
6253
- setShowOrgUnitTree(true);
6254
- } }, selectedOrgUnit.displayName))))) : (React__default.createElement("div", { className: classes.orgUnitTreeLoader },
6255
- React__default.createElement(CircularLoader$1, { small: true })))) : (React__default.createElement("div", { className: classes.container },
6256
- React__default.createElement("div", { className: classes.debounceFieldContainer },
6257
- React__default.createElement(InputField$1, { placeholder: "Search", value: searchText, disabled: disabled, onChange: handleFilterChange })),
6258
- loading ? (React__default.createElement("div", { className: classes.orgUnitTreeLoader },
6259
- React__default.createElement(CircularLoader$1, { small: true }))) : (React__default.createElement("div", { className: classes.orgUnitTreeContainer, style: { maxHeight: '200px', overflowY: 'auto' } }, renderOrgUnitTree()))))))));
6260
- };
6261
-
6262
- // Copyright 2024 UDSM DHIS2 Lab. All rights reserved.
6263
- // Use of this source code is governed by a BSD-style
6264
- // license that can be found in the LICENSE file.
6265
- class FieldConfig {
6266
- constructor(config) {
6267
- this.hideLabel = config?.hideLabel ?? false;
6268
- this.inputWidth = config?.inputWidth || '100%';
6269
- }
6270
- }
6271
-
6272
- // Default focus: Zanzibar (Unguja) and nearby coastline
6273
- const DEFAULT_CENTER = [-6.1659, 39.2026];
6274
- const DEFAULT_ZOOM = 8;
6275
- function normalizeCoordinate(lat, lng) {
6276
- if (Number.isNaN(lat) || Number.isNaN(lng))
6277
- return null;
6278
- if (lat < -90 || lat > 90 || lng < -180 || lng > 180)
6279
- return null;
6280
- // Treat Null Island as "no coordinate"
6281
- if (lat === 0 && lng === 0)
6282
- return null;
6283
- return { lat, lng };
6284
- }
6285
- /**
6286
- * Accepts either:
6287
- * - "[lon,lat]" (JSON-style array)
6288
- * - "lat, lon" (string)
6289
- */
6290
- function parseCoordinate(value) {
6291
- if (!value || typeof value !== 'string')
6292
- return null;
6293
- const trimmed = value.trim();
6294
- let lat;
6295
- let lng;
6296
- if (trimmed.startsWith('[') && trimmed.endsWith(']')) {
6297
- try {
6298
- const arr = JSON.parse(trimmed);
6299
- if (!Array.isArray(arr) || arr.length < 2)
6300
- return null;
6301
- lng = Number(arr[0]);
6302
- lat = Number(arr[1]);
6303
- }
6304
- catch {
6305
- return null;
6306
- }
6307
- }
6308
- else {
6309
- const parts = trimmed.split(',').map((part) => part.trim());
6310
- if (parts.length !== 2)
6311
- return null;
6312
- lat = Number(parts[0]);
6313
- lng = Number(parts[1]);
6314
- }
6315
- return normalizeCoordinate(lat, lng);
6316
- }
6317
- function formatCoordinate(coordinate) {
6318
- if (!coordinate)
6319
- return null;
6320
- return `[${coordinate.lng.toFixed(6)},${coordinate.lat.toFixed(6)}]`;
6321
- }
6322
- const MapClickListener = ({ disabled, onCoordinateSelected, }) => {
6323
- useMapEvents({
6324
- click(event) {
6325
- if (disabled)
6326
- return;
6327
- const { lat, lng } = event.latlng;
6328
- onCoordinateSelected({ lat, lng });
6329
- },
6330
- });
6331
- return null;
6332
- };
6333
- const RecenterOnCoordinate = ({ coordinate }) => {
6334
- const map = useMap();
6335
- React__default.useEffect(() => {
6336
- if (coordinate) {
6337
- map.flyTo([coordinate.lat, coordinate.lng], map.getZoom(), {
6338
- duration: 0.4,
6339
- });
6340
- }
6341
- }, [coordinate, map]);
6342
- return null;
6343
- };
6344
- // DHIS2 / react-leaflet typing workaround
6345
- const CoordinateMapContainer = MapContainer;
6346
- const CoordinatePickerField = ({ label, name, value, required, disabled, error, validationText, onChange, onBlur, }) => {
6347
- const parsedCoordinate = React__default.useMemo(() => parseCoordinate(value), [value]);
6348
- const [latitudeInput, setLatitudeInput] = React__default.useState(parsedCoordinate ? String(parsedCoordinate.lat) : '');
6349
- const [longitudeInput, setLongitudeInput] = React__default.useState(parsedCoordinate ? String(parsedCoordinate.lng) : '');
6350
- const [validationMessage, setValidationMessage] = React__default.useState(null);
6351
- const [isMapDialogOpen, setIsMapDialogOpen] = React__default.useState(false);
6352
- const [pendingCoordinate, setPendingCoordinate] = React__default.useState(parsedCoordinate ?? null);
6353
- const [mapCenterPosition, setMapCenterPosition] = React__default.useState(parsedCoordinate
6354
- ? [parsedCoordinate.lat, parsedCoordinate.lng]
6355
- : DEFAULT_CENTER);
6356
- React__default.useEffect(() => {
6357
- const updatedCoordinate = parseCoordinate(value);
6358
- if (updatedCoordinate) {
6359
- setLatitudeInput(String(updatedCoordinate.lat));
6360
- setLongitudeInput(String(updatedCoordinate.lng));
6361
- setPendingCoordinate(updatedCoordinate);
6362
- setMapCenterPosition([updatedCoordinate.lat, updatedCoordinate.lng]);
6363
- }
6364
- else {
6365
- setLatitudeInput('');
6366
- setLongitudeInput('');
6367
- setPendingCoordinate(null);
6368
- setMapCenterPosition(DEFAULT_CENTER);
6369
- }
6370
- }, [value]);
6371
- const currentCoordinate = React__default.useMemo(() => {
6372
- const lat = Number(latitudeInput);
6373
- const lng = Number(longitudeInput);
6374
- return normalizeCoordinate(lat, lng);
6375
- }, [latitudeInput, longitudeInput]);
6376
- const applyCoordinateChange = React__default.useCallback((coordinate) => {
6377
- if (!coordinate) {
6378
- setLatitudeInput('');
6379
- setLongitudeInput('');
6380
- setValidationMessage(null);
6381
- onChange(null);
6382
- return;
6383
- }
6384
- const normalized = normalizeCoordinate(coordinate.lat, coordinate.lng);
6385
- if (!normalized) {
6386
- setValidationMessage('Please enter a valid coordinate within the allowed range.');
6387
- onChange(null);
6388
- return;
6389
- }
6390
- setLatitudeInput(String(normalized.lat));
6391
- setLongitudeInput(String(normalized.lng));
6392
- setValidationMessage(null);
6393
- const formattedValue = formatCoordinate(normalized);
6394
- onChange(formattedValue);
6395
- }, [onChange]);
6396
- const handleLatitudeChange = (event) => {
6397
- const rawValue = event.value;
6398
- setLatitudeInput(rawValue);
6399
- const numericLatitude = Number(rawValue);
6400
- if (rawValue !== '' &&
6401
- (Number.isNaN(numericLatitude) ||
6402
- numericLatitude < -90 ||
6403
- numericLatitude > 90)) {
6404
- setValidationMessage('Latitude must be between -90 and 90.');
6405
- return;
6406
- }
6407
- if (rawValue === '' || longitudeInput === '') {
6408
- applyCoordinateChange(null);
6409
- return;
6410
- }
6411
- const numericLongitude = Number(longitudeInput);
6412
- if (Number.isNaN(numericLongitude) ||
6413
- numericLongitude < -180 ||
6414
- numericLongitude > 180) {
6415
- setValidationMessage('Longitude must be between -180 and 180.');
6416
- return;
6417
- }
6418
- const updatedCoordinate = {
6419
- lat: numericLatitude,
6420
- lng: numericLongitude,
6421
- };
6422
- setPendingCoordinate(updatedCoordinate);
6423
- applyCoordinateChange(updatedCoordinate);
6424
- };
6425
- const handleLongitudeChange = (event) => {
6426
- const rawValue = event.value;
6427
- setLongitudeInput(rawValue);
6428
- const numericLongitude = Number(rawValue);
6429
- if (rawValue !== '' &&
6430
- (Number.isNaN(numericLongitude) ||
6431
- numericLongitude < -180 ||
6432
- numericLongitude > 180)) {
6433
- setValidationMessage('Longitude must be between -180 and 180.');
6434
- return;
6435
- }
6436
- if (latitudeInput === '' || rawValue === '') {
6437
- applyCoordinateChange(null);
6438
- return;
6439
- }
6440
- const numericLatitude = Number(latitudeInput);
6441
- if (Number.isNaN(numericLatitude) ||
6442
- numericLatitude < -90 ||
6443
- numericLatitude > 90) {
6444
- setValidationMessage('Latitude must be between -90 and 90.');
6445
- return;
6446
- }
6447
- const updatedCoordinate = {
6448
- lat: numericLatitude,
6449
- lng: numericLongitude,
6450
- };
6451
- setPendingCoordinate(updatedCoordinate);
6452
- applyCoordinateChange(updatedCoordinate);
6453
- };
6454
- const handleOpenMapDialog = () => {
6455
- if (disabled)
6456
- return;
6457
- const baseCoordinate = currentCoordinate ?? pendingCoordinate ?? null;
6458
- if (baseCoordinate) {
6459
- setPendingCoordinate(baseCoordinate);
6460
- setMapCenterPosition([baseCoordinate.lat, baseCoordinate.lng]);
6461
- }
6462
- else {
6463
- setMapCenterPosition(DEFAULT_CENTER);
6464
- }
6465
- setIsMapDialogOpen(true);
6466
- if (!baseCoordinate && navigator.geolocation) {
6467
- navigator.geolocation.getCurrentPosition((position) => {
6468
- const coordinate = normalizeCoordinate(position.coords.latitude, position.coords.longitude);
6469
- if (coordinate) {
6470
- setPendingCoordinate(coordinate);
6471
- setMapCenterPosition([coordinate.lat, coordinate.lng]);
6472
- }
6473
- else {
6474
- setMapCenterPosition(DEFAULT_CENTER);
6475
- }
6476
- }, () => {
6477
- setValidationMessage((previous) => previous ??
6478
- 'We could not detect your location. Please move the map and click on the correct place.');
6479
- });
7465
+ const handleCollapse = ({ path }) => {
7466
+ const pathIndex = expanded?.indexOf(path);
7467
+ if (pathIndex && pathIndex !== -1 && expanded) {
7468
+ const updatedExpanded = pathIndex === 0
7469
+ ? expanded.slice(1)
7470
+ : [...expanded.slice(0, pathIndex), ...expanded.slice(pathIndex + 1)];
7471
+ setExpanded(updatedExpanded);
6480
7472
  }
6481
7473
  };
6482
- const handleCloseMapDialog = () => {
6483
- setIsMapDialogOpen(false);
7474
+ const handleOrgUnitSearch = async (query) => {
7475
+ setSearchLoading(true);
7476
+ try {
7477
+ 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`);
7478
+ setSearchData((searchResponse.data || {})['organisationUnits']);
7479
+ setSearchLoading(false);
7480
+ }
7481
+ catch (e) {
7482
+ setSearchLoading(false);
7483
+ }
6484
7484
  };
6485
- const handleMapClick = (coordinate) => {
6486
- const normalized = normalizeCoordinate(coordinate.lat, coordinate.lng);
6487
- if (!normalized)
6488
- return;
6489
- setPendingCoordinate(normalized);
6490
- setMapCenterPosition([normalized.lat, normalized.lng]);
7485
+ const debouncedSearch = useCallback(debounce((value) => {
7486
+ handleOrgUnitSearch(value);
7487
+ }, 500), []);
7488
+ const handleFilterChange = (event) => {
7489
+ setSearchText(event.value);
7490
+ debouncedSearch(event.value);
6491
7491
  };
6492
- const handleConfirmFromMap = () => {
6493
- if (!pendingCoordinate)
6494
- return;
6495
- applyCoordinateChange(pendingCoordinate);
6496
- setIsMapDialogOpen(false);
7492
+ const ready = useMemo(() => {
7493
+ return searchText?.length ? !searchLoading : !loading;
7494
+ }, [searchText, searchLoading, loading]);
7495
+ const renderOrgUnitTree = () => {
7496
+ if (searchText && searchText?.length > 0) {
7497
+ if (searchLoading) {
7498
+ return (React__default.createElement("div", { className: classes.orgUnitTreeLoader },
7499
+ React__default.createElement(CircularLoader$1, { small: true })));
7500
+ }
7501
+ 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) => {
7502
+ setSelectedOrgUnit(event);
7503
+ setShowOrgUnitTree(false);
7504
+ onSelectOrgUnit(event.id);
7505
+ } })));
7506
+ }
7507
+ return (rootOrgUnits.length > 0 && (React__default.createElement(OrganisationUnitTree, { key: key, roots: rootOrgUnits?.map((orgUnit) => orgUnit.id) || [], singleSelection: true, expanded: expanded, handleExpand: handleExpand, handleCollapse: handleCollapse, selected: highlighted, onChange: (event) => {
7508
+ setSelectedOrgUnit(event);
7509
+ setShowOrgUnitTree(false);
7510
+ onSelectOrgUnit(event.id);
7511
+ } })));
6497
7512
  };
6498
- const combinedErrorMessage = validationMessage || (error ? validationText : null);
6499
- const markerCoordinate = pendingCoordinate || currentCoordinate || null;
6500
- const selectedLocationText = markerCoordinate
6501
- ? `Selected location: Lat ${markerCoordinate.lat.toFixed(5)}, Lon ${markerCoordinate.lng.toFixed(5)}`
6502
- : 'No location selected yet. Click on the street map to drop a marker.';
6503
- return (React__default.createElement(React__default.Fragment, null,
6504
- React__default.createElement(Field, { label: label, name: name, required: required, error: Boolean(combinedErrorMessage), validationText: combinedErrorMessage ?? undefined },
6505
- React__default.createElement("div", { style: {
6506
- display: 'grid',
6507
- gridTemplateColumns: 'minmax(0, 1.2fr) minmax(0, 1fr) minmax(0, 1fr)',
6508
- gap: 8,
6509
- alignItems: 'flex-end',
6510
- } },
6511
- React__default.createElement("div", { style: { display: 'flex', flexDirection: 'column', gap: 4 } },
6512
- React__default.createElement(Button$1, { name: `${name}-open-map`, disabled: disabled, onClick: handleOpenMapDialog, secondary: true }, currentCoordinate
6513
- ? 'Update location on map'
6514
- : 'Pick location on map')),
6515
- React__default.createElement(InputField$1, { label: "Latitude (\u00B0)", name: `${name}-lat`, type: "number", step: "0.000001", disabled: disabled, value: latitudeInput, onChange: handleLatitudeChange, onBlur: onBlur, placeholder: "-6.814527" }),
6516
- React__default.createElement(InputField$1, { label: "Longitude (\u00B0)", name: `${name}-lng`, type: "number", step: "0.000001", disabled: disabled, value: longitudeInput, onChange: handleLongitudeChange, onBlur: onBlur, placeholder: "39.279557" }))),
6517
- isMapDialogOpen && (React__default.createElement(Modal$1, { onClose: handleCloseMapDialog, position: "middle", className: "coordinate-modal" },
6518
- React__default.createElement(ModalTitle$1, null, "Select location on street map"),
6519
- React__default.createElement(ModalContent$1, null,
6520
- React__default.createElement("div", { style: {
6521
- width: '80vw',
6522
- height: '70vh',
6523
- maxWidth: '100%',
6524
- maxHeight: '80vh',
6525
- } },
6526
- React__default.createElement(CoordinateMapContainer, { center: mapCenterPosition, zoom: markerCoordinate ? 12 : DEFAULT_ZOOM, style: { width: '100%', height: '100%', borderRadius: 8 }, scrollWheelZoom: !disabled },
6527
- React__default.createElement(TileLayer, { attribution: "\u00A9 OpenStreetMap contributors", url: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" }),
6528
- React__default.createElement(RecenterOnCoordinate, { coordinate: markerCoordinate }),
6529
- markerCoordinate && (React__default.createElement(Marker, { position: [markerCoordinate.lat, markerCoordinate.lng] })),
6530
- React__default.createElement(MapClickListener, { disabled: disabled, onCoordinateSelected: handleMapClick }))),
6531
- React__default.createElement("p", { style: { marginTop: 8, fontSize: 13 } }, selectedLocationText),
6532
- React__default.createElement(Help, null, "Use the street map to find the correct facility, building or area. Pan (drag), zoom in/out, then click once to place or move the marker. Click Use Selected Location to save the coordinates.")),
6533
- React__default.createElement(ModalActions$1, null,
6534
- React__default.createElement("div", { style: { display: 'flex', gap: 12 } },
6535
- React__default.createElement(Button$1, { onClick: handleCloseMapDialog, secondary: true }, "Cancel"),
6536
- React__default.createElement(Button$1, { primary: true, onClick: handleConfirmFromMap, disabled: !pendingCoordinate }, "Use Selected Location")))))));
7513
+ return (config && (React__default.createElement(Provider, { config: config, plugin: false, parentAlertsAdd: undefined, showAlertsInPlugin: false },
7514
+ React__default.createElement("div", null,
7515
+ label && (React__default.createElement("div", { className: classes.orgUnitFieldLabel },
7516
+ React__default.createElement("span", null, label),
7517
+ required ? (React__default.createElement("span", { className: classes.orgUnitFieldRequiredLabel }, "*")) : (React__default.createElement(React__default.Fragment, null)))),
7518
+ !showOrgUnitTree ? (selectedOrgUnit ? (React__default.createElement(React__default.Fragment, null,
7519
+ React__default.createElement(Tooltip, { content: selectedOrgUnitLabel }, disabled ? (React__default.createElement(Chip, null, selectedOrgUnit.displayName)) : (React__default.createElement(Chip, { onRemove: () => {
7520
+ // setShowOrgUnitTree(true);
7521
+ // Clear internal state
7522
+ setSelectedOrgUnit(undefined);
7523
+ setSearchText(undefined);
7524
+ setSearchData(undefined);
7525
+ setSearchLoading(false);
7526
+ setExpanded(initiallyExpanded);
7527
+ // Emit cleared value
7528
+ onSelectOrgUnit('');
7529
+ // Show required warning if applicable
7530
+ if (required) {
7531
+ setShowRequiredNotice(true);
7532
+ }
7533
+ setShowOrgUnitTree(true);
7534
+ } }, selectedOrgUnit.displayName))))) : (React__default.createElement("div", { className: classes.orgUnitTreeLoader },
7535
+ React__default.createElement(CircularLoader$1, { small: true })))) : (React__default.createElement("div", { className: classes.container },
7536
+ React__default.createElement("div", { className: classes.debounceFieldContainer },
7537
+ React__default.createElement(InputField$1, { placeholder: "Search", value: searchText, disabled: disabled, onChange: handleFilterChange })),
7538
+ loading ? (React__default.createElement("div", { className: classes.orgUnitTreeLoader },
7539
+ React__default.createElement(CircularLoader$1, { small: true }))) : (React__default.createElement("div", { className: classes.orgUnitTreeContainer, style: { maxHeight: '200px', overflowY: 'auto' } }, renderOrgUnitTree())),
7540
+ showRequiredNotice && required && (React__default.createElement("div", { style: { margin: '8px' } },
7541
+ React__default.createElement(NoticeBox, { error: true }, "This field is required. Please select an organisation unit.")))))))));
6537
7542
  };
6538
7543
 
6539
- const ALL_COUNTRIES = [
6540
- // East Africa first (for convenience)
6541
- { isoCode: 'TZ', dialCode: '+255', name: 'Tanzania', flag: '🇹🇿' },
6542
- { isoCode: 'KE', dialCode: '+254', name: 'Kenya', flag: '🇰🇪' },
6543
- { isoCode: 'UG', dialCode: '+256', name: 'Uganda', flag: '🇺🇬' },
6544
- { isoCode: 'RW', dialCode: '+250', name: 'Rwanda', flag: '🇷🇼' },
6545
- { isoCode: 'BI', dialCode: '+257', name: 'Burundi', flag: '🇧🇮' },
6546
- { isoCode: 'SS', dialCode: '+211', name: 'South Sudan', flag: '🇸🇸' },
6547
- { isoCode: 'ET', dialCode: '+251', name: 'Ethiopia', flag: '🇪🇹' },
6548
- // A few examples from other regions:
6549
- { isoCode: 'GB', dialCode: '+44', name: 'United Kingdom', flag: '🇬🇧' },
6550
- { isoCode: 'US', dialCode: '+1', name: 'United States', flag: '🇺🇸' },
6551
- { isoCode: 'CA', dialCode: '+1', name: 'Canada', flag: '🇨🇦' },
6552
- { isoCode: 'DE', dialCode: '+49', name: 'Germany', flag: '🇩🇪' },
6553
- { isoCode: 'IN', dialCode: '+91', name: 'India', flag: '🇮🇳' },
6554
- { isoCode: 'CN', dialCode: '+86', name: 'China', flag: '🇨🇳' },
6555
- { isoCode: 'BR', dialCode: '+55', name: 'Brazil', flag: '🇧🇷' },
6556
- // 👉 Here you add the rest of the world.
6557
- // You can load a standard JSON of all countries (isoCode, dialCode, name, flag)
6558
- // and generate this array at build time if you prefer.
6559
- ];
6560
-
6561
- /* eslint-disable @typescript-eslint/no-non-null-assertion */
6562
- const DEFAULT_COUNTRY_ISO = 'TZ';
6563
- const FilterableSingleSelectField = SingleSelectField;
6564
- function normalizeTanzaniaLocal(raw) {
6565
- const digits = (raw || '').replace(/\D/g, '');
6566
- if (!digits)
6567
- return '';
6568
- if (digits.startsWith('255')) {
6569
- let sub = digits.slice(3);
6570
- if (sub.startsWith('0'))
6571
- sub = sub.slice(1);
6572
- return ('0' + sub).slice(0, 10);
6573
- }
6574
- if (digits.startsWith('0')) {
6575
- return digits.slice(0, 10);
6576
- }
6577
- if (/^[67]\d{7,9}$/.test(digits)) {
6578
- return ('0' + digits).slice(0, 10);
6579
- }
6580
- if (digits.length >= 9 && !digits.startsWith('0')) {
6581
- return ('0' + digits.slice(0, 9)).slice(0, 10);
7544
+ // Copyright 2024 UDSM DHIS2 Lab. All rights reserved.
7545
+ // Use of this source code is governed by a BSD-style
7546
+ // license that can be found in the LICENSE file.
7547
+ class FieldConfig {
7548
+ constructor(config) {
7549
+ this.hideLabel = config?.hideLabel ?? false;
7550
+ this.inputWidth = config?.inputWidth || '100%';
6582
7551
  }
6583
- return digits.slice(0, 10);
6584
7552
  }
6585
- const InternationalPhoneField = ({ name, label, placeholder, value, required, disabled, error, validationText, inputWidth, defaultCountryIsoCode = DEFAULT_COUNTRY_ISO, onChange, onBlur, }) => {
6586
- const [selectedIsoCode, setSelectedIsoCode] = React__default.useState(defaultCountryIsoCode);
6587
- const [filterText, setFilterText] = React__default.useState('');
6588
- const [leadingZeroWarning, setLeadingZeroWarning] = React__default.useState(null);
6589
- const selectedCountry = ALL_COUNTRIES.find((c) => c.isoCode === selectedIsoCode) ??
6590
- ALL_COUNTRIES.find((c) => c.isoCode === DEFAULT_COUNTRY_ISO);
6591
- const [localNumber, setLocalNumber] = React__default.useState('');
6592
- React__default.useEffect(() => {
6593
- const raw = value ?? '';
6594
- if (selectedCountry.isoCode === 'TZ') {
6595
- const normalizedStored = normalizeTanzaniaLocal(raw);
6596
- if (!normalizedStored) {
6597
- setLocalNumber('');
6598
- return;
6599
- }
6600
- const digits = normalizedStored.replace(/\D/g, '');
6601
- const ui = digits.startsWith('0') ? digits.slice(1) : digits;
6602
- setLocalNumber(ui);
6603
- }
6604
- else {
6605
- const digits = raw.replace(/\D/g, '').slice(0, 15);
6606
- setLocalNumber(digits);
7553
+
7554
+ // field-cascade.types.ts
7555
+ /**
7556
+ * Cascade types for form fields.
7557
+ *
7558
+ * Supports configuration-driven "cascading" behaviors such as:
7559
+ * - Filtering dropdown options based on the selected value of another field
7560
+ * (e.g., path codes like "/Zanzibar/Unguja/...").
7561
+ *
7562
+ * This file intentionally contains:
7563
+ * - enums
7564
+ * - interfaces / types
7565
+ * - defaults
7566
+ *
7567
+ * Runtime logic belongs in: field-cascade.util.ts
7568
+ */
7569
+ /** Discriminator for all cascade configuration kinds */
7570
+ var CascadeKind;
7571
+ (function (CascadeKind) {
7572
+ CascadeKind["OPTIONS_PATH"] = "OPTIONS_PATH";
7573
+ // Future:
7574
+ // ORG_UNIT_PATH = 'ORG_UNIT_PATH',
7575
+ // OPTIONS_MAPPING = 'OPTIONS_MAPPING',
7576
+ })(CascadeKind || (CascadeKind = {}));
7577
+ /**
7578
+ * Strategy used to match the parent value against child option "path".
7579
+ *
7580
+ * Notes:
7581
+ * - PREFIX: true "under this parent path" match. Best when parent value is a full path prefix.
7582
+ * - LEAF_TOKEN: token-safe "includes" match (recommended for DHIS2-ish paths). Matches:
7583
+ * child endsWith("/<leaf>") OR child contains("/<leaf>/")
7584
+ * - CONTAINS: raw substring match anywhere (least strict; can produce false positives).
7585
+ * - EXACT: exact path match.
7586
+ */
7587
+ var ParentMatchMode;
7588
+ (function (ParentMatchMode) {
7589
+ ParentMatchMode["PREFIX"] = "PREFIX";
7590
+ ParentMatchMode["LEAF_TOKEN"] = "LEAF_TOKEN";
7591
+ ParentMatchMode["CONTAINS"] = "CONTAINS";
7592
+ ParentMatchMode["EXACT"] = "EXACT";
7593
+ })(ParentMatchMode || (ParentMatchMode = {}));
7594
+ /** Where to read the child option path from */
7595
+ var OptionPathField;
7596
+ (function (OptionPathField) {
7597
+ OptionPathField["CODE"] = "code";
7598
+ OptionPathField["ID"] = "id";
7599
+ OptionPathField["VALUE"] = "value";
7600
+ })(OptionPathField || (OptionPathField = {}));
7601
+ /** What is stored in the parent field control value */
7602
+ var ParentValueType;
7603
+ (function (ParentValueType) {
7604
+ ParentValueType["CODE"] = "CODE";
7605
+ ParentValueType["ID"] = "ID";
7606
+ })(ParentValueType || (ParentValueType = {}));
7607
+ /**
7608
+ * Centralized defaults for OPTIONS_PATH
7609
+ * (keep defaults here, merge in util).
7610
+ */
7611
+ const DEFAULT_OPTIONS_PATH_CASCADE = {
7612
+ optionPathSeparator: '/',
7613
+ parentMatchMode: ParentMatchMode.LEAF_TOKEN, // ✅ token-safe "includes"
7614
+ childPathField: OptionPathField.CODE,
7615
+ parentValueType: ParentValueType.CODE,
7616
+ disableUntilParentSelected: true,
7617
+ clearOnParentChange: true,
7618
+ allowAllIfParentMissing: false,
7619
+ };
7620
+
7621
+ // field-cascade.util.ts
7622
+ class FieldCascadeUtil {
7623
+ static buildConfigByChildFieldId(configs) {
7624
+ const map = Object.create(null);
7625
+ for (let i = 0; i < (configs?.length ?? 0); i += 1) {
7626
+ const cfg = configs[i];
7627
+ if (!cfg?.fieldId)
7628
+ continue;
7629
+ map[cfg.fieldId] = cfg;
6607
7630
  }
6608
- setLeadingZeroWarning(null);
6609
- }, [value, selectedCountry.isoCode]);
6610
- const filteredCountries = React__default.useMemo(() => {
6611
- const term = filterText.trim().toLowerCase();
6612
- if (!term)
6613
- return ALL_COUNTRIES;
6614
- return ALL_COUNTRIES.filter((c) => {
6615
- const haystack = `${c.name} ${c.dialCode} ${c.isoCode}`.toLowerCase();
6616
- return haystack.includes(term);
6617
- });
6618
- }, [filterText]);
6619
- const handleCountryChange = ({ selected }) => {
6620
- setSelectedIsoCode(selected);
6621
- };
6622
- const handleLocalChange = ({ value }) => {
6623
- const digitsOnly = (value || '').replace(/\D/g, '');
6624
- if (selectedCountry.isoCode === 'TZ') {
6625
- let ui = digitsOnly;
6626
- if (ui.startsWith('0')) {
6627
- setLeadingZeroWarning('For Tanzania, do not start the number with 0. Enter it without the leading 0 (e.g. 767000000).');
6628
- ui = ui.slice(1);
7631
+ return Object.freeze(map);
7632
+ }
7633
+ static normalizePath(raw, separator = '/') {
7634
+ const input = String(raw ?? '').trim();
7635
+ if (!input)
7636
+ return '';
7637
+ if (!input.includes(separator + separator) && !input.endsWith(separator)) {
7638
+ return input;
7639
+ }
7640
+ let out = '';
7641
+ let prevWasSep = false;
7642
+ for (let i = 0; i < input.length; i += 1) {
7643
+ const ch = input[i];
7644
+ const isSep = ch === separator;
7645
+ if (isSep) {
7646
+ if (!prevWasSep)
7647
+ out += ch;
7648
+ prevWasSep = true;
6629
7649
  }
6630
7650
  else {
6631
- setLeadingZeroWarning(null);
7651
+ out += ch;
7652
+ prevWasSep = false;
6632
7653
  }
6633
- ui = ui.slice(0, 9);
6634
- const stored = ui ? '0' + ui : '';
6635
- setLocalNumber(ui);
6636
- onChange(stored);
6637
7654
  }
6638
- else {
6639
- const ui = digitsOnly.slice(0, 15);
6640
- setLocalNumber(ui);
6641
- onChange(ui);
6642
- setLeadingZeroWarning(null);
6643
- }
6644
- };
6645
- const effectiveValidationText = leadingZeroWarning ??
6646
- validationText ??
6647
- 'Enter the phone number without the leading 0 (e.g. 767000000). The country code is already applied, and the system will store it as 0767000000 for Tanzania.';
6648
- const hasError = Boolean(error || leadingZeroWarning);
6649
- const wrapperStyle = {
6650
- maxWidth: typeof inputWidth === 'number' ? inputWidth : inputWidth || 480,
6651
- display: 'flex',
6652
- flexDirection: 'column',
6653
- gap: '0.5rem',
6654
- };
6655
- return (React__default.createElement("div", { style: wrapperStyle },
6656
- label && (React__default.createElement("label", { htmlFor: name, style: {
6657
- fontSize: '0.875rem',
6658
- fontWeight: 500,
6659
- color: '#1f2933',
6660
- } },
6661
- label,
6662
- required ? (React__default.createElement("span", { style: { color: '#e53935', marginLeft: 4 } }, "*")) : null)),
6663
- React__default.createElement("div", { style: {
6664
- display: 'flex',
6665
- width: '100%',
6666
- gap: '0.75rem',
6667
- alignItems: 'stretch',
6668
- } },
6669
- React__default.createElement("div", { style: {
6670
- flex: '0 0 auto',
6671
- width: 260,
6672
- } },
6673
- React__default.createElement(FilterableSingleSelectField, { selected: selectedIsoCode, onChange: handleCountryChange, disabled: disabled, dense: true, filterable: true, onFilterChange: ({ value }) => setFilterText(value), noMatchText: "No matching country" }, filteredCountries.map((country) => (React__default.createElement(SingleSelectOption, { disabled: disabled, key: country.isoCode, value: country.isoCode, label: `${country.flag} ${country.name} (${country.dialCode})` }))))),
6674
- React__default.createElement("div", { style: { flex: '1 1 0', minWidth: 0 } },
6675
- React__default.createElement(InputField$1, { type: "tel", name: name, placeholder: placeholder ?? '767000000', value: localNumber, required: required, disabled: disabled, error: hasError, validationText: effectiveValidationText, autoComplete: "tel", max: selectedCountry.isoCode === 'TZ' ? '9' : '15', onChange: handleLocalChange, onBlur: () => {
6676
- if (selectedCountry.isoCode === 'TZ') {
6677
- const digits = (localNumber || '')
6678
- .replace(/\D/g, '')
6679
- .slice(0, 9);
6680
- const stored = digits ? '0' + digits : '';
6681
- if (digits !== localNumber) {
6682
- setLocalNumber(digits);
6683
- onChange(stored);
6684
- }
6685
- }
6686
- onBlur?.();
6687
- } })))));
6688
- };
7655
+ if (out === separator)
7656
+ return separator;
7657
+ return out.endsWith(separator) ? out.slice(0, -1) : out;
7658
+ }
7659
+ static getPathLeaf(raw, separator = '/') {
7660
+ const normalized = FieldCascadeUtil.normalizePath(raw, separator);
7661
+ if (!normalized)
7662
+ return '';
7663
+ const parts = normalized.split(separator).filter(Boolean);
7664
+ return parts.length ? parts[parts.length - 1] : normalized;
7665
+ }
7666
+ static containsLeafToken(childPath, parentLeaf, separator = '/') {
7667
+ if (!childPath || !parentLeaf)
7668
+ return false;
7669
+ const token = `${separator}${parentLeaf}`;
7670
+ return (childPath.endsWith(token) || childPath.includes(token + separator));
7671
+ }
7672
+ /**
7673
+ * Safe property getter for "unknown object shapes" (keeps TS happy).
7674
+ */
7675
+ static getProp(obj, key) {
7676
+ return obj[key];
7677
+ }
7678
+ /**
7679
+ * Reads the child option path from configured field (code/id) and normalizes it.
7680
+ * Works with any option object type (including interfaces without index signatures).
7681
+ */
7682
+ static getChildOptionPath(option, pathField, separator = '/') {
7683
+ const raw = FieldCascadeUtil.getProp(option, pathField);
7684
+ return FieldCascadeUtil.normalizePath(raw, separator);
7685
+ }
7686
+ static getParentEffectiveValue(merged, parentValue) {
7687
+ const raw = String(parentValue ?? '').trim();
7688
+ if (!raw)
7689
+ return '';
7690
+ if (merged.parentValueType === ParentValueType.ID) {
7691
+ return raw;
7692
+ }
7693
+ return FieldCascadeUtil.normalizePath(raw, merged.optionPathSeparator);
7694
+ }
7695
+ static matchesChildToParent(childPathRaw, parentEffectiveRaw, mode, separator = '/') {
7696
+ const childPath = FieldCascadeUtil.normalizePath(childPathRaw, separator);
7697
+ const parentEffective = FieldCascadeUtil.normalizePath(parentEffectiveRaw, separator);
7698
+ if (!childPath || !parentEffective)
7699
+ return false;
7700
+ switch (mode) {
7701
+ case ParentMatchMode.PREFIX: {
7702
+ // Allow exact node match and boundary-safe prefix
7703
+ if (childPath === parentEffective)
7704
+ return true;
7705
+ const prefix = parentEffective.endsWith(separator)
7706
+ ? parentEffective
7707
+ : parentEffective + separator;
7708
+ return childPath.startsWith(prefix);
7709
+ }
7710
+ default: {
7711
+ const leaf = FieldCascadeUtil.getPathLeaf(parentEffective, separator);
7712
+ return FieldCascadeUtil.containsLeafToken(childPath, leaf, separator);
7713
+ }
7714
+ }
7715
+ }
7716
+ static shouldDisableChildField(cascade, parentValue) {
7717
+ if (!cascade || cascade.kind !== CascadeKind.OPTIONS_PATH)
7718
+ return false;
7719
+ const merged = { ...DEFAULT_OPTIONS_PATH_CASCADE, ...cascade };
7720
+ if (!merged.disableUntilParentSelected)
7721
+ return false;
7722
+ const parentEffective = FieldCascadeUtil.getParentEffectiveValue(merged, parentValue);
7723
+ if (!parentEffective)
7724
+ return true;
7725
+ if (merged.parentValueType === ParentValueType.CODE) {
7726
+ return (FieldCascadeUtil.getPathLeaf(parentEffective, merged.optionPathSeparator)
7727
+ .length === 0);
7728
+ }
7729
+ return false;
7730
+ }
7731
+ static filterChildOptionsByParentPath(childOptions, cascade, parentValue) {
7732
+ if (!cascade || cascade.kind !== CascadeKind.OPTIONS_PATH) {
7733
+ return (childOptions ?? []);
7734
+ }
7735
+ const merged = { ...DEFAULT_OPTIONS_PATH_CASCADE, ...cascade };
7736
+ const parentEffective = FieldCascadeUtil.getParentEffectiveValue(merged, parentValue);
7737
+ if (!parentEffective) {
7738
+ return merged.allowAllIfParentMissing
7739
+ ? (childOptions ?? [])
7740
+ : [];
7741
+ }
7742
+ const out = [];
7743
+ const sep = merged.optionPathSeparator;
7744
+ const mode = merged.parentMatchMode;
7745
+ const pathField = merged.childPathField;
7746
+ for (let i = 0; i < (childOptions?.length ?? 0); i += 1) {
7747
+ const opt = childOptions[i];
7748
+ const childPath = FieldCascadeUtil.getChildOptionPath(opt, pathField, sep);
7749
+ if (!childPath)
7750
+ continue;
7751
+ if (FieldCascadeUtil.matchesChildToParent(childPath, parentEffective, mode, sep)) {
7752
+ out.push(opt);
7753
+ }
7754
+ }
7755
+ return out;
7756
+ }
7757
+ static filterOptionsByCascade(options, config, parentValue) {
7758
+ if (!config || config.kind !== CascadeKind.OPTIONS_PATH) {
7759
+ return [...(options ?? [])];
7760
+ }
7761
+ const merged = { ...DEFAULT_OPTIONS_PATH_CASCADE, ...config };
7762
+ const parentEffective = FieldCascadeUtil.getParentEffectiveValue(merged, parentValue);
7763
+ if (!parentEffective) {
7764
+ return merged.allowAllIfParentMissing ? [...(options ?? [])] : [];
7765
+ }
7766
+ const sep = merged.optionPathSeparator;
7767
+ return (options ?? []).filter((opt) => {
7768
+ const childPath = FieldCascadeUtil.getChildOptionPath((opt ?? {}), merged.childPathField, sep);
7769
+ return (!!childPath &&
7770
+ FieldCascadeUtil.matchesChildToParent(childPath, parentEffective, merged.parentMatchMode, sep));
7771
+ });
7772
+ }
7773
+ }
6689
7774
 
7775
+ // Copyright 2024 UDSM DHIS2 Lab. All rights reserved.
7776
+ // Use of this source code is governed by a BSD-style
7777
+ // license that can be found in the LICENSE file.
7778
+ // import {
7779
+ // computed,
7780
+ // Directive,
7781
+ // EventEmitter,
7782
+ // inject,
7783
+ // input,
7784
+ // model,
7785
+ // NgZone,
7786
+ // Output,
7787
+ // Signal,
7788
+ // } from '@angular/core';
7789
+ // import { toObservable } from '@angular/core/rxjs-interop';
7790
+ // import { FormGroup } from '@angular/forms';
7791
+ // import {
7792
+ // Checkbox,
7793
+ // CircularLoader,
7794
+ // colors,
7795
+ // InputField,
7796
+ // MultiSelectField,
7797
+ // MultiSelectOption,
7798
+ // SingleSelectField,
7799
+ // SingleSelectOption,
7800
+ // TextAreaField,
7801
+ // Transfer,
7802
+ // } from '@dhis2/ui';
7803
+ // import {
7804
+ // D2Window,
7805
+ // DataFilterCondition,
7806
+ // DataQueryFilter,
7807
+ // DHIS2Event,
7808
+ // TrackedEntityInstance,
7809
+ // } from '@iapps/d2-web-sdk';
7810
+ // import React, { useEffect, useMemo, useState } from 'react';
7811
+ // import * as ReactDOM from 'react-dom/client';
7812
+ // import { filter, take } from 'rxjs';
7813
+ // import { ReactWrapperModule } from '../../react-wrapper/react-wrapper.component';
7814
+ // import { useFieldValidation } from '../hooks';
7815
+ // // import { IFormField } from '../interfaces';
7816
+ // // import { FieldConfig } from '../models';
7817
+ // import { FileUploadField } from './file-upload-field.component';
7818
+ // import { OrgUnitFormField } from './org-unit-form-field.component';
7819
+ // import { CustomOrgUnitConfig } from '../models/org-unit.model';
7820
+ // import { IFormField } from '../interfaces/form-field.interface';
7821
+ // import { FieldConfig } from '../models/field-config.model';
7822
+ // import { CoordinatePickerField } from './coordinate-field-component';
7823
+ // import { NoticeBox } from '@dhis2/ui';
7824
+ // import { InternationalPhoneField } from './phone-number-field.component';
7825
+ // import {
7826
+ // DEFAULT_OPTIONS_PATH_CASCADE,
7827
+ // OptionsPathCascadeConfig,
7828
+ // OptionsPathCascadeConfigMap,
7829
+ // } from '../types/field-cascade.types';
7830
+ // import { FieldCascadeUtil } from '../utils/field-cascade.util';
7831
+ // @Directive()
7832
+ // export class BaseFormFieldComponent extends ReactWrapperModule {
7833
+ // ngZone = inject(NgZone);
7834
+ // fieldType = 'textbox';
7835
+ // field = input.required<IFormField<string>>();
7836
+ // fieldError = input<string | undefined>();
7837
+ // fieldConfig = input<FieldConfig>(new FieldConfig());
7838
+ // form = model.required<FormGroup>();
7839
+ // isValid = input<boolean>();
7840
+ // isValueAssigned = input<boolean>();
7841
+ // dataId = input<string>();
7842
+ // customOrgUnitRoots = input<CustomOrgUnitConfig[]>();
7843
+ // optionCascadeConfigs = input<OptionsPathCascadeConfig[]>();
7844
+ // optionCascadeConfigMap = input<OptionsPathCascadeConfigMap>(
7845
+ // {} as OptionsPathCascadeConfigMap
7846
+ // );
7847
+ // //TODO: FIND BETTER WAY TO PASS PROGRAM TO FIELDS i.e field extensions
7848
+ // program = input<string>();
7849
+ // value = model<string>();
7850
+ // protected value$ = toObservable(this.value);
7851
+ // protected isValueAssigned$ = toObservable(this.isValueAssigned);
7852
+ // protected fieldError$ = toObservable(this.fieldError);
7853
+ // label: Signal<string | undefined> = computed(() => {
7854
+ // return !this.fieldConfig()?.hideLabel ? this.field().label : undefined;
7855
+ // });
7856
+ // placeholder: Signal<string> = computed(() => {
7857
+ // return (
7858
+ // this.field()?.placeholder || `Enter ${this.field()?.label || 'value'}`
7859
+ // );
7860
+ // });
7861
+ // InputField = this.#getInputField();
7862
+ // @Output() update = new EventEmitter<{ form: FormGroup; value: any }>();
7863
+ // @Output() immediateUpdate = new EventEmitter<{
7864
+ // form: FormGroup;
7865
+ // value: any;
7866
+ // }>();
7867
+ // override async ngAfterViewInit() {
7868
+ // if (!this.elementRef) throw new Error('No element ref');
7869
+ // this.reactDomRoot = ReactDOM.createRoot(this.elementRef.nativeElement);
7870
+ // this.component = this.InputField;
7871
+ // this.render();
7872
+ // }
7873
+ // #getInputField() {
7874
+ // return (): React.JSX.Element => {
7875
+ // const [value, setValue] = useState(
7876
+ // this.form().get(this.field().id)?.value ||
7877
+ // this.form().get(this.field().key)?.value
7878
+ // );
7879
+ // const [selected, setSelected] = useState();
7880
+ // const [touched, setTouched] = useState(false);
7881
+ // const [disabled, setDisabled] = useState<boolean>(
7882
+ // this.field()?.disabled ?? this.field()?.generated ?? false
7883
+ // );
7884
+ // const [initialError, setInitialError] = useState<string>();
7885
+ // const [recordExistError, setRecordExistError] = useState<
7886
+ // string | undefined
7887
+ // >();
7888
+ // const [checkingUniqueness, setCheckingUniqueness] = useState<boolean>();
7889
+ // useEffect(() => {
7890
+ // const isAssignedSubscription = this.isValueAssigned$
7891
+ // .pipe(filter((isValueAssigned) => isValueAssigned === true))
7892
+ // .subscribe({
7893
+ // next: () => {
7894
+ // const value =
7895
+ // this.form().get(this.field().id)?.value ||
7896
+ // this.form().get(this.field().key)?.value;
7897
+ // setValue(value);
7898
+ // setDisabled(true);
7899
+ // checkValueUniqueness();
7900
+ // },
7901
+ // });
7902
+ // return () => {
7903
+ // isAssignedSubscription.unsubscribe();
7904
+ // };
7905
+ // }, []);
7906
+ // // TODO: Review error handling as take() has potential to missed any other updated error information
7907
+ // useEffect(() => {
7908
+ // const fieldErrorSubscription = this.fieldError$
7909
+ // .pipe(
7910
+ // filter((error) => error !== initialError),
7911
+ // take(1)
7912
+ // )
7913
+ // .subscribe({
7914
+ // next: (error: string | undefined) => {
7915
+ // setInitialError(error);
7916
+ // },
7917
+ // });
7918
+ // return () => {
7919
+ // fieldErrorSubscription.unsubscribe();
7920
+ // };
7921
+ // }, [initialError]); // Add initialError as a dependency to avoid stale closures
7922
+ // const arrayValue = useMemo(() => {
7923
+ // if (value && value.length > 0) {
7924
+ // return value.split(',');
7925
+ // }
7926
+ // return [];
7927
+ // }, [value]);
7928
+ // const inputWidth = useMemo(() => {
7929
+ // if (
7930
+ // this.field().controlType === 'date' ||
7931
+ // this.field().controlType === 'date-time'
7932
+ // ) {
7933
+ // return '360px';
7934
+ // }
7935
+ // return this.fieldConfig()?.inputWidth;
7936
+ // }, []);
7937
+ // const { validationError, hasError } = useFieldValidation({
7938
+ // field: this.field(),
7939
+ // form: this.form(),
7940
+ // initialError,
7941
+ // recordExistError,
7942
+ // value,
7943
+ // touched,
7944
+ // });
7945
+ // const onValueChange = (value: unknown) => {
7946
+ // this.ngZone.run(() => {
7947
+ // (
7948
+ // this.form().get(this.field().id) ||
7949
+ // this.form().get(this.field().key)
7950
+ // )?.setValue(value);
7951
+ // this.update.emit({
7952
+ // form: this.form(),
7953
+ // value,
7954
+ // });
7955
+ // });
7956
+ // setValue(value);
7957
+ // setTouched(true);
7958
+ // };
7959
+ // const generateUUID = (): string => {
7960
+ // return (
7961
+ // globalThis.crypto?.randomUUID?.() ??
7962
+ // 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
7963
+ // const r = (Math.random() * 16) | 0;
7964
+ // const v = c === 'x' ? r : (r & 0x3) | 0x8;
7965
+ // return v.toString(16);
7966
+ // })
7967
+ // );
7968
+ // };
7969
+ // const checkValueUniqueness = async () => {
7970
+ // if (
7971
+ // this.field().unique ||
7972
+ // ((this.field().extension?.isDataElementUnique ?? false) &&
7973
+ // value &&
7974
+ // value.length > 0 &&
7975
+ // touched)
7976
+ // ) {
7977
+ // setCheckingUniqueness(true);
7978
+ // setRecordExistError(undefined);
7979
+ // try {
7980
+ // const isDuplicate = await this.searchForDuplicates(value);
7981
+ // setCheckingUniqueness(false);
7982
+ // if (isDuplicate) {
7983
+ // const customError = `Record with this ${this.label()} is already registered`;
7984
+ // (
7985
+ // this.form().controls[this.field().id] ||
7986
+ // this.form().controls[this.field().key]
7987
+ // )?.setErrors({
7988
+ // customError,
7989
+ // });
7990
+ // setRecordExistError(customError);
7991
+ // }
7992
+ // } catch (e) {
7993
+ // setCheckingUniqueness(false);
7994
+ // setRecordExistError(undefined);
7995
+ // }
7996
+ // }
7997
+ // };
7998
+ // const formFieldContent = () => {
7999
+ // switch (this.field().controlType) {
8000
+ // case 'number':
8001
+ // return (
8002
+ // <InputField
8003
+ // error={hasError}
8004
+ // validationText={validationError}
8005
+ // type={this.field().type as any}
8006
+ // inputWidth={inputWidth}
8007
+ // required={this.field().required}
8008
+ // name={this.field().id}
8009
+ // label={this.label()}
8010
+ // min={this.field().min?.toString()}
8011
+ // max={this.field().max?.toString()}
8012
+ // placeholder={this.placeholder()}
8013
+ // value={value}
8014
+ // readOnly={disabled}
8015
+ // onChange={(event: any) => {
8016
+ // onValueChange(event.value);
8017
+ // }}
8018
+ // onBlur={() => {
8019
+ // checkValueUniqueness();
8020
+ // }}
8021
+ // />
8022
+ // );
8023
+ // case 'tel':
8024
+ // return (
8025
+ // <InternationalPhoneField
8026
+ // name={this.field().id}
8027
+ // label={this.label()}
8028
+ // placeholder={this.placeholder()}
8029
+ // value={value ?? ''}
8030
+ // required={this.field().required}
8031
+ // disabled={disabled}
8032
+ // error={hasError}
8033
+ // validationText={validationError}
8034
+ // inputWidth={this.fieldConfig()?.inputWidth}
8035
+ // defaultCountryIsoCode="TZ"
8036
+ // onChange={(localNumber: string) => {
8037
+ // onValueChange(localNumber);
8038
+ // }}
8039
+ // onBlur={() => {
8040
+ // checkValueUniqueness();
8041
+ // }}
8042
+ // />
8043
+ // );
8044
+ // case 'coordinate':
8045
+ // return (
8046
+ // <div
8047
+ // style={{ display: 'flex', flexDirection: 'column', gap: 12 }}
8048
+ // >
8049
+ // <NoticeBox title="Location capture required">
8050
+ // <p style={{ margin: 0 }}>
8051
+ // This field requires selecting the exact geographic location
8052
+ // on the map.
8053
+ // </p>
8054
+ // <ul
8055
+ // style={{ margin: '6px 0 0 18px', padding: 0, fontSize: 13 }}
8056
+ // >
8057
+ // <li>
8058
+ // Click <strong>“Pick location on map”</strong> to open the
8059
+ // street map.
8060
+ // </li>
8061
+ // <li>
8062
+ // Pan and zoom until you locate the correct facility,
8063
+ // building, house or area.
8064
+ // </li>
8065
+ // <li>
8066
+ // Click once on the map to place or move the marker
8067
+ // accurately.
8068
+ // </li>
8069
+ // <li>
8070
+ // Click <strong>“Use Selected Location”</strong> to save the
8071
+ // coordinates.
8072
+ // </li>
8073
+ // </ul>
8074
+ // </NoticeBox>
8075
+ // <CoordinatePickerField
8076
+ // error={hasError}
8077
+ // validationText={validationError}
8078
+ // required={this.field().required}
8079
+ // name={this.field().id}
8080
+ // disabled={disabled}
8081
+ // label={this.label()}
8082
+ // value={value}
8083
+ // onChange={(newValue: string | null) => {
8084
+ // onValueChange(newValue);
8085
+ // }}
8086
+ // onBlur={() => {
8087
+ // checkValueUniqueness();
8088
+ // }}
8089
+ // />
8090
+ // </div>
8091
+ // );
8092
+ // case 'textarea':
8093
+ // return (
8094
+ // <TextAreaField
8095
+ // error={hasError}
8096
+ // validationText={validationError}
8097
+ // inputWidth={this.fieldConfig()?.inputWidth}
8098
+ // required={this.field().required}
8099
+ // name={this.field().id}
8100
+ // disabled={disabled}
8101
+ // label={this.label()}
8102
+ // rows={5}
8103
+ // placeholder={this.placeholder()}
8104
+ // value={value}
8105
+ // onChange={(event: any) => {
8106
+ // onValueChange(event.value);
8107
+ // }}
8108
+ // onBlur={() => {
8109
+ // checkValueUniqueness();
8110
+ // }}
8111
+ // />
8112
+ // );
8113
+ // case 'org-unit': {
8114
+ // return (
8115
+ // <OrgUnitFormField
8116
+ // label={this.label()}
8117
+ // key={this.field().id}
8118
+ // field={this.field().id}
8119
+ // required={this.field().required}
8120
+ // disabled={disabled}
8121
+ // customOrgUnitRoots={this.customOrgUnitRoots()}
8122
+ // onSelectOrgUnit={(selectedOrgUnit: string) => {
8123
+ // onValueChange(selectedOrgUnit);
8124
+ // }}
8125
+ // selected={value}
8126
+ // />
8127
+ // );
8128
+ // }
8129
+ // case 'transfer':
8130
+ // return (
8131
+ // <Transfer
8132
+ // filterable
8133
+ // filterPlaceholder="Search"
8134
+ // selected={selected}
8135
+ // leftHeader={
8136
+ // <div
8137
+ // style={{
8138
+ // fontSize: 14,
8139
+ // padding: '8px 4px',
8140
+ // }}
8141
+ // >
8142
+ // {this.field().availableOptionsLabel}
8143
+ // </div>
8144
+ // }
8145
+ // rightHeader={
8146
+ // <div
8147
+ // style={{
8148
+ // fontSize: 14,
8149
+ // padding: '8px 4px',
8150
+ // }}
8151
+ // >
8152
+ // {this.field().selectedOptionsLabel}
8153
+ // </div>
8154
+ // }
8155
+ // options={this.field().options}
8156
+ // onChange={(event: any) => {
8157
+ // onValueChange(event.selected);
8158
+ // }}
8159
+ // />
8160
+ // );
8161
+ // case 'checkbox':
8162
+ // return (
8163
+ // <Checkbox
8164
+ // checked={Boolean(value)}
8165
+ // error={hasError}
8166
+ // label={this.label()}
8167
+ // name={this.field().id}
8168
+ // disabled={disabled}
8169
+ // onChange={(event: any) => {
8170
+ // onValueChange(event.checked);
8171
+ // }}
8172
+ // onBlur={() => {
8173
+ // checkValueUniqueness();
8174
+ // }}
8175
+ // />
8176
+ // );
8177
+ // case 'dropdown':
8178
+ // return (
8179
+ // <SingleSelectField
8180
+ // filterable={(this.field().options || []).length > 5}
8181
+ // clearable
8182
+ // error={hasError}
8183
+ // validationText={validationError}
8184
+ // inputWidth={this.fieldConfig()?.inputWidth}
8185
+ // disabled={disabled}
8186
+ // required={this.field().required}
8187
+ // className="select"
8188
+ // label={this.label()}
8189
+ // selected={value}
8190
+ // onChange={(event: any) => {
8191
+ // onValueChange(event.selected);
8192
+ // }}
8193
+ // onBlur={() => {
8194
+ // checkValueUniqueness();
8195
+ // }}
8196
+ // >
8197
+ // {(this.field().options || []).map((option) => (
8198
+ // <SingleSelectOption
8199
+ // key={generateUUID()}
8200
+ // label={option.label}
8201
+ // value={option.value}
8202
+ // />
8203
+ // ))}
8204
+ // </SingleSelectField>
8205
+ // );
8206
+ // case 'multi-dropdown':
8207
+ // return (
8208
+ // <MultiSelectField
8209
+ // clearText="Clear"
8210
+ // clearable
8211
+ // empty="No data found"
8212
+ // filterable={(this.field().options || []).length > 5}
8213
+ // filterPlaceholder="Type to filter options"
8214
+ // error={hasError}
8215
+ // validationText={validationError}
8216
+ // inputWidth={this.fieldConfig()?.inputWidth}
8217
+ // disabled={disabled}
8218
+ // label={this.label()}
8219
+ // required={this.field().required}
8220
+ // loadingText="Loading options"
8221
+ // noMatchText="No options found"
8222
+ // onChange={(event: { selected: string[] }) => {
8223
+ // const selectedValue = (event.selected || []).join(',');
8224
+ // onValueChange(selectedValue);
8225
+ // }}
8226
+ // onBlur={() => {
8227
+ // checkValueUniqueness();
8228
+ // }}
8229
+ // selected={arrayValue}
8230
+ // >
8231
+ // {(this.field().options || []).map((option) => (
8232
+ // <MultiSelectOption
8233
+ // key={generateUUID()}
8234
+ // label={option.label}
8235
+ // value={option.value}
8236
+ // />
8237
+ // ))}
8238
+ // </MultiSelectField>
8239
+ // );
8240
+ // // case 'date':
8241
+ // // case 'date-time':
8242
+ // // return (
8243
+ // // <InputField
8244
+ // // error={hasError}
8245
+ // // validationText={validationError}
8246
+ // // type={this.field().type as any}
8247
+ // // inputWidth={inputWidth}
8248
+ // // required={this.field().required}
8249
+ // // name={this.field().id}
8250
+ // // label={this.label()}
8251
+ // // min={this.field().min?.toString()}
8252
+ // // max={this.field().max?.toString()}
8253
+ // // placeholder={this.placeholder()}
8254
+ // // value={value}
8255
+ // // readOnly={disabled}
8256
+ // // onChange={(event: any) => {
8257
+ // // onValueChange(event.value);
8258
+ // // }}
8259
+ // // onBlur={() => {
8260
+ // // checkValueUniqueness();
8261
+ // // }}
8262
+ // // />
8263
+ // // );
8264
+ // case 'date':
8265
+ // case 'date-time': {
8266
+ // const field = this.field();
8267
+ // const isDateTimeField = field.type === 'date-time';
8268
+ // const inputType: any = isDateTimeField ? 'datetime-local' : 'date';
8269
+ // // Value coming from DHIS2 store
8270
+ // const htmlValue = this.formatValueForHtmlInputFromDhis(
8271
+ // value,
8272
+ // isDateTimeField
8273
+ // );
8274
+ // const htmlMin = field.min
8275
+ // ? this.formatValueForHtmlInputFromDhis(
8276
+ // String(field.min),
8277
+ // isDateTimeField
8278
+ // )
8279
+ // : undefined;
8280
+ // // Max defined in metadata (if any)
8281
+ // const metadataMax = field.max
8282
+ // ? this.formatValueForHtmlInputFromDhis(
8283
+ // String(field.max),
8284
+ // isDateTimeField
8285
+ // )
8286
+ // : undefined;
8287
+ // // System max = “now” (no future allowed)
8288
+ // const systemMax = this.getNowForHtmlDateInput(isDateTimeField);
8289
+ // // Effective max = earliest of metadataMax and systemMax
8290
+ // const htmlMax = this.pickEarlierDateLimit(metadataMax, systemMax);
8291
+ // return (
8292
+ // <InputField
8293
+ // error={hasError}
8294
+ // validationText={validationError}
8295
+ // type={inputType}
8296
+ // inputWidth={inputWidth}
8297
+ // required={field.required}
8298
+ // name={field.id}
8299
+ // label={this.label()}
8300
+ // min={htmlMin}
8301
+ // max={htmlMax}
8302
+ // placeholder={this.placeholder()}
8303
+ // value={htmlValue}
8304
+ // readOnly={disabled}
8305
+ // onChange={({ value: newValue }: { value: string }) => {
8306
+ // const normalized = this.normalizeDateValueFromHtmlInput(
8307
+ // newValue,
8308
+ // isDateTimeField,
8309
+ // true
8310
+ // );
8311
+ // onValueChange(normalized);
8312
+ // }}
8313
+ // onBlur={() => {
8314
+ // checkValueUniqueness();
8315
+ // }}
8316
+ // />
8317
+ // );
8318
+ // }
8319
+ // case 'file':
8320
+ // return (
8321
+ // <>
8322
+ // <FileUploadField
8323
+ // label={this.label()}
8324
+ // id={this.field().id}
8325
+ // hasError={hasError}
8326
+ // required={this.field().required}
8327
+ // validationText={validationError}
8328
+ // performUpload={true}
8329
+ // uploadUrl={'fileResources'}
8330
+ // onUploadSuccess={(fileId: string) => {
8331
+ // onValueChange(fileId);
8332
+ // }}
8333
+ // onRemoveFile={() => {
8334
+ // onValueChange('');
8335
+ // }}
8336
+ // extension={this.field()?.extension}
8337
+ // value={value}
8338
+ // metaType={this.field().metaType}
8339
+ // dataId={this.dataId()}
8340
+ // program={this.program()}
8341
+ // />
8342
+ // </>
8343
+ // );
8344
+ // default:
8345
+ // return (
8346
+ // <InputField
8347
+ // error={hasError}
8348
+ // validationText={validationError}
8349
+ // type={this.field().type as any}
8350
+ // inputWidth={inputWidth}
8351
+ // required={this.field().required}
8352
+ // name={this.field().id}
8353
+ // label={this.label()}
8354
+ // min={this.field().min?.toString()}
8355
+ // max={this.field().max?.toString()}
8356
+ // placeholder={this.placeholder()}
8357
+ // value={value}
8358
+ // readOnly={disabled}
8359
+ // onChange={(event: any) => {
8360
+ // onValueChange(event.value);
8361
+ // }}
8362
+ // onBlur={() => {
8363
+ // checkValueUniqueness();
8364
+ // }}
8365
+ // />
8366
+ // );
8367
+ // }
8368
+ // };
8369
+ // {
8370
+ // return (
8371
+ // <React.Fragment>
8372
+ // {formFieldContent()}
8373
+ // {checkingUniqueness && (
8374
+ // <div
8375
+ // style={{
8376
+ // display: 'flex',
8377
+ // alignItems: 'center',
8378
+ // gap: 8,
8379
+ // paddingTop: 8,
8380
+ // }}
8381
+ // >
8382
+ // <CircularLoader small />
8383
+ // <div style={{ color: colors.grey800, fontSize: 14 }}>
8384
+ // Checking...
8385
+ // </div>
8386
+ // </div>
8387
+ // )}
8388
+ // </React.Fragment>
8389
+ // );
8390
+ // }
8391
+ // };
8392
+ // }
8393
+ // ✅ DROP-IN REPLACEMENT: BaseFormFieldComponent (only the relevant changed parts)
8394
+ // You can comment your existing #getInputField() implementation and paste this one.
8395
+ //
8396
+ // Notes:
8397
+ // - Implements OPTIONS_PATH cascading using optionCascadeConfigMap (preferred) and falls back to optionCascadeConfigs.
8398
+ // - Filters dropdown + multi-dropdown options using FieldCascadeUtil.
8399
+ // - Disables child until parent selected (if configured).
8400
+ // - Clears child value when parent changes (if configured) ONLY when current value is no longer valid.
8401
+ // - Avoids generateUUID() for option keys (uses stable keys).
8402
+ // - Keeps your existing “generated/disabled/isAssigned” semantics.
6690
8403
  // Copyright 2024 UDSM DHIS2 Lab. All rights reserved.
6691
8404
  // Use of this source code is governed by a BSD-style
6692
8405
  // license that can be found in the LICENSE file.
@@ -6699,21 +8412,30 @@ class BaseFormFieldComponent extends ReactWrapperModule {
6699
8412
  this.fieldError = input(...(ngDevMode ? [undefined, { debugName: "fieldError" }] : []));
6700
8413
  this.fieldConfig = input(new FieldConfig(), ...(ngDevMode ? [{ debugName: "fieldConfig" }] : []));
6701
8414
  this.form = model.required(...(ngDevMode ? [{ debugName: "form" }] : []));
8415
+ // kept for compatibility (even if not used directly here)
6702
8416
  this.isValid = input(...(ngDevMode ? [undefined, { debugName: "isValid" }] : []));
6703
8417
  this.isValueAssigned = input(...(ngDevMode ? [undefined, { debugName: "isValueAssigned" }] : []));
6704
8418
  this.dataId = input(...(ngDevMode ? [undefined, { debugName: "dataId" }] : []));
6705
8419
  this.customOrgUnitRoots = input(...(ngDevMode ? [undefined, { debugName: "customOrgUnitRoots" }] : []));
6706
- //TODO: FIND BETTER WAY TO PASS PROGRAM TO FIELDS i.e field extensions
8420
+ // Cascade
8421
+ this.optionCascadeConfigs = input([], ...(ngDevMode ? [{ debugName: "optionCascadeConfigs" }] : []));
8422
+ this.optionCascadeConfigMap = input({}, ...(ngDevMode ? [{ debugName: "optionCascadeConfigMap" }] : []));
8423
+ this.coordinatePickerGeoConfig = input(...(ngDevMode ? [undefined, { debugName: "coordinatePickerGeoConfig" }] : []));
8424
+ this.fieldControlKeyById = input({}, ...(ngDevMode ? [{ debugName: "fieldControlKeyById" }] : []));
8425
+ // kept for compatibility (used by FileUploadField)
6707
8426
  this.program = input(...(ngDevMode ? [undefined, { debugName: "program" }] : []));
6708
8427
  this.value = model(...(ngDevMode ? [undefined, { debugName: "value" }] : []));
6709
8428
  this.value$ = toObservable(this.value);
6710
8429
  this.isValueAssigned$ = toObservable(this.isValueAssigned);
6711
8430
  this.fieldError$ = toObservable(this.fieldError);
6712
8431
  this.label = computed(() => {
6713
- return !this.fieldConfig()?.hideLabel ? this.field().label : undefined;
8432
+ const cfg = this.fieldConfig();
8433
+ const f = this.field();
8434
+ return cfg?.hideLabel ? undefined : f.label;
6714
8435
  }, ...(ngDevMode ? [{ debugName: "label" }] : []));
6715
8436
  this.placeholder = computed(() => {
6716
- return (this.field()?.placeholder || `Enter ${this.field()?.label || 'value'}`);
8437
+ const f = this.field();
8438
+ return f?.placeholder || `Enter ${f?.label || 'value'}`;
6717
8439
  }, ...(ngDevMode ? [{ debugName: "placeholder" }] : []));
6718
8440
  this.InputField = this.#getInputField();
6719
8441
  this.update = new EventEmitter();
@@ -6726,126 +8448,209 @@ class BaseFormFieldComponent extends ReactWrapperModule {
6726
8448
  this.component = this.InputField;
6727
8449
  this.render();
6728
8450
  }
8451
+ // -------------------------------
8452
+ // Cascade helpers (UID -> control)
8453
+ // -------------------------------
8454
+ #resolveCascadeForCurrentField() {
8455
+ const f = this.field();
8456
+ const map = this.optionCascadeConfigMap?.() ?? {};
8457
+ const byId = f?.id ? map?.[f.id] : undefined;
8458
+ const byKey = f?.key ? map?.[f.key] : undefined;
8459
+ if (byId || byKey)
8460
+ return (byId || byKey);
8461
+ const list = this.optionCascadeConfigs?.() ?? [];
8462
+ const id = f?.id;
8463
+ const key = f?.key;
8464
+ return list.find((c) => c?.fieldId === id || c?.fieldId === key);
8465
+ }
8466
+ #resolveControlName(fieldIdOrKey) {
8467
+ if (!fieldIdOrKey)
8468
+ return null;
8469
+ const mapped = this.fieldControlKeyById?.()?.[fieldIdOrKey];
8470
+ return mapped ?? fieldIdOrKey;
8471
+ }
8472
+ #getControl(fg, fieldIdOrKey) {
8473
+ const name = this.#resolveControlName(fieldIdOrKey);
8474
+ return name ? fg.get(name) : null;
8475
+ }
8476
+ #getCurrentFieldControl(fg) {
8477
+ const f = this.field();
8478
+ return this.#getControl(fg, f?.id) || this.#getControl(fg, f?.key);
8479
+ }
8480
+ #getOptionKey(option) {
8481
+ // Stable React key, avoids generateUUID re-mounting.
8482
+ return String(option?.value ?? option?.id ?? option?.code ?? option?.label ?? '');
8483
+ }
6729
8484
  #getInputField() {
6730
8485
  return () => {
6731
- const [value, setValue] = useState(this.form().get(this.field().id)?.value ||
6732
- this.form().get(this.field().key)?.value);
8486
+ const fg = this.form();
8487
+ const field = this.field();
8488
+ // Refs prevent stale closures in subscriptions
8489
+ const valueRef = useRef('');
8490
+ const touchedRef = useRef(false);
8491
+ // State
8492
+ const [value, setValue] = useState(() => {
8493
+ const ctrl = this.#getCurrentFieldControl(fg);
8494
+ const v = ctrl?.value;
8495
+ const s = v == null ? '' : String(v);
8496
+ valueRef.current = s;
8497
+ return s;
8498
+ });
8499
+ const [filteredOptions, setFilteredOptions] = useState(() => field.options ?? []);
6733
8500
  const [selected, setSelected] = useState();
6734
8501
  const [touched, setTouched] = useState(false);
6735
- const [disabled, setDisabled] = useState(this.field()?.disabled ?? this.field()?.generated ?? false);
8502
+ const baseDisabled = !!(field?.disabled ?? false) || !!(field?.generated ?? false);
8503
+ const [disabled, setDisabled] = useState(baseDisabled);
6736
8504
  const [initialError, setInitialError] = useState();
6737
8505
  const [recordExistError, setRecordExistError] = useState();
6738
- const [checkingUniqueness, setCheckingUniqueness] = useState();
8506
+ const [checkingUniqueness, setCheckingUniqueness] = useState(false);
8507
+ // Keep refs synced
6739
8508
  useEffect(() => {
6740
- const isAssignedSubscription = this.isValueAssigned$
6741
- .pipe(filter((isValueAssigned) => isValueAssigned === true))
8509
+ valueRef.current = value;
8510
+ }, [value]);
8511
+ useEffect(() => {
8512
+ touchedRef.current = touched;
8513
+ }, [touched]);
8514
+ // ----------------------------
8515
+ // Error stream: keep first new error
8516
+ // ----------------------------
8517
+ useEffect(() => {
8518
+ const sub = this.fieldError$
8519
+ .pipe(filter((error) => error !== initialError), take(1))
8520
+ .subscribe({ next: (error) => setInitialError(error) });
8521
+ return () => sub.unsubscribe();
8522
+ }, [initialError]);
8523
+ // ----------------------------
8524
+ // Uniqueness checker (stable)
8525
+ // ----------------------------
8526
+ const checkValueUniqueness = async (rawValue) => {
8527
+ const currentValue = (rawValue ?? valueRef.current ?? '').trim();
8528
+ const f = this.field();
8529
+ const isEligible = f.unique ||
8530
+ ((f.extension?.isDataElementUnique ?? false) &&
8531
+ currentValue.length > 0 &&
8532
+ touchedRef.current);
8533
+ if (!isEligible)
8534
+ return;
8535
+ setCheckingUniqueness(true);
8536
+ setRecordExistError(undefined);
8537
+ try {
8538
+ const isDuplicate = await this.searchForDuplicates(currentValue);
8539
+ setCheckingUniqueness(false);
8540
+ if (!isDuplicate)
8541
+ return;
8542
+ const customError = `Record with this ${this.label()} is already registered`;
8543
+ const ctrl = fg.controls[f.id] || (f.key ? fg.controls[f.key] : undefined);
8544
+ ctrl?.setErrors({ customError });
8545
+ setRecordExistError(customError);
8546
+ }
8547
+ catch {
8548
+ setCheckingUniqueness(false);
8549
+ setRecordExistError(undefined);
8550
+ }
8551
+ };
8552
+ // ----------------------------
8553
+ // Auto-assigned -> lock field + uniqueness check
8554
+ // ----------------------------
8555
+ useEffect(() => {
8556
+ const sub = this.isValueAssigned$
8557
+ .pipe(filter((v) => v === true))
6742
8558
  .subscribe({
6743
8559
  next: () => {
6744
- const value = this.form().get(this.field().id)?.value ||
6745
- this.form().get(this.field().key)?.value;
6746
- setValue(value);
8560
+ const ctrl = this.#getCurrentFieldControl(fg);
8561
+ const v = ctrl?.value == null ? '' : String(ctrl.value);
8562
+ setValue(v);
6747
8563
  setDisabled(true);
6748
- checkValueUniqueness();
8564
+ checkValueUniqueness(v);
6749
8565
  },
6750
8566
  });
6751
- return () => {
6752
- isAssignedSubscription.unsubscribe();
6753
- };
8567
+ return () => sub.unsubscribe();
6754
8568
  }, []);
6755
- // TODO: Review error handling as take() has potential to missed any other updated error information
8569
+ // ----------------------------
8570
+ // Cascade wiring (parent -> child)
8571
+ // ----------------------------
6756
8572
  useEffect(() => {
6757
- const fieldErrorSubscription = this.fieldError$
6758
- .pipe(filter((error) => error !== initialError), take(1))
6759
- .subscribe({
6760
- next: (error) => {
6761
- setInitialError(error);
6762
- },
6763
- });
6764
- return () => {
6765
- fieldErrorSubscription.unsubscribe();
8573
+ const cascade = this.#resolveCascadeForCurrentField();
8574
+ if (!cascade || cascade.kind !== 'OPTIONS_PATH') {
8575
+ setFilteredOptions(field.options ?? []);
8576
+ setDisabled(baseDisabled);
8577
+ // return null;
8578
+ return undefined;
8579
+ }
8580
+ const parentCtrl = this.#getControl(fg, cascade.parentFieldId);
8581
+ const childCtrl = this.#getCurrentFieldControl(fg);
8582
+ if (!parentCtrl || !childCtrl) {
8583
+ setFilteredOptions(field.options ?? []);
8584
+ setDisabled(baseDisabled);
8585
+ // return null;
8586
+ return undefined;
8587
+ }
8588
+ const merged = { ...DEFAULT_OPTIONS_PATH_CASCADE, ...cascade };
8589
+ const applyCascade = (parentValue, reason) => {
8590
+ const parentStr = String(parentValue ?? '');
8591
+ // disable logic
8592
+ const cascadeDisable = FieldCascadeUtil.shouldDisableChildField(cascade, parentStr);
8593
+ setDisabled(baseDisabled || cascadeDisable);
8594
+ // filter options
8595
+ const nextOptions = FieldCascadeUtil.filterChildOptionsByParentPath(field.options ?? [], cascade, parentStr);
8596
+ setFilteredOptions(nextOptions);
8597
+ // clear invalid child on parent change if configured
8598
+ if (merged.clearOnParentChange && reason === 'parentChange') {
8599
+ const currentChildValue = String(childCtrl.value ?? '').trim();
8600
+ if (currentChildValue) {
8601
+ const stillValid = nextOptions.some((o) => {
8602
+ const ov = String(o?.value ?? o?.id ?? '');
8603
+ return ov === currentChildValue;
8604
+ });
8605
+ if (!stillValid) {
8606
+ childCtrl.setValue(null, { emitEvent: true });
8607
+ setValue('');
8608
+ }
8609
+ }
8610
+ }
6766
8611
  };
6767
- }, [initialError]); // Add initialError as a dependency to avoid stale closures
8612
+ applyCascade(parentCtrl.value, 'init');
8613
+ const sub = parentCtrl.valueChanges.subscribe((v) => applyCascade(v, 'parentChange'));
8614
+ return () => sub.unsubscribe();
8615
+ }, []);
8616
+ // Derived
6768
8617
  const arrayValue = useMemo(() => {
6769
- if (value && value.length > 0) {
6770
- return value.split(',');
6771
- }
6772
- return [];
8618
+ const str = String(value ?? '');
8619
+ return str.length > 0 ? str.split(',') : [];
6773
8620
  }, [value]);
6774
8621
  const inputWidth = useMemo(() => {
6775
- if (this.field().controlType === 'date' ||
6776
- this.field().controlType === 'date-time') {
8622
+ const f = this.field();
8623
+ if (f.controlType === 'date' || f.controlType === 'date-time') {
6777
8624
  return '360px';
6778
8625
  }
6779
8626
  return this.fieldConfig()?.inputWidth;
6780
8627
  }, []);
6781
8628
  const { validationError, hasError } = useFieldValidation({
6782
- field: this.field(),
6783
- form: this.form(),
8629
+ field,
8630
+ form: fg,
6784
8631
  initialError,
6785
8632
  recordExistError,
6786
8633
  value,
6787
8634
  touched,
6788
8635
  });
6789
- const onValueChange = (value) => {
8636
+ const onValueChange = (newValue) => {
6790
8637
  this.ngZone.run(() => {
6791
- (this.form().get(this.field().id) ||
6792
- this.form().get(this.field().key))?.setValue(value);
6793
- this.update.emit({
6794
- form: this.form(),
6795
- value,
6796
- });
8638
+ const ctrl = this.#getCurrentFieldControl(fg);
8639
+ ctrl?.setValue(newValue);
8640
+ this.update.emit({ form: fg, value: newValue });
6797
8641
  });
6798
- setValue(value);
8642
+ const s = newValue == null ? '' : String(newValue);
8643
+ setValue(s);
6799
8644
  setTouched(true);
6800
8645
  };
6801
- const generateUUID = () => {
6802
- return (globalThis.crypto?.randomUUID?.() ??
6803
- 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
6804
- const r = (Math.random() * 16) | 0;
6805
- const v = c === 'x' ? r : (r & 0x3) | 0x8;
6806
- return v.toString(16);
6807
- }));
6808
- };
6809
- const checkValueUniqueness = async () => {
6810
- if (this.field().unique ||
6811
- ((this.field().extension?.isDataElementUnique ?? false) &&
6812
- value &&
6813
- value.length > 0 &&
6814
- touched)) {
6815
- setCheckingUniqueness(true);
6816
- setRecordExistError(undefined);
6817
- try {
6818
- const isDuplicate = await this.searchForDuplicates(value);
6819
- setCheckingUniqueness(false);
6820
- if (isDuplicate) {
6821
- const customError = `Record with this ${this.label()} is already registered`;
6822
- (this.form().controls[this.field().id] ||
6823
- this.form().controls[this.field().key])?.setErrors({
6824
- customError,
6825
- });
6826
- setRecordExistError(customError);
6827
- }
6828
- }
6829
- catch (e) {
6830
- setCheckingUniqueness(false);
6831
- setRecordExistError(undefined);
6832
- }
6833
- }
6834
- };
8646
+ // UI renderer
6835
8647
  const formFieldContent = () => {
6836
- switch (this.field().controlType) {
8648
+ const f = this.field();
8649
+ switch (f.controlType) {
6837
8650
  case 'number':
6838
- return (React__default.createElement(InputField$1, { error: hasError, validationText: validationError, type: this.field().type, inputWidth: 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, readOnly: disabled, onChange: (event) => {
6839
- onValueChange(event.value);
6840
- }, onBlur: () => {
6841
- checkValueUniqueness();
6842
- } }));
8651
+ return (React__default.createElement(InputField$1, { error: hasError, validationText: validationError, type: f.type, inputWidth: inputWidth, required: f.required, name: f.id, label: this.label(), min: f.min?.toString(), max: f.max?.toString(), placeholder: this.placeholder(), value: value, readOnly: disabled, onChange: (event) => onValueChange(event.value), onBlur: () => checkValueUniqueness() }));
6843
8652
  case 'tel':
6844
- return (React__default.createElement(InternationalPhoneField, { name: this.field().id, label: this.label(), placeholder: this.placeholder(), value: value ?? '', required: this.field().required, disabled: disabled, error: hasError, validationText: validationError, inputWidth: this.fieldConfig()?.inputWidth, defaultCountryIsoCode: "TZ", onChange: (localNumber) => {
6845
- onValueChange(localNumber);
6846
- }, onBlur: () => {
6847
- checkValueUniqueness();
6848
- } }));
8653
+ return (React__default.createElement(InternationalPhoneField, { name: f.id, label: this.label(), placeholder: this.placeholder(), value: value ?? '', required: f.required, disabled: disabled, error: hasError, validationText: validationError, inputWidth: this.fieldConfig()?.inputWidth, defaultCountryIsoCode: "TZ", onChange: (localNumber) => onValueChange(localNumber), onBlur: () => checkValueUniqueness() }));
6849
8654
  case 'coordinate':
6850
8655
  return (React__default.createElement("div", { style: { display: 'flex', flexDirection: 'column', gap: 12 } },
6851
8656
  React__default.createElement(NoticeBox, { title: "Location capture required" },
@@ -6861,127 +8666,56 @@ class BaseFormFieldComponent extends ReactWrapperModule {
6861
8666
  "Click ",
6862
8667
  React__default.createElement("strong", null, "\u201CUse Selected Location\u201D"),
6863
8668
  " to save the coordinates."))),
6864
- React__default.createElement(CoordinatePickerField, { error: hasError, validationText: validationError, required: this.field().required, name: this.field().id, disabled: disabled, label: this.label(), value: value, onChange: (newValue) => {
6865
- onValueChange(newValue);
6866
- }, onBlur: () => {
6867
- checkValueUniqueness();
6868
- } })));
8669
+ React__default.createElement(CoordinatePickerField, { error: hasError, validationText: validationError, required: f.required, name: f.id, disabled: disabled, label: this.label(), value: value, geoConfig: this.coordinatePickerGeoConfig(), onChange: (newValue) => onValueChange(newValue), onBlur: () => checkValueUniqueness() })));
6869
8670
  case 'textarea':
6870
- return (React__default.createElement(TextAreaField, { error: hasError, validationText: validationError, inputWidth: this.fieldConfig()?.inputWidth, required: this.field().required, name: this.field().id, disabled: disabled, label: this.label(), rows: 5, placeholder: this.placeholder(), value: value, onChange: (event) => {
6871
- onValueChange(event.value);
6872
- }, onBlur: () => {
6873
- checkValueUniqueness();
6874
- } }));
6875
- case 'org-unit': {
6876
- return (React__default.createElement(OrgUnitFormField, { label: this.label(), key: this.field().id, field: this.field().id, required: this.field().required, disabled: disabled, customOrgUnitRoots: this.customOrgUnitRoots(), onSelectOrgUnit: (selectedOrgUnit) => {
6877
- onValueChange(selectedOrgUnit);
6878
- }, selected: value }));
6879
- }
8671
+ return (React__default.createElement(TextAreaField, { error: hasError, validationText: validationError, inputWidth: this.fieldConfig()?.inputWidth, required: f.required, name: f.id, disabled: disabled, label: this.label(), rows: 5, placeholder: this.placeholder(), value: value, onChange: (event) => onValueChange(event.value), onBlur: () => checkValueUniqueness() }));
8672
+ case 'org-unit':
8673
+ return (React__default.createElement(OrgUnitFormField, { label: this.label(), key: f.id, field: f.id, required: f.required, disabled: disabled, customOrgUnitRoots: this.customOrgUnitRoots(), onSelectOrgUnit: (selectedOrgUnit) => onValueChange(selectedOrgUnit), selected: value }));
6880
8674
  case 'transfer':
6881
- return (React__default.createElement(Transfer, { filterable: true, filterPlaceholder: "Search", selected: selected, leftHeader: React__default.createElement("div", { style: {
6882
- fontSize: 14,
6883
- padding: '8px 4px',
6884
- } }, this.field().availableOptionsLabel), rightHeader: React__default.createElement("div", { style: {
6885
- fontSize: 14,
6886
- padding: '8px 4px',
6887
- } }, this.field().selectedOptionsLabel), options: this.field().options, onChange: (event) => {
6888
- onValueChange(event.selected);
6889
- } }));
8675
+ return (React__default.createElement(Transfer, { filterable: true, filterPlaceholder: "Search", selected: selected, leftHeader: React__default.createElement("div", { style: { fontSize: 14, padding: '8px 4px' } }, f.availableOptionsLabel), rightHeader: React__default.createElement("div", { style: { fontSize: 14, padding: '8px 4px' } }, f.selectedOptionsLabel), options: f.options, onChange: (event) => onValueChange(event.selected) }));
6890
8676
  case 'checkbox':
6891
- return (React__default.createElement(Checkbox, { checked: Boolean(value), error: hasError, label: this.label(), name: this.field().id, disabled: disabled, onChange: (event) => {
6892
- onValueChange(event.checked);
6893
- }, onBlur: () => {
6894
- checkValueUniqueness();
6895
- } }));
8677
+ return (React__default.createElement(Checkbox, { checked: Boolean(value), error: hasError, label: this.label(), name: f.id, disabled: disabled, onChange: (event) => onValueChange(event.checked), onBlur: () => checkValueUniqueness() }));
6896
8678
  case 'dropdown':
6897
- return (React__default.createElement(SingleSelectField, { filterable: (this.field().options || []).length > 5, clearable: true, error: hasError, validationText: validationError, inputWidth: this.fieldConfig()?.inputWidth, disabled: disabled, required: this.field().required, className: "select", label: this.label(), selected: value, onChange: (event) => {
6898
- onValueChange(event.selected);
6899
- }, onBlur: () => {
6900
- checkValueUniqueness();
6901
- } }, (this.field().options || []).map((option) => (React__default.createElement(SingleSelectOption, { key: generateUUID(), label: option.label, value: option.value })))));
8679
+ return (React__default.createElement(SingleSelectField, { filterable: (filteredOptions || []).length > 5, clearable: true, error: hasError, validationText: validationError, inputWidth: this.fieldConfig()?.inputWidth, disabled: disabled, required: f.required, className: "select", label: this.label(), selected: value, onChange: (event) => onValueChange(event.selected), onBlur: () => checkValueUniqueness() }, (filteredOptions || []).map((option) => (React__default.createElement(SingleSelectOption, { key: this.#getOptionKey(option), label: option.label ?? option.name ?? option.displayName, value: option.value ?? option.id })))));
6902
8680
  case 'multi-dropdown':
6903
- 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: disabled, label: this.label(), required: this.field().required, loadingText: "Loading options", noMatchText: "No options found", onChange: (event) => {
8681
+ return (React__default.createElement(MultiSelectField, { clearText: "Clear", clearable: true, empty: "No data found", filterable: (filteredOptions || []).length > 5, filterPlaceholder: "Type to filter options", error: hasError, validationText: validationError, inputWidth: this.fieldConfig()?.inputWidth, disabled: disabled, label: this.label(), required: f.required, loadingText: "Loading options", noMatchText: "No options found", onChange: (event) => {
6904
8682
  const selectedValue = (event.selected || []).join(',');
6905
8683
  onValueChange(selectedValue);
6906
- }, onBlur: () => {
6907
- checkValueUniqueness();
6908
- }, selected: arrayValue }, (this.field().options || []).map((option) => (React__default.createElement(MultiSelectOption, { key: generateUUID(), label: option.label, value: option.value })))));
6909
- // case 'date':
6910
- // case 'date-time':
6911
- // return (
6912
- // <InputField
6913
- // error={hasError}
6914
- // validationText={validationError}
6915
- // type={this.field().type as any}
6916
- // inputWidth={inputWidth}
6917
- // required={this.field().required}
6918
- // name={this.field().id}
6919
- // label={this.label()}
6920
- // min={this.field().min?.toString()}
6921
- // max={this.field().max?.toString()}
6922
- // placeholder={this.placeholder()}
6923
- // value={value}
6924
- // readOnly={disabled}
6925
- // onChange={(event: any) => {
6926
- // onValueChange(event.value);
6927
- // }}
6928
- // onBlur={() => {
6929
- // checkValueUniqueness();
6930
- // }}
6931
- // />
6932
- // );
8684
+ }, onBlur: () => checkValueUniqueness(), selected: arrayValue }, (filteredOptions || []).map((option) => (React__default.createElement(MultiSelectOption, { key: this.#getOptionKey(option), label: option.label ?? option.name ?? option.displayName, value: option.value ?? option.id })))));
6933
8685
  case 'date':
6934
8686
  case 'date-time': {
6935
- const field = this.field();
6936
- const isDateTimeField = field.type === 'date-time';
8687
+ const isDateTimeField = f.type === 'date-time';
6937
8688
  const inputType = isDateTimeField ? 'datetime-local' : 'date';
6938
- // Value coming from DHIS2 store
6939
8689
  const htmlValue = this.formatValueForHtmlInputFromDhis(value, isDateTimeField);
6940
- const htmlMin = field.min
6941
- ? this.formatValueForHtmlInputFromDhis(String(field.min), isDateTimeField)
8690
+ const htmlMin = f.min
8691
+ ? this.formatValueForHtmlInputFromDhis(String(f.min), isDateTimeField)
6942
8692
  : undefined;
6943
- // Max defined in metadata (if any)
6944
- const metadataMax = field.max
6945
- ? this.formatValueForHtmlInputFromDhis(String(field.max), isDateTimeField)
8693
+ const metadataMax = f.max
8694
+ ? this.formatValueForHtmlInputFromDhis(String(f.max), isDateTimeField)
6946
8695
  : undefined;
6947
- // System max = “now” (no future allowed)
6948
8696
  const systemMax = this.getNowForHtmlDateInput(isDateTimeField);
6949
- // Effective max = earliest of metadataMax and systemMax
6950
8697
  const htmlMax = this.pickEarlierDateLimit(metadataMax, systemMax);
6951
- return (React__default.createElement(InputField$1, { error: hasError, validationText: validationError, type: inputType, inputWidth: inputWidth, required: field.required, name: field.id, label: this.label(), min: htmlMin, max: htmlMax, placeholder: this.placeholder(), value: htmlValue, readOnly: disabled, onChange: ({ value: newValue }) => {
8698
+ return (React__default.createElement(InputField$1, { error: hasError, validationText: validationError, type: inputType, inputWidth: inputWidth, required: f.required, name: f.id, label: this.label(), min: htmlMin, max: htmlMax, placeholder: this.placeholder(), value: htmlValue, readOnly: disabled, onChange: ({ value: newValue }) => {
6952
8699
  const normalized = this.normalizeDateValueFromHtmlInput(newValue, isDateTimeField, true);
6953
8700
  onValueChange(normalized);
6954
- }, onBlur: () => {
6955
- checkValueUniqueness();
6956
- } }));
8701
+ }, onBlur: () => checkValueUniqueness() }));
6957
8702
  }
6958
8703
  case 'file':
6959
- return (React__default.createElement(React__default.Fragment, null,
6960
- React__default.createElement(FileUploadField, { label: this.label(), id: this.field().id, hasError: hasError, required: this.field().required, validationText: validationError, performUpload: true, uploadUrl: 'fileResources', onUploadSuccess: (fileId) => {
6961
- onValueChange(fileId);
6962
- }, onRemoveFile: () => {
6963
- onValueChange('');
6964
- }, extension: this.field()?.extension, value: value, metaType: this.field().metaType, dataId: this.dataId(), program: this.program() })));
8704
+ return (React__default.createElement(FileUploadField, { label: this.label(), id: f.id, hasError: hasError, required: f.required, validationText: validationError, performUpload: true, uploadUrl: 'fileResources', onUploadSuccess: (fileId) => onValueChange(fileId), onRemoveFile: () => onValueChange(''), extension: f?.extension, value: value, metaType: f.metaType, dataId: this.dataId(), program: this.program() }));
6965
8705
  default:
6966
- return (React__default.createElement(InputField$1, { error: hasError, validationText: validationError, type: this.field().type, inputWidth: 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, readOnly: disabled, onChange: (event) => {
6967
- onValueChange(event.value);
6968
- }, onBlur: () => {
6969
- checkValueUniqueness();
6970
- } }));
8706
+ return (React__default.createElement(InputField$1, { error: hasError, validationText: validationError, type: f.type, inputWidth: inputWidth, required: f.required, name: f.id, label: this.label(), min: f.min?.toString(), max: f.max?.toString(), placeholder: this.placeholder(), value: value, readOnly: disabled, onChange: (event) => onValueChange(event.value), onBlur: () => checkValueUniqueness() }));
6971
8707
  }
6972
8708
  };
6973
- {
6974
- return (React__default.createElement(React__default.Fragment, null,
6975
- formFieldContent(),
6976
- checkingUniqueness && (React__default.createElement("div", { style: {
6977
- display: 'flex',
6978
- alignItems: 'center',
6979
- gap: 8,
6980
- paddingTop: 8,
6981
- } },
6982
- React__default.createElement(CircularLoader$1, { small: true }),
6983
- React__default.createElement("div", { style: { color: colors$1.grey800, fontSize: 14 } }, "Checking...")))));
6984
- }
8709
+ return (React__default.createElement(React__default.Fragment, null,
8710
+ formFieldContent(),
8711
+ checkingUniqueness && (React__default.createElement("div", { style: {
8712
+ display: 'flex',
8713
+ alignItems: 'center',
8714
+ gap: 8,
8715
+ paddingTop: 8,
8716
+ } },
8717
+ React__default.createElement(CircularLoader$1, { small: true }),
8718
+ React__default.createElement("div", { style: { color: colors$1.grey800, fontSize: 14 } }, "Checking...")))));
6985
8719
  };
6986
8720
  }
6987
8721
  onChange(event) {
@@ -7150,7 +8884,7 @@ class BaseFormFieldComponent extends ReactWrapperModule {
7150
8884
  }
7151
8885
  }
7152
8886
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: BaseFormFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
7153
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.1.3", type: BaseFormFieldComponent, isStandalone: true, inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, fieldError: { classPropertyName: "fieldError", publicName: "fieldError", isSignal: true, isRequired: false, transformFunction: null }, fieldConfig: { classPropertyName: "fieldConfig", publicName: "fieldConfig", isSignal: true, isRequired: false, transformFunction: null }, form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: true, transformFunction: null }, isValid: { classPropertyName: "isValid", publicName: "isValid", isSignal: true, isRequired: false, transformFunction: null }, isValueAssigned: { classPropertyName: "isValueAssigned", publicName: "isValueAssigned", isSignal: true, isRequired: false, transformFunction: null }, dataId: { classPropertyName: "dataId", publicName: "dataId", isSignal: true, isRequired: false, transformFunction: null }, customOrgUnitRoots: { classPropertyName: "customOrgUnitRoots", publicName: "customOrgUnitRoots", isSignal: true, isRequired: false, transformFunction: null }, program: { classPropertyName: "program", publicName: "program", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { form: "formChange", value: "valueChange", update: "update", immediateUpdate: "immediateUpdate" }, usesInheritance: true, ngImport: i0 }); }
8887
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.1.3", type: BaseFormFieldComponent, isStandalone: true, inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, fieldError: { classPropertyName: "fieldError", publicName: "fieldError", isSignal: true, isRequired: false, transformFunction: null }, fieldConfig: { classPropertyName: "fieldConfig", publicName: "fieldConfig", isSignal: true, isRequired: false, transformFunction: null }, form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: true, transformFunction: null }, isValid: { classPropertyName: "isValid", publicName: "isValid", isSignal: true, isRequired: false, transformFunction: null }, isValueAssigned: { classPropertyName: "isValueAssigned", publicName: "isValueAssigned", isSignal: true, isRequired: false, transformFunction: null }, dataId: { classPropertyName: "dataId", publicName: "dataId", isSignal: true, isRequired: false, transformFunction: null }, customOrgUnitRoots: { classPropertyName: "customOrgUnitRoots", publicName: "customOrgUnitRoots", isSignal: true, isRequired: false, transformFunction: null }, optionCascadeConfigs: { classPropertyName: "optionCascadeConfigs", publicName: "optionCascadeConfigs", isSignal: true, isRequired: false, transformFunction: null }, optionCascadeConfigMap: { classPropertyName: "optionCascadeConfigMap", publicName: "optionCascadeConfigMap", isSignal: true, isRequired: false, transformFunction: null }, coordinatePickerGeoConfig: { classPropertyName: "coordinatePickerGeoConfig", publicName: "coordinatePickerGeoConfig", isSignal: true, isRequired: false, transformFunction: null }, fieldControlKeyById: { classPropertyName: "fieldControlKeyById", publicName: "fieldControlKeyById", isSignal: true, isRequired: false, transformFunction: null }, program: { classPropertyName: "program", publicName: "program", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { form: "formChange", value: "valueChange", update: "update", immediateUpdate: "immediateUpdate" }, usesInheritance: true, ngImport: i0 }); }
7154
8888
  }
7155
8889
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: BaseFormFieldComponent, decorators: [{
7156
8890
  type: Directive
@@ -7187,6 +8921,10 @@ class FormFieldComponent {
7187
8921
  this.customOrgUnitRoots = input(...(ngDevMode ? [undefined, { debugName: "customOrgUnitRoots" }] : []));
7188
8922
  //TODO: FIND BETTER WAY TO PASS PROGRAM TO FIELDS i.e field extensions
7189
8923
  this.program = input(...(ngDevMode ? [undefined, { debugName: "program" }] : []));
8924
+ this.optionCascadeConfigs = input([], ...(ngDevMode ? [{ debugName: "optionCascadeConfigs" }] : []));
8925
+ this.optionCascadeConfigMap = input({}, ...(ngDevMode ? [{ debugName: "optionCascadeConfigMap" }] : []));
8926
+ this.coordinatePickerGeoConfig = input(...(ngDevMode ? [undefined, { debugName: "coordinatePickerGeoConfig" }] : []));
8927
+ this.fieldControlKeyById = input({}, ...(ngDevMode ? [{ debugName: "fieldControlKeyById" }] : []));
7190
8928
  this.color = 'primary';
7191
8929
  this.fieldUpdate = new EventEmitter();
7192
8930
  this.immediateFieldUpdate = new EventEmitter();
@@ -7365,11 +9103,11 @@ class FormFieldComponent {
7365
9103
  this._runtimeOptions = [...options];
7366
9104
  }
7367
9105
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: FormFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7368
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.1.3", type: FormFieldComponent, isStandalone: false, selector: "ng-dhis2-ui-form-field", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, fieldConfig: { classPropertyName: "fieldConfig", publicName: "fieldConfig", isSignal: true, isRequired: true, transformFunction: null }, form: { classPropertyName: "form", publicName: "form", isSignal: false, isRequired: false, transformFunction: null }, isCheckBoxButton: { classPropertyName: "isCheckBoxButton", publicName: "isCheckBoxButton", isSignal: true, isRequired: false, transformFunction: null }, fieldClass: { classPropertyName: "fieldClass", publicName: "fieldClass", isSignal: true, isRequired: false, transformFunction: null }, programRuleActions: { classPropertyName: "programRuleActions", publicName: "programRuleActions", isSignal: true, isRequired: false, transformFunction: null }, dataEntities: { classPropertyName: "dataEntities", publicName: "dataEntities", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: false, transformFunction: null }, dataId: { classPropertyName: "dataId", publicName: "dataId", isSignal: true, isRequired: false, transformFunction: null }, customOrgUnitRoots: { classPropertyName: "customOrgUnitRoots", publicName: "customOrgUnitRoots", isSignal: true, isRequired: false, transformFunction: null }, program: { classPropertyName: "program", publicName: "program", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { fieldUpdate: "fieldUpdate", immediateFieldUpdate: "immediateFieldUpdate", runtimeOptionChange: "runtimeOptionChange" }, usesOnChanges: true, ngImport: i0, template: "<div *ngIf=\"field()\" class=\"form-field-item\">\n <ng-dhis2-ui-form-field-item\n [field]=\"field()\"\n [fieldError]=\"runtimeError()\"\n [isValueAssigned]=\"isValueAssigned()\"\n [fieldConfig]=\"fieldConfig()\"\n [(form)]=\"form\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [program]=\"program()\"\n [value]=\"value()\"\n (update)=\"onValueChange()\"\n (immediateUpdate)=\"onImmediateChange($event)\"\n />\n</div>\n", styles: [".form-field-item{margin-bottom:16px}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: FormFieldItemComponent, selector: "ng-dhis2-ui-form-field-item" }] }); }
9106
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.3", type: FormFieldComponent, isStandalone: false, selector: "ng-dhis2-ui-form-field", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, fieldConfig: { classPropertyName: "fieldConfig", publicName: "fieldConfig", isSignal: true, isRequired: true, transformFunction: null }, form: { classPropertyName: "form", publicName: "form", isSignal: false, isRequired: false, transformFunction: null }, isCheckBoxButton: { classPropertyName: "isCheckBoxButton", publicName: "isCheckBoxButton", isSignal: true, isRequired: false, transformFunction: null }, fieldClass: { classPropertyName: "fieldClass", publicName: "fieldClass", isSignal: true, isRequired: false, transformFunction: null }, programRuleActions: { classPropertyName: "programRuleActions", publicName: "programRuleActions", isSignal: true, isRequired: false, transformFunction: null }, dataEntities: { classPropertyName: "dataEntities", publicName: "dataEntities", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: false, transformFunction: null }, dataId: { classPropertyName: "dataId", publicName: "dataId", isSignal: true, isRequired: false, transformFunction: null }, customOrgUnitRoots: { classPropertyName: "customOrgUnitRoots", publicName: "customOrgUnitRoots", isSignal: true, isRequired: false, transformFunction: null }, program: { classPropertyName: "program", publicName: "program", isSignal: true, isRequired: false, transformFunction: null }, optionCascadeConfigs: { classPropertyName: "optionCascadeConfigs", publicName: "optionCascadeConfigs", isSignal: true, isRequired: false, transformFunction: null }, optionCascadeConfigMap: { classPropertyName: "optionCascadeConfigMap", publicName: "optionCascadeConfigMap", isSignal: true, isRequired: false, transformFunction: null }, coordinatePickerGeoConfig: { classPropertyName: "coordinatePickerGeoConfig", publicName: "coordinatePickerGeoConfig", isSignal: true, isRequired: false, transformFunction: null }, fieldControlKeyById: { classPropertyName: "fieldControlKeyById", publicName: "fieldControlKeyById", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { fieldUpdate: "fieldUpdate", immediateFieldUpdate: "immediateFieldUpdate", runtimeOptionChange: "runtimeOptionChange" }, usesOnChanges: true, ngImport: i0, template: "@if (field(); as formField) {\n @let fieldError = runtimeError();\n @let isAssigned = isValueAssigned();\n @let fieldConfigValue = fieldConfig();\n @let cascadeConfigs = optionCascadeConfigs();\n @let entryFormCoordinatePickerGeoConfig = coordinatePickerGeoConfig();\n\n <div class=\"form-field-item\">\n <ng-dhis2-ui-form-field-item\n [field]=\"formField\"\n [fieldError]=\"fieldError\"\n [isValueAssigned]=\"isAssigned\"\n [fieldConfig]=\"fieldConfigValue\"\n [(form)]=\"form\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigs]=\"cascadeConfigs\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [fieldControlKeyById]=\"fieldControlKeyById()\"\n [coordinatePickerGeoConfig]=\"entryFormCoordinatePickerGeoConfig\"\n [program]=\"program()\"\n [value]=\"value()\"\n (update)=\"onValueChange()\"\n (immediateUpdate)=\"onImmediateChange($event)\"\n />\n </div>\n}\n", styles: [".form-field-item{margin-bottom:16px}\n"], dependencies: [{ kind: "component", type: FormFieldItemComponent, selector: "ng-dhis2-ui-form-field-item" }] }); }
7369
9107
  }
7370
9108
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: FormFieldComponent, decorators: [{
7371
9109
  type: Component,
7372
- args: [{ selector: 'ng-dhis2-ui-form-field', standalone: false, template: "<div *ngIf=\"field()\" class=\"form-field-item\">\n <ng-dhis2-ui-form-field-item\n [field]=\"field()\"\n [fieldError]=\"runtimeError()\"\n [isValueAssigned]=\"isValueAssigned()\"\n [fieldConfig]=\"fieldConfig()\"\n [(form)]=\"form\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [program]=\"program()\"\n [value]=\"value()\"\n (update)=\"onValueChange()\"\n (immediateUpdate)=\"onImmediateChange($event)\"\n />\n</div>\n", styles: [".form-field-item{margin-bottom:16px}\n"] }]
9110
+ args: [{ selector: 'ng-dhis2-ui-form-field', standalone: false, template: "@if (field(); as formField) {\n @let fieldError = runtimeError();\n @let isAssigned = isValueAssigned();\n @let fieldConfigValue = fieldConfig();\n @let cascadeConfigs = optionCascadeConfigs();\n @let entryFormCoordinatePickerGeoConfig = coordinatePickerGeoConfig();\n\n <div class=\"form-field-item\">\n <ng-dhis2-ui-form-field-item\n [field]=\"formField\"\n [fieldError]=\"fieldError\"\n [isValueAssigned]=\"isAssigned\"\n [fieldConfig]=\"fieldConfigValue\"\n [(form)]=\"form\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigs]=\"cascadeConfigs\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [fieldControlKeyById]=\"fieldControlKeyById()\"\n [coordinatePickerGeoConfig]=\"entryFormCoordinatePickerGeoConfig\"\n [program]=\"program()\"\n [value]=\"value()\"\n (update)=\"onValueChange()\"\n (immediateUpdate)=\"onImmediateChange($event)\"\n />\n </div>\n}\n", styles: [".form-field-item{margin-bottom:16px}\n"] }]
7373
9111
  }], ctorParameters: () => [], propDecorators: { form: [{
7374
9112
  type: Input
7375
9113
  }], fieldUpdate: [{
@@ -7424,32 +9162,6 @@ class FormValue {
7424
9162
  }
7425
9163
 
7426
9164
  class FormComponent {
7427
- // get sanitizedFields(): IFormField<string>[] {
7428
- // return (this.fields() || []).filter((field: any) => {
7429
- // if (field.hidden) {
7430
- // return false;
7431
- // }
7432
- // const type = field.isDataElement
7433
- // ? 'dataElement'
7434
- // : 'trackedEntityAttribute';
7435
- // const elementItem = field[type] || field;
7436
- // if (!elementItem) {
7437
- // return true;
7438
- // }
7439
- // const availableRule = head(
7440
- // (this.programRuleActions() || []).filter((ruleAction) => {
7441
- // return (
7442
- // ruleAction.field === elementItem.id &&
7443
- // ruleAction.actionType === 'HIDEFIELD'
7444
- // );
7445
- // })
7446
- // );
7447
- // if (!availableRule) {
7448
- // return true;
7449
- // }
7450
- // return availableRule.actionType !== 'HIDEFIELD';
7451
- // });
7452
- // }
7453
9165
  get layoutCssClass() {
7454
9166
  if (!this.isFormHorizontal()) {
7455
9167
  return 'col-12';
@@ -7479,6 +9191,16 @@ class FormComponent {
7479
9191
  this.dataEntities = input(undefined, ...(ngDevMode ? [{ debugName: "dataEntities" }] : []));
7480
9192
  this.dataId = input(...(ngDevMode ? [undefined, { debugName: "dataId" }] : []));
7481
9193
  this.customOrgUnitRoots = input(...(ngDevMode ? [undefined, { debugName: "customOrgUnitRoots" }] : []));
9194
+ this.optionCascadeConfigs = input([], ...(ngDevMode ? [{ debugName: "optionCascadeConfigs" }] : []));
9195
+ this.coordinatePickerGeoConfig = input(...(ngDevMode ? [undefined, { debugName: "coordinatePickerGeoConfig" }] : []));
9196
+ /** ✅ Build map once when configs change */
9197
+ this.optionCascadeConfigMap = computed(() => {
9198
+ const configs = this.optionCascadeConfigs() ?? [];
9199
+ // (optional) guard if you later widen union types
9200
+ const optionPathConfigs = configs.filter((c) => c?.kind === CascadeKind.OPTIONS_PATH);
9201
+ // util returns: Readonly<Record<string, OptionsPathCascadeConfig>>
9202
+ return FieldCascadeUtil.buildConfigByChildFieldId(optionPathConfigs);
9203
+ }, ...(ngDevMode ? [{ debugName: "optionCascadeConfigMap" }] : []));
7482
9204
  //TODO: FIND BETTER WAY TO PASS PROGRAM TO FIELDS i.e field extensions
7483
9205
  this.program = input(...(ngDevMode ? [undefined, { debugName: "program" }] : []));
7484
9206
  this.collapsibleSections = input(false, ...(ngDevMode ? [{ debugName: "collapsibleSections" }] : []));
@@ -7494,6 +9216,43 @@ class FormComponent {
7494
9216
  this.formUpdate = new EventEmitter();
7495
9217
  this.formValidityUpdate = new EventEmitter();
7496
9218
  // get sanitizedFields(): IFormField<string>[] {
9219
+ // return (this.fields() || []).filter((field: any) => {
9220
+ // if (field.hidden) {
9221
+ // return false;
9222
+ // }
9223
+ // const type = field.isDataElement
9224
+ // ? 'dataElement'
9225
+ // : 'trackedEntityAttribute';
9226
+ // const elementItem = field[type] || field;
9227
+ // if (!elementItem) {
9228
+ // return true;
9229
+ // }
9230
+ // const availableRule = head(
9231
+ // (this.programRuleActions() || []).filter((ruleAction) => {
9232
+ // return (
9233
+ // ruleAction.field === elementItem.id &&
9234
+ // ruleAction.actionType === 'HIDEFIELD'
9235
+ // );
9236
+ // })
9237
+ // );
9238
+ // if (!availableRule) {
9239
+ // return true;
9240
+ // }
9241
+ // return availableRule.actionType !== 'HIDEFIELD';
9242
+ // });
9243
+ // }
9244
+ this.fieldControlKeyById = computed(() => {
9245
+ const list = this.fields() ?? []; // or sanitizedFields
9246
+ const map = Object.create(null);
9247
+ for (const f of list) {
9248
+ if (!f?.id)
9249
+ continue;
9250
+ // Prefer explicit key if present, else fall back to id.
9251
+ map[f.id] = f.key || f.id;
9252
+ }
9253
+ return map;
9254
+ }, ...(ngDevMode ? [{ debugName: "fieldControlKeyById" }] : []));
9255
+ // get sanitizedFields(): IFormField<string>[] {
7497
9256
  // return (this.fields() || []).filter(
7498
9257
  // (field) => !this.isFieldHiddenByRules(field)
7499
9258
  // );
@@ -7615,7 +9374,6 @@ class FormComponent {
7615
9374
  // TODO: This is uneccesary emit at this stage of execution, since nothing has changes at initiation and potentially break some of implementation that depends formUpdate, which also is triggered when there is actual change in the form apart form initial values that came with it
7616
9375
  this.formUpdate.emit(new FormValue(this.form(), this.fields()));
7617
9376
  this.formValidityUpdate.emit(new FormValue(this.form(), this.fields()).isValid);
7618
- console.log();
7619
9377
  }
7620
9378
  // ngOnChanges(changes: SimpleChanges): void {
7621
9379
  // this.values = this.form.getRawValue();
@@ -7692,11 +9450,11 @@ class FormComponent {
7692
9450
  return this.hiddenFieldIds().has(elementItem.id);
7693
9451
  }
7694
9452
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: FormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7695
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.3", type: FormComponent, isStandalone: false, selector: "ng-dhis2-ui-form", inputs: { programEntryFormConfig: { classPropertyName: "programEntryFormConfig", publicName: "programEntryFormConfig", isSignal: true, isRequired: false, transformFunction: null }, formConfig: { classPropertyName: "formConfig", publicName: "formConfig", isSignal: true, isRequired: false, transformFunction: null }, fields: { classPropertyName: "fields", publicName: "fields", isSignal: true, isRequired: true, transformFunction: null }, form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: true, transformFunction: null }, isFormHorizontal: { classPropertyName: "isFormHorizontal", publicName: "isFormHorizontal", isSignal: true, isRequired: false, transformFunction: null }, showSaveButton: { classPropertyName: "showSaveButton", publicName: "showSaveButton", isSignal: true, isRequired: false, transformFunction: null }, fieldsData: { classPropertyName: "fieldsData", publicName: "fieldsData", isSignal: true, isRequired: false, transformFunction: null }, formMetaData: { classPropertyName: "formMetaData", publicName: "formMetaData", isSignal: true, isRequired: false, transformFunction: null }, programEntryFormMetaData: { classPropertyName: "programEntryFormMetaData", publicName: "programEntryFormMetaData", isSignal: true, isRequired: false, transformFunction: null }, fieldClass: { classPropertyName: "fieldClass", publicName: "fieldClass", isSignal: true, isRequired: false, transformFunction: null }, shouldRenderAsCheckBoxesButton: { classPropertyName: "shouldRenderAsCheckBoxesButton", publicName: "shouldRenderAsCheckBoxesButton", isSignal: true, isRequired: false, transformFunction: null }, programRuleActions: { classPropertyName: "programRuleActions", publicName: "programRuleActions", isSignal: true, isRequired: false, transformFunction: null }, dataEntities: { classPropertyName: "dataEntities", publicName: "dataEntities", isSignal: true, isRequired: false, transformFunction: null }, dataId: { classPropertyName: "dataId", publicName: "dataId", isSignal: true, isRequired: false, transformFunction: null }, customOrgUnitRoots: { classPropertyName: "customOrgUnitRoots", publicName: "customOrgUnitRoots", isSignal: true, isRequired: false, transformFunction: null }, program: { classPropertyName: "program", publicName: "program", isSignal: true, isRequired: false, transformFunction: null }, collapsibleSections: { classPropertyName: "collapsibleSections", publicName: "collapsibleSections", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { formUpdate: "formUpdate", formValidityUpdate: "formValidityUpdate" }, viewQueries: [{ propertyName: "fieldComponents", predicate: FormFieldComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<!-- <form [formGroup]=\"form()\" class=\"{{ configuration().directionClassName }}\">\n <div class=\"form-name\">\n <h2>{{ configuration().formName }}</h2>\n </div>\n\n <div>\n {{ formMetaData().sections }}\n </div>\n <div\n *ngFor=\"let field of sanitizedFields\"\n class=\"form-field-{{ configuration().direction }}\"\n >\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [program]=\"program()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n</form> -->\n\n<!-- <form [formGroup]=\"form()\" class=\"form {{ configuration().directionClassName }}\">\n <div class=\"form__header\">\n <h2 class=\"form__title\">{{ configuration().formName }}</h2>\n </div>\n\n @if (programEntryFormMetaData(); as meta) {\n\n @if (meta.programStageSections?.length) {\n @for (section of meta.programStageSections; track section?.id ?? $index) {\n <section class=\"form__section\">\n @if (section?.name) {\n <div class=\"form__field-group-name\">\n {{ section.name }}\n </div>\n }\n\n <div class=\"form__section-content\">\n @if (section.formFields?.length) {\n @for (field of section.formFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n } @else {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n </div>\n </section>\n } @empty {\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n } @else {\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n\n } @else {\n <div class=\"form__empty\">No metadata available</div>\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n</form> -->\n\n<!-- @if (programEntryFormConfig() && programEntryFormConfig()!.formType === 'EVENT') {\n <form [formGroup]=\"form()\" class=\"form {{ configuration().directionClassName }}\">\n <div class=\"form__header\">\n <h2 class=\"form__title\">{{ configuration().formName }}</h2>\n </div>\n\n @if (programEntryFormMetaData(); as meta) {\n @if (meta.programStageSections?.length) {\n @for (section of meta.programStageSections; track section?.id ?? $index) {\n <section class=\"form__section\">\n @if (section?.name) {\n @if (collapsibleSections()) {\n <button\n type=\"button\"\n class=\"form__section-toggle\"\n (click)=\"openSection(section, $index)\"\n [attr.aria-expanded]=\"isSectionOpen(section, $index)\"\n >\n <span class=\"form__section-title\">{{ section.name }}</span>\n <span\n class=\"form__chevron\"\n [class.form__chevron--open]=\"isSectionOpen(section, $index)\"\n ></span>\n </button>\n } @else {\n <div class=\"form__field-group-name\">\n {{ section.name }}\n </div>\n }\n }\n\n @if (!collapsibleSections() || isSectionOpen(section, $index)) {\n <div class=\"form__section-content\">\n @if (section.formFields?.length) {\n @for (field of section.formFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n } @else {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n </div>\n }\n </section>\n } @empty {\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n } @else {\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n\n } @else {\n <div class=\"form__empty\">No metadata available</div>\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n </form>\n} @else if (programEntryFormConfig() && programEntryFormConfig()!.formType === 'TRACKER') {\n <form [formGroup]=\"form()\" class=\"form {{ configuration().directionClassName }}\">\n <div class=\"form__header\">\n <h2 class=\"form__title\">{{ configuration().formName }}</h2>\n </div>\n\n @if (programEntryFormMetaData(); as meta) {\n @if (meta.sections?.length) {\n @for (section of meta.sections; track section?.id ?? $index) {\n <section class=\"form__section\">\n @if (section?.name) {\n @if (collapsibleSections()) {\n <button\n type=\"button\"\n class=\"form__section-toggle\"\n (click)=\"openSection(section, $index)\"\n [attr.aria-expanded]=\"isSectionOpen(section, $index)\"\n >\n <span class=\"form__section-title\">{{ section.name }}</span>\n <span\n class=\"form__chevron\"\n [class.form__chevron--open]=\"isSectionOpen(section, $index)\"\n ></span>\n </button>\n } @else {\n <div class=\"form__field-group-name\">\n {{ section.name }}\n </div>\n }\n }\n \n @if (!collapsibleSections() || isSectionOpen(section, $index)) {\n <div class=\"form__section-content\">\n \n @if (section.formFields?.length) {\n \n @for (field of section.formFields; track field?.id ?? $index) {\n <div>\n </div>\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n } @else {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n </div>\n }\n </section>\n } @empty {\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n } @else {\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n\n } @else {\n <div class=\"form__empty\">No metadata available</div>\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n </form>\n} @else {\n <form [formGroup]=\"form()\" class=\"{{ configuration().directionClassName }}\">\n <div class=\"form-name\">\n <h2>{{ configuration().formName }}</h2>\n </div>\n\n <div>\n {{ formMetaData().sections }}\n </div>\n <div\n *ngFor=\"let field of sanitizedFields\"\n class=\"form-field-{{ configuration().direction }}\"\n >\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n </form>\n} -->\n\n@if (programEntryFormConfig() && programEntryFormConfig()!.formType === 'EVENT')\n{\n<form\n [formGroup]=\"form()\"\n class=\"form {{ configuration().directionClassName }}\"\n>\n <div class=\"form__header\">\n <h2 class=\"form__title\">{{ configuration().formName }}</h2>\n </div>\n\n @if (programEntryFormMetaData(); as meta) { @if\n (meta?.programStageSections?.length) { @for (section of\n meta?.programStageSections; track section?.id ?? $index) { @let sectionId =\n 'section-' + (section?.id ?? $index); @let descId = sectionId + '-desc'; @let\n desc = section?.description; @let hasDesc = !!desc;\n\n <section class=\"form__section\" [attr.data-section-id]=\"sectionId\">\n @if (section?.name) { @if (collapsibleSections()) {\n <button\n type=\"button\"\n class=\"form__section-toggle\"\n (click)=\"openSection(section, $index)\"\n [attr.aria-expanded]=\"isSectionOpen(section, $index)\"\n [attr.aria-controls]=\"sectionId\"\n [attr.aria-describedby]=\"\n hasDesc && isSectionOpen(section, $index) ? descId : null\n \"\n >\n <span class=\"form__section-title\">{{ section.name }}</span>\n <span\n class=\"form__chevron\"\n [class.form__chevron--open]=\"isSectionOpen(section, $index)\"\n ></span>\n </button>\n } @else {\n <div class=\"form__field-group-name\">{{ section.name }} - {{ descId }}</div>\n @if (hasDesc) {\n <p class=\"form__section-description\" [id]=\"descId\">\n {{ desc }}\n </p>\n } } } @if (!collapsibleSections() || isSectionOpen(section, $index)) { @if\n (collapsibleSections() && hasDesc) {\n <p class=\"form__section-description\" [id]=\"descId\">\n {{ desc }}\n </p>\n }\n\n <div class=\"form__section-content\" [id]=\"sectionId\">\n @if (section.formFields?.length) { @for (field of\n getVisibleSectionFields(section); track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields available for this section.</div>\n } } @else {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n </div>\n }\n </section>\n } @empty { @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n } } } @else { @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <div>\n {{ sanitizedFields | json }}\n </div>\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n } } } @else {\n <div class=\"form__empty\">No metadata available</div>\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n } }\n</form>\n} @else if (programEntryFormConfig() && programEntryFormConfig()!.formType ===\n'TRACKER') {\n<form\n [formGroup]=\"form()\"\n class=\"form {{ configuration().directionClassName }}\"\n>\n <div class=\"form__header\">\n <h2 class=\"form__title\">{{ configuration().formName }}</h2>\n </div>\n\n @if (programEntryFormMetaData(); as meta) { @if (meta?.sections?.length) {\n @for (section of meta?.sections; track section?.id ?? $index) { @let sectionId\n = 'section-' + (section?.id ?? $index); @let descId = sectionId + '-desc';\n @let desc = section?.description; @let hasDesc = !!desc;\n\n <section class=\"form__section\" [attr.data-section-id]=\"sectionId\">\n @if (section?.name) { @if (collapsibleSections()) {\n <button\n type=\"button\"\n class=\"form__section-toggle\"\n (click)=\"openSection(section, $index)\"\n [attr.aria-expanded]=\"isSectionOpen(section, $index)\"\n [attr.aria-controls]=\"sectionId\"\n [attr.aria-describedby]=\"\n hasDesc && isSectionOpen(section, $index) ? descId : null\n \"\n >\n <span class=\"form__section-title\">{{ section.name }}</span>\n <span\n class=\"form__chevron\"\n [class.form__chevron--open]=\"isSectionOpen(section, $index)\"\n ></span>\n </button>\n } @else {\n <div class=\"form__field-group-name\">\n {{ section.name }}\n </div>\n @if (hasDesc) {\n <p class=\"form__section-description\" [id]=\"descId\">\n {{ desc }}\n </p>\n } } } @if (!collapsibleSections() || isSectionOpen(section, $index)) { @if\n (collapsibleSections() && hasDesc) {\n <p class=\"form__section-description\" [id]=\"descId\">\n {{ desc }}\n </p>\n }\n <div class=\"form__section-content\" [id]=\"sectionId\">\n @if (section.formFields?.length) { @for (field of\n getVisibleSectionFields(section); track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields available for this section.</div>\n } } @else {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n </div>\n }\n </section>\n } @empty { @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n } } } @else { @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n } } } @else {\n <div class=\"form__empty\">No metadata available</div>\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n } }\n</form>\n} @else {\n<!-- <form [formGroup]=\"form()\" class=\"{{ configuration().directionClassName }}\">\n <div class=\"form-name\">\n <h2>{{ configuration().formName }}</h2>\n </div>\n\n <div *ngFor=\"let field of sanitizedFields\" class=\"form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n </form> -->\n<form [formGroup]=\"form()\" [class]=\"configuration().directionClassName\">\n @if (configuration()?.formName) {\n <div class=\"form-name\">\n <h2>{{ configuration()?.formName }}</h2>\n </div>\n } @if (sanitizedFields?.length) { @for (field of sanitizedFields; track\n field?.id ?? $index) {\n <div class=\"form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } } @else {\n <div class=\"text-sm text-gray-500\">No fields to display.</div>\n }\n</form>\n}\n", styles: ["@charset \"UTF-8\";.form__section-toggle{width:100%;display:flex;align-items:center;justify-content:space-between;font-size:15px;font-weight:600;padding:14px 16px 16px;background-color:#e8edf2;color:#374151;border:0;cursor:pointer;text-align:left}.form__section-toggle:focus{outline:2px solid #93c5fd;outline-offset:2px}.form__section-title{pointer-events:none}.form__chevron{width:10px;height:10px;display:inline-block;margin-left:12px;-webkit-mask-image:linear-gradient(#000,#000);mask-image:linear-gradient(#000,#000);border-right:2px solid currentColor;border-bottom:2px solid currentColor;transform:rotate(-45deg);transition:transform .12s ease-in-out}.form__chevron--open{transform:rotate(45deg)}.form__section{border:1px solid #eee;margin-bottom:16px;background-color:#fff}.form__field-group-name{display:inline-flex;font-size:14px;font-weight:600;padding:8px 16px;background-color:#e8edf2;color:#374151}.form__section-content{padding:16px}.form__section-description{margin:5px 5px 15px;font-size:15px;line-height:1.5;color:#4b5563;white-space:pre-line}.form__section-description:before{content:\"\";display:inline-block;width:4px;height:.9em;margin-right:8px;vertical-align:-2px;background-color:#cbd5e1;border-radius:2px}\n"], dependencies: [{ kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: FormFieldComponent, selector: "ng-dhis2-ui-form-field", inputs: ["field", "fieldConfig", "form", "isCheckBoxButton", "fieldClass", "programRuleActions", "dataEntities", "minDate", "maxDate", "dataId", "customOrgUnitRoots", "program"], outputs: ["fieldUpdate", "immediateFieldUpdate", "runtimeOptionChange"] }, { kind: "pipe", type: i1.JsonPipe, name: "json" }] }); }
9453
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.3", type: FormComponent, isStandalone: false, selector: "ng-dhis2-ui-form", inputs: { programEntryFormConfig: { classPropertyName: "programEntryFormConfig", publicName: "programEntryFormConfig", isSignal: true, isRequired: false, transformFunction: null }, formConfig: { classPropertyName: "formConfig", publicName: "formConfig", isSignal: true, isRequired: false, transformFunction: null }, fields: { classPropertyName: "fields", publicName: "fields", isSignal: true, isRequired: true, transformFunction: null }, form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: true, transformFunction: null }, isFormHorizontal: { classPropertyName: "isFormHorizontal", publicName: "isFormHorizontal", isSignal: true, isRequired: false, transformFunction: null }, showSaveButton: { classPropertyName: "showSaveButton", publicName: "showSaveButton", isSignal: true, isRequired: false, transformFunction: null }, fieldsData: { classPropertyName: "fieldsData", publicName: "fieldsData", isSignal: true, isRequired: false, transformFunction: null }, formMetaData: { classPropertyName: "formMetaData", publicName: "formMetaData", isSignal: true, isRequired: false, transformFunction: null }, programEntryFormMetaData: { classPropertyName: "programEntryFormMetaData", publicName: "programEntryFormMetaData", isSignal: true, isRequired: false, transformFunction: null }, fieldClass: { classPropertyName: "fieldClass", publicName: "fieldClass", isSignal: true, isRequired: false, transformFunction: null }, shouldRenderAsCheckBoxesButton: { classPropertyName: "shouldRenderAsCheckBoxesButton", publicName: "shouldRenderAsCheckBoxesButton", isSignal: true, isRequired: false, transformFunction: null }, programRuleActions: { classPropertyName: "programRuleActions", publicName: "programRuleActions", isSignal: true, isRequired: false, transformFunction: null }, dataEntities: { classPropertyName: "dataEntities", publicName: "dataEntities", isSignal: true, isRequired: false, transformFunction: null }, dataId: { classPropertyName: "dataId", publicName: "dataId", isSignal: true, isRequired: false, transformFunction: null }, customOrgUnitRoots: { classPropertyName: "customOrgUnitRoots", publicName: "customOrgUnitRoots", isSignal: true, isRequired: false, transformFunction: null }, optionCascadeConfigs: { classPropertyName: "optionCascadeConfigs", publicName: "optionCascadeConfigs", isSignal: true, isRequired: false, transformFunction: null }, coordinatePickerGeoConfig: { classPropertyName: "coordinatePickerGeoConfig", publicName: "coordinatePickerGeoConfig", isSignal: true, isRequired: false, transformFunction: null }, program: { classPropertyName: "program", publicName: "program", isSignal: true, isRequired: false, transformFunction: null }, collapsibleSections: { classPropertyName: "collapsibleSections", publicName: "collapsibleSections", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { formUpdate: "formUpdate", formValidityUpdate: "formValidityUpdate" }, viewQueries: [{ propertyName: "fieldComponents", predicate: FormFieldComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<!-- <form [formGroup]=\"form()\" class=\"{{ configuration().directionClassName }}\">\n <div class=\"form-name\">\n <h2>{{ configuration().formName }}</h2>\n </div>\n\n <div>\n {{ formMetaData().sections }}\n </div>\n <div\n *ngFor=\"let field of sanitizedFields\"\n class=\"form-field-{{ configuration().direction }}\"\n >\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [program]=\"program()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n</form> -->\n\n<!-- <form [formGroup]=\"form()\" class=\"form {{ configuration().directionClassName }}\">\n <div class=\"form__header\">\n <h2 class=\"form__title\">{{ configuration().formName }}</h2>\n </div>\n\n @if (programEntryFormMetaData(); as meta) {\n\n @if (meta.programStageSections?.length) {\n @for (section of meta.programStageSections; track section?.id ?? $index) {\n <section class=\"form__section\">\n @if (section?.name) {\n <div class=\"form__field-group-name\">\n {{ section.name }}\n </div>\n }\n\n <div class=\"form__section-content\">\n @if (section.formFields?.length) {\n @for (field of section.formFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n } @else {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n </div>\n </section>\n } @empty {\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n } @else {\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n\n } @else {\n <div class=\"form__empty\">No metadata available</div>\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n</form> -->\n\n<!-- @if (programEntryFormConfig() && programEntryFormConfig()!.formType === 'EVENT') {\n <form [formGroup]=\"form()\" class=\"form {{ configuration().directionClassName }}\">\n <div class=\"form__header\">\n <h2 class=\"form__title\">{{ configuration().formName }}</h2>\n </div>\n\n @if (programEntryFormMetaData(); as meta) {\n @if (meta.programStageSections?.length) {\n @for (section of meta.programStageSections; track section?.id ?? $index) {\n <section class=\"form__section\">\n @if (section?.name) {\n @if (collapsibleSections()) {\n <button\n type=\"button\"\n class=\"form__section-toggle\"\n (click)=\"openSection(section, $index)\"\n [attr.aria-expanded]=\"isSectionOpen(section, $index)\"\n >\n <span class=\"form__section-title\">{{ section.name }}</span>\n <span\n class=\"form__chevron\"\n [class.form__chevron--open]=\"isSectionOpen(section, $index)\"\n ></span>\n </button>\n } @else {\n <div class=\"form__field-group-name\">\n {{ section.name }}\n </div>\n }\n }\n\n @if (!collapsibleSections() || isSectionOpen(section, $index)) {\n <div class=\"form__section-content\">\n @if (section.formFields?.length) {\n @for (field of section.formFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n } @else {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n </div>\n }\n </section>\n } @empty {\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n } @else {\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n\n } @else {\n <div class=\"form__empty\">No metadata available</div>\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n </form>\n} @else if (programEntryFormConfig() && programEntryFormConfig()!.formType === 'TRACKER') {\n <form [formGroup]=\"form()\" class=\"form {{ configuration().directionClassName }}\">\n <div class=\"form__header\">\n <h2 class=\"form__title\">{{ configuration().formName }}</h2>\n </div>\n\n @if (programEntryFormMetaData(); as meta) {\n @if (meta.sections?.length) {\n @for (section of meta.sections; track section?.id ?? $index) {\n <section class=\"form__section\">\n @if (section?.name) {\n @if (collapsibleSections()) {\n <button\n type=\"button\"\n class=\"form__section-toggle\"\n (click)=\"openSection(section, $index)\"\n [attr.aria-expanded]=\"isSectionOpen(section, $index)\"\n >\n <span class=\"form__section-title\">{{ section.name }}</span>\n <span\n class=\"form__chevron\"\n [class.form__chevron--open]=\"isSectionOpen(section, $index)\"\n ></span>\n </button>\n } @else {\n <div class=\"form__field-group-name\">\n {{ section.name }}\n </div>\n }\n }\n \n @if (!collapsibleSections() || isSectionOpen(section, $index)) {\n <div class=\"form__section-content\">\n \n @if (section.formFields?.length) {\n \n @for (field of section.formFields; track field?.id ?? $index) {\n <div>\n </div>\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n } @else {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n </div>\n }\n </section>\n } @empty {\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n } @else {\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n\n } @else {\n <div class=\"form__empty\">No metadata available</div>\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n </form>\n} @else {\n <form [formGroup]=\"form()\" class=\"{{ configuration().directionClassName }}\">\n <div class=\"form-name\">\n <h2>{{ configuration().formName }}</h2>\n </div>\n\n <div>\n {{ formMetaData().sections }}\n </div>\n <div\n *ngFor=\"let field of sanitizedFields\"\n class=\"form-field-{{ configuration().direction }}\"\n >\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n </form>\n} -->\n<!-- \n@if (programEntryFormConfig() && programEntryFormConfig()!.formType === 'EVENT')\n{\n<form\n [formGroup]=\"form()\"\n class=\"form {{ configuration().directionClassName }}\"\n>\n <div class=\"form__header\">\n <h2 class=\"form__title\">{{ configuration().formName }}</h2>\n </div>\n\n @if (programEntryFormMetaData(); as meta) { @if\n (meta?.programStageSections?.length) { @for (section of\n meta?.programStageSections; track section?.id ?? $index) { @let sectionId =\n 'section-' + (section?.id ?? $index); @let descId = sectionId + '-desc'; @let\n desc = section?.description; @let hasDesc = !!desc;\n\n <section class=\"form__section\" [attr.data-section-id]=\"sectionId\">\n @if (section?.name) { @if (collapsibleSections()) {\n <button\n type=\"button\"\n class=\"form__section-toggle\"\n (click)=\"openSection(section, $index)\"\n [attr.aria-expanded]=\"isSectionOpen(section, $index)\"\n [attr.aria-controls]=\"sectionId\"\n [attr.aria-describedby]=\"\n hasDesc && isSectionOpen(section, $index) ? descId : null\n \"\n >\n <span class=\"form__section-title\">{{ section.name }}</span>\n <span\n class=\"form__chevron\"\n [class.form__chevron--open]=\"isSectionOpen(section, $index)\"\n ></span>\n </button>\n } @else {\n <div class=\"form__field-group-name\">{{ section.name }} - {{ descId }}</div>\n @if (hasDesc) {\n <p class=\"form__section-description\" [id]=\"descId\">\n {{ desc }}\n </p>\n } } } @if (!collapsibleSections() || isSectionOpen(section, $index)) { @if\n (collapsibleSections() && hasDesc) {\n <p class=\"form__section-description\" [id]=\"descId\">\n {{ desc }}\n </p>\n }\n\n <div class=\"form__section-content\" [id]=\"sectionId\">\n @if (section.formFields?.length) { @for (field of\n getVisibleSectionFields(section); track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n \n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [optionCascadeConfigs]=\"optionCascadeConfigs()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields available for this section.</div>\n } } @else {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n </div>\n }\n </section>\n } @empty { @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n } } } @else { @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n } } } @else {\n <div class=\"form__empty\">No metadata available</div>\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n } }\n</form>\n} @else if (programEntryFormConfig() && programEntryFormConfig()!.formType ===\n'TRACKER') {\n<form\n [formGroup]=\"form()\"\n class=\"form {{ configuration().directionClassName }}\"\n>\n <div class=\"form__header\">\n <h2 class=\"form__title\">{{ configuration().formName }}</h2>\n </div>\n\n @if (programEntryFormMetaData(); as meta) { @if (meta?.sections?.length) {\n @for (section of meta?.sections; track section?.id ?? $index) { @let sectionId\n = 'section-' + (section?.id ?? $index); @let descId = sectionId + '-desc';\n @let desc = section?.description; @let hasDesc = !!desc;\n\n <section class=\"form__section\" [attr.data-section-id]=\"sectionId\">\n @if (section?.name) { @if (collapsibleSections()) {\n <button\n type=\"button\"\n class=\"form__section-toggle\"\n (click)=\"openSection(section, $index)\"\n [attr.aria-expanded]=\"isSectionOpen(section, $index)\"\n [attr.aria-controls]=\"sectionId\"\n [attr.aria-describedby]=\"\n hasDesc && isSectionOpen(section, $index) ? descId : null\n \"\n >\n <span class=\"form__section-title\">{{ section.name }}</span>\n <span\n class=\"form__chevron\"\n [class.form__chevron--open]=\"isSectionOpen(section, $index)\"\n ></span>\n </button>\n } @else {\n <div class=\"form__field-group-name\">\n {{ section.name }}\n </div>\n @if (hasDesc) {\n <p class=\"form__section-description\" [id]=\"descId\">\n {{ desc }}\n </p>\n } } } @if (!collapsibleSections() || isSectionOpen(section, $index)) { @if\n (collapsibleSections() && hasDesc) {\n <p class=\"form__section-description\" [id]=\"descId\">\n {{ desc }}\n </p>\n }\n <div class=\"form__section-content\" [id]=\"sectionId\">\n @if (section.formFields?.length) { @for (field of\n getVisibleSectionFields(section); track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields available for this section.</div>\n } } @else {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n </div>\n }\n </section>\n } @empty { @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n } } } @else { @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n } } } @else {\n <div class=\"form__empty\">No metadata available</div>\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n } }\n</form>\n} @else {\n<form [formGroup]=\"form()\" [class]=\"configuration().directionClassName\">\n @if (configuration()?.formName) {\n <div class=\"form-name\">\n <h2>{{ configuration()?.formName }}</h2>\n </div>\n } @if (sanitizedFields?.length) { @for (field of sanitizedFields; track\n field?.id ?? $index) {\n <div class=\"form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } } @else {\n <div class=\"text-sm text-gray-500\">No fields to display.</div>\n }\n</form>\n} -->\n\n@let entryFormConfig = programEntryFormConfig();\n@let entryFormMeta = programEntryFormMetaData();\n@let uiConfig = configuration();\n@let formGroupValue = form();\n\n@let isSectionsCollapsible = collapsibleSections();\n\n@let dataEntitiesValue = dataEntities();\n@let dataEntityId = dataId();\n@let orgUnitRootIds = customOrgUnitRoots();\n\n@let cascadeConfigMap = optionCascadeConfigMap();\n@let cascadeConfigs = optionCascadeConfigs();\n\n@let ruleActionList = programRuleActions();\n@let renderAsCheckboxButtons = shouldRenderAsCheckBoxesButton();\n\n@let entryFormCoordinatePickerGeoConfig = coordinatePickerGeoConfig();\n@let entryFormFieldControlKeyById = fieldControlKeyById();\n\n@if (entryFormConfig?.formType === 'EVENT') {\n <form [formGroup]=\"formGroupValue\" class=\"form {{ uiConfig.directionClassName }}\">\n <div class=\"form__header\">\n <h2 class=\"form__title\">{{ uiConfig.formName }}</h2>\n </div>\n\n @if (entryFormMeta?.programStageSections?.length) {\n @for (stageSection of entryFormMeta.programStageSections; track stageSection?.id ?? $index) {\n @let sectionKey = stageSection?.id ?? $index;\n @let sectionDomId = 'section-' + sectionKey;\n @let descriptionDomId = sectionDomId + '-desc';\n @let sectionDescription = stageSection?.description;\n @let hasDescription = !!sectionDescription;\n\n <section class=\"form__section\" [attr.data-section-id]=\"sectionDomId\">\n @if (stageSection?.name) {\n @if (isSectionsCollapsible) {\n @let isOpen = isSectionOpen(stageSection, $index);\n\n <button\n type=\"button\"\n class=\"form__section-toggle\"\n (click)=\"openSection(stageSection, $index)\"\n [attr.aria-expanded]=\"isOpen\"\n [attr.aria-controls]=\"sectionDomId\"\n [attr.aria-describedby]=\"hasDescription && isOpen ? descriptionDomId : null\"\n >\n <span class=\"form__section-title\">{{ stageSection.name }}</span>\n <span class=\"form__chevron\" [class.form__chevron--open]=\"isOpen\"></span>\n </button>\n } @else {\n <div class=\"form__field-group-name\">{{ stageSection.name }}</div>\n @if (hasDescription) {\n <p class=\"form__section-description\" [id]=\"descriptionDomId\">\n {{ sectionDescription }}\n </p>\n }\n }\n }\n\n @let isOpen = !isSectionsCollapsible || isSectionOpen(stageSection, $index);\n @if (isOpen) {\n @if (isSectionsCollapsible && hasDescription) {\n <p class=\"form__section-description\" [id]=\"descriptionDomId\">\n {{ sectionDescription }}\n </p>\n }\n\n <div class=\"form__section-content\" [id]=\"sectionDomId\">\n @if (stageSection?.formFields?.length) {\n @for (visibleField of getVisibleSectionFields(stageSection); track visibleField?.id ?? $index) {\n <div class=\"form__field form-field-{{ uiConfig.direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"visibleField\"\n [fieldConfig]=\"uiConfig.fieldConfig\"\n [form]=\"formGroupValue\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntitiesValue\"\n [dataId]=\"dataEntityId\"\n [customOrgUnitRoots]=\"orgUnitRootIds\"\n [optionCascadeConfigMap]=\"cascadeConfigMap\"\n [optionCascadeConfigs]=\"cascadeConfigs\"\n [coordinatePickerGeoConfig]=\"entryFormCoordinatePickerGeoConfig\"\n [fieldControlKeyById]=\"entryFormFieldControlKeyById\"\n [programRuleActions]=\"ruleActionList\"\n [isCheckBoxButton]=\"renderAsCheckboxButtons\"\n (fieldUpdate)=\"onFieldUpdate($event, visibleField)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n } @else {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n </div>\n }\n </section>\n } @empty {\n @for (fallbackField of sanitizedFields; track fallbackField?.id ?? $index) {\n <div class=\"form__field form-field-{{ uiConfig.direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"fallbackField\"\n [fieldConfig]=\"uiConfig.fieldConfig\"\n [form]=\"formGroupValue\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntitiesValue\"\n [dataId]=\"dataEntityId\"\n [customOrgUnitRoots]=\"orgUnitRootIds\"\n [optionCascadeConfigMap]=\"cascadeConfigMap\"\n [coordinatePickerGeoConfig]=\"entryFormCoordinatePickerGeoConfig\"\n [fieldControlKeyById]=\"entryFormFieldControlKeyById\"\n [programRuleActions]=\"ruleActionList\"\n [isCheckBoxButton]=\"renderAsCheckboxButtons\"\n (fieldUpdate)=\"onFieldUpdate($event, fallbackField)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n } @else {\n @for (fallbackField of sanitizedFields; track fallbackField?.id ?? $index) {\n <div class=\"form__field form-field-{{ uiConfig.direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"fallbackField\"\n [fieldConfig]=\"uiConfig.fieldConfig\"\n [form]=\"formGroupValue\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntitiesValue\"\n [dataId]=\"dataEntityId\"\n [customOrgUnitRoots]=\"orgUnitRootIds\"\n [optionCascadeConfigMap]=\"cascadeConfigMap\"\n [coordinatePickerGeoConfig]=\"entryFormCoordinatePickerGeoConfig\"\n [fieldControlKeyById]=\"entryFormFieldControlKeyById\"\n [programRuleActions]=\"ruleActionList\"\n [isCheckBoxButton]=\"renderAsCheckboxButtons\"\n (fieldUpdate)=\"onFieldUpdate($event, fallbackField)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n </form>\n\n} @else if (entryFormConfig?.formType === 'TRACKER') {\n\n <form [formGroup]=\"formGroupValue\" class=\"form {{ uiConfig.directionClassName }}\">\n <div class=\"form__header\">\n <h2 class=\"form__title\">{{ uiConfig.formName }}</h2>\n </div>\n\n @if (entryFormMeta?.sections?.length) {\n @for (teiSection of entryFormMeta.sections; track teiSection?.id ?? $index) {\n @let sectionKey = teiSection?.id ?? $index;\n @let sectionDomId = 'section-' + sectionKey;\n @let descriptionDomId = sectionDomId + '-desc';\n @let sectionDescription = teiSection?.description;\n @let hasDescription = !!sectionDescription;\n\n <section class=\"form__section\" [attr.data-section-id]=\"sectionDomId\">\n @if (teiSection?.name) {\n @if (isSectionsCollapsible) {\n @let isOpen = isSectionOpen(teiSection, $index);\n\n <button\n type=\"button\"\n class=\"form__section-toggle\"\n (click)=\"openSection(teiSection, $index)\"\n [attr.aria-expanded]=\"isOpen\"\n [attr.aria-controls]=\"sectionDomId\"\n [attr.aria-describedby]=\"hasDescription && isOpen ? descriptionDomId : null\"\n >\n <span class=\"form__section-title\">{{ teiSection.name }}</span>\n <span class=\"form__chevron\" [class.form__chevron--open]=\"isOpen\"></span>\n </button>\n } @else {\n <div class=\"form__field-group-name\">{{ teiSection.name }}</div>\n @if (hasDescription) {\n <p class=\"form__section-description\" [id]=\"descriptionDomId\">\n {{ sectionDescription }}\n </p>\n }\n }\n }\n\n @let isOpen = !isSectionsCollapsible || isSectionOpen(teiSection, $index);\n @if (isOpen) {\n @if (isSectionsCollapsible && hasDescription) {\n <p class=\"form__section-description\" [id]=\"descriptionDomId\">\n {{ sectionDescription }}\n </p>\n }\n\n <div class=\"form__section-content\" [id]=\"sectionDomId\">\n @if (teiSection?.formFields?.length) {\n @for (visibleField of getVisibleSectionFields(teiSection); track visibleField?.id ?? $index) {\n <div class=\"form__field form-field-{{ uiConfig.direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"visibleField\"\n [fieldConfig]=\"uiConfig.fieldConfig\"\n [form]=\"formGroupValue\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntitiesValue\"\n [dataId]=\"dataEntityId\"\n [customOrgUnitRoots]=\"orgUnitRootIds\"\n [optionCascadeConfigMap]=\"cascadeConfigMap\"\n [coordinatePickerGeoConfig]=\"entryFormCoordinatePickerGeoConfig\"\n [fieldControlKeyById]=\"entryFormFieldControlKeyById\"\n [programRuleActions]=\"ruleActionList\"\n [isCheckBoxButton]=\"renderAsCheckboxButtons\"\n (fieldUpdate)=\"onFieldUpdate($event, visibleField)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n } @else {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n </div>\n }\n </section>\n } @empty {\n @for (fallbackField of sanitizedFields; track fallbackField?.id ?? $index) {\n <div class=\"form__field form-field-{{ uiConfig.direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"fallbackField\"\n [fieldConfig]=\"uiConfig.fieldConfig\"\n [form]=\"formGroupValue\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntitiesValue\"\n [dataId]=\"dataEntityId\"\n [customOrgUnitRoots]=\"orgUnitRootIds\"\n [optionCascadeConfigMap]=\"cascadeConfigMap\"\n [coordinatePickerGeoConfig]=\"entryFormCoordinatePickerGeoConfig\"\n [fieldControlKeyById]=\"entryFormFieldControlKeyById\"\n [programRuleActions]=\"ruleActionList\"\n [isCheckBoxButton]=\"renderAsCheckboxButtons\"\n (fieldUpdate)=\"onFieldUpdate($event, fallbackField)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n } @else {\n <div class=\"form__empty\">No metadata available</div>\n @for (fallbackField of sanitizedFields; track fallbackField?.id ?? $index) {\n <div class=\"form__field form-field-{{ uiConfig.direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"fallbackField\"\n [fieldConfig]=\"uiConfig.fieldConfig\"\n [form]=\"formGroupValue\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntitiesValue\"\n [dataId]=\"dataEntityId\"\n [customOrgUnitRoots]=\"orgUnitRootIds\"\n [optionCascadeConfigMap]=\"cascadeConfigMap\"\n [coordinatePickerGeoConfig]=\"entryFormCoordinatePickerGeoConfig\"\n [fieldControlKeyById]=\"entryFormFieldControlKeyById\"\n [programRuleActions]=\"ruleActionList\"\n [isCheckBoxButton]=\"renderAsCheckboxButtons\"\n (fieldUpdate)=\"onFieldUpdate($event, fallbackField)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n </form>\n\n} @else {\n\n <form [formGroup]=\"formGroupValue\" [class]=\"uiConfig.directionClassName\">\n @if (uiConfig?.formName) {\n <div class=\"form-name\">\n <h2>{{ uiConfig.formName }}</h2>\n </div>\n }\n\n @if (sanitizedFields?.length) {\n @for (fallbackField of sanitizedFields; track fallbackField?.id ?? $index) {\n <div class=\"form-field-{{ uiConfig.direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"fallbackField\"\n [fieldConfig]=\"uiConfig.fieldConfig\"\n [form]=\"formGroupValue\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntitiesValue\"\n [dataId]=\"dataEntityId\"\n [customOrgUnitRoots]=\"orgUnitRootIds\"\n [optionCascadeConfigMap]=\"cascadeConfigMap\"\n [coordinatePickerGeoConfig]=\"entryFormCoordinatePickerGeoConfig\"\n [fieldControlKeyById]=\"entryFormFieldControlKeyById\"\n [programRuleActions]=\"ruleActionList\"\n [isCheckBoxButton]=\"renderAsCheckboxButtons\"\n (fieldUpdate)=\"onFieldUpdate($event, fallbackField)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n }\n } @else {\n <div class=\"text-sm text-gray-500\">No fields to display.</div>\n }\n </form>\n\n}\n\n", styles: ["@charset \"UTF-8\";.form__section-toggle{width:100%;display:flex;align-items:center;justify-content:space-between;font-size:15px;font-weight:600;padding:14px 16px 16px;background-color:#e8edf2;color:#374151;border:0;cursor:pointer;text-align:left}.form__section-toggle:focus{outline:2px solid #93c5fd;outline-offset:2px}.form__section-title{pointer-events:none}.form__chevron{width:10px;height:10px;display:inline-block;margin-left:12px;-webkit-mask-image:linear-gradient(#000,#000);mask-image:linear-gradient(#000,#000);border-right:2px solid currentColor;border-bottom:2px solid currentColor;transform:rotate(-45deg);transition:transform .12s ease-in-out}.form__chevron--open{transform:rotate(45deg)}.form__section{border:1px solid #eee;margin-bottom:16px;background-color:#fff}.form__field-group-name{display:inline-flex;font-size:14px;font-weight:600;padding:8px 16px;background-color:#e8edf2;color:#374151}.form__section-content{padding:16px}.form__section-description{margin:5px 5px 15px;font-size:15px;line-height:1.5;color:#4b5563;white-space:pre-line}.form__section-description:before{content:\"\";display:inline-block;width:4px;height:.9em;margin-right:8px;vertical-align:-2px;background-color:#cbd5e1;border-radius:2px}\n"], dependencies: [{ kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: FormFieldComponent, selector: "ng-dhis2-ui-form-field", inputs: ["field", "fieldConfig", "form", "isCheckBoxButton", "fieldClass", "programRuleActions", "dataEntities", "minDate", "maxDate", "dataId", "customOrgUnitRoots", "program", "optionCascadeConfigs", "optionCascadeConfigMap", "coordinatePickerGeoConfig", "fieldControlKeyById"], outputs: ["fieldUpdate", "immediateFieldUpdate", "runtimeOptionChange"] }] }); }
7696
9454
  }
7697
9455
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: FormComponent, decorators: [{
7698
9456
  type: Component,
7699
- args: [{ selector: 'ng-dhis2-ui-form', standalone: false, template: "<!-- <form [formGroup]=\"form()\" class=\"{{ configuration().directionClassName }}\">\n <div class=\"form-name\">\n <h2>{{ configuration().formName }}</h2>\n </div>\n\n <div>\n {{ formMetaData().sections }}\n </div>\n <div\n *ngFor=\"let field of sanitizedFields\"\n class=\"form-field-{{ configuration().direction }}\"\n >\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [program]=\"program()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n</form> -->\n\n<!-- <form [formGroup]=\"form()\" class=\"form {{ configuration().directionClassName }}\">\n <div class=\"form__header\">\n <h2 class=\"form__title\">{{ configuration().formName }}</h2>\n </div>\n\n @if (programEntryFormMetaData(); as meta) {\n\n @if (meta.programStageSections?.length) {\n @for (section of meta.programStageSections; track section?.id ?? $index) {\n <section class=\"form__section\">\n @if (section?.name) {\n <div class=\"form__field-group-name\">\n {{ section.name }}\n </div>\n }\n\n <div class=\"form__section-content\">\n @if (section.formFields?.length) {\n @for (field of section.formFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n } @else {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n </div>\n </section>\n } @empty {\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n } @else {\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n\n } @else {\n <div class=\"form__empty\">No metadata available</div>\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n</form> -->\n\n<!-- @if (programEntryFormConfig() && programEntryFormConfig()!.formType === 'EVENT') {\n <form [formGroup]=\"form()\" class=\"form {{ configuration().directionClassName }}\">\n <div class=\"form__header\">\n <h2 class=\"form__title\">{{ configuration().formName }}</h2>\n </div>\n\n @if (programEntryFormMetaData(); as meta) {\n @if (meta.programStageSections?.length) {\n @for (section of meta.programStageSections; track section?.id ?? $index) {\n <section class=\"form__section\">\n @if (section?.name) {\n @if (collapsibleSections()) {\n <button\n type=\"button\"\n class=\"form__section-toggle\"\n (click)=\"openSection(section, $index)\"\n [attr.aria-expanded]=\"isSectionOpen(section, $index)\"\n >\n <span class=\"form__section-title\">{{ section.name }}</span>\n <span\n class=\"form__chevron\"\n [class.form__chevron--open]=\"isSectionOpen(section, $index)\"\n ></span>\n </button>\n } @else {\n <div class=\"form__field-group-name\">\n {{ section.name }}\n </div>\n }\n }\n\n @if (!collapsibleSections() || isSectionOpen(section, $index)) {\n <div class=\"form__section-content\">\n @if (section.formFields?.length) {\n @for (field of section.formFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n } @else {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n </div>\n }\n </section>\n } @empty {\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n } @else {\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n\n } @else {\n <div class=\"form__empty\">No metadata available</div>\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n </form>\n} @else if (programEntryFormConfig() && programEntryFormConfig()!.formType === 'TRACKER') {\n <form [formGroup]=\"form()\" class=\"form {{ configuration().directionClassName }}\">\n <div class=\"form__header\">\n <h2 class=\"form__title\">{{ configuration().formName }}</h2>\n </div>\n\n @if (programEntryFormMetaData(); as meta) {\n @if (meta.sections?.length) {\n @for (section of meta.sections; track section?.id ?? $index) {\n <section class=\"form__section\">\n @if (section?.name) {\n @if (collapsibleSections()) {\n <button\n type=\"button\"\n class=\"form__section-toggle\"\n (click)=\"openSection(section, $index)\"\n [attr.aria-expanded]=\"isSectionOpen(section, $index)\"\n >\n <span class=\"form__section-title\">{{ section.name }}</span>\n <span\n class=\"form__chevron\"\n [class.form__chevron--open]=\"isSectionOpen(section, $index)\"\n ></span>\n </button>\n } @else {\n <div class=\"form__field-group-name\">\n {{ section.name }}\n </div>\n }\n }\n \n @if (!collapsibleSections() || isSectionOpen(section, $index)) {\n <div class=\"form__section-content\">\n \n @if (section.formFields?.length) {\n \n @for (field of section.formFields; track field?.id ?? $index) {\n <div>\n </div>\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n } @else {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n </div>\n }\n </section>\n } @empty {\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n } @else {\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n\n } @else {\n <div class=\"form__empty\">No metadata available</div>\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n </form>\n} @else {\n <form [formGroup]=\"form()\" class=\"{{ configuration().directionClassName }}\">\n <div class=\"form-name\">\n <h2>{{ configuration().formName }}</h2>\n </div>\n\n <div>\n {{ formMetaData().sections }}\n </div>\n <div\n *ngFor=\"let field of sanitizedFields\"\n class=\"form-field-{{ configuration().direction }}\"\n >\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n </form>\n} -->\n\n@if (programEntryFormConfig() && programEntryFormConfig()!.formType === 'EVENT')\n{\n<form\n [formGroup]=\"form()\"\n class=\"form {{ configuration().directionClassName }}\"\n>\n <div class=\"form__header\">\n <h2 class=\"form__title\">{{ configuration().formName }}</h2>\n </div>\n\n @if (programEntryFormMetaData(); as meta) { @if\n (meta?.programStageSections?.length) { @for (section of\n meta?.programStageSections; track section?.id ?? $index) { @let sectionId =\n 'section-' + (section?.id ?? $index); @let descId = sectionId + '-desc'; @let\n desc = section?.description; @let hasDesc = !!desc;\n\n <section class=\"form__section\" [attr.data-section-id]=\"sectionId\">\n @if (section?.name) { @if (collapsibleSections()) {\n <button\n type=\"button\"\n class=\"form__section-toggle\"\n (click)=\"openSection(section, $index)\"\n [attr.aria-expanded]=\"isSectionOpen(section, $index)\"\n [attr.aria-controls]=\"sectionId\"\n [attr.aria-describedby]=\"\n hasDesc && isSectionOpen(section, $index) ? descId : null\n \"\n >\n <span class=\"form__section-title\">{{ section.name }}</span>\n <span\n class=\"form__chevron\"\n [class.form__chevron--open]=\"isSectionOpen(section, $index)\"\n ></span>\n </button>\n } @else {\n <div class=\"form__field-group-name\">{{ section.name }} - {{ descId }}</div>\n @if (hasDesc) {\n <p class=\"form__section-description\" [id]=\"descId\">\n {{ desc }}\n </p>\n } } } @if (!collapsibleSections() || isSectionOpen(section, $index)) { @if\n (collapsibleSections() && hasDesc) {\n <p class=\"form__section-description\" [id]=\"descId\">\n {{ desc }}\n </p>\n }\n\n <div class=\"form__section-content\" [id]=\"sectionId\">\n @if (section.formFields?.length) { @for (field of\n getVisibleSectionFields(section); track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields available for this section.</div>\n } } @else {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n </div>\n }\n </section>\n } @empty { @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n } } } @else { @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <div>\n {{ sanitizedFields | json }}\n </div>\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n } } } @else {\n <div class=\"form__empty\">No metadata available</div>\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n } }\n</form>\n} @else if (programEntryFormConfig() && programEntryFormConfig()!.formType ===\n'TRACKER') {\n<form\n [formGroup]=\"form()\"\n class=\"form {{ configuration().directionClassName }}\"\n>\n <div class=\"form__header\">\n <h2 class=\"form__title\">{{ configuration().formName }}</h2>\n </div>\n\n @if (programEntryFormMetaData(); as meta) { @if (meta?.sections?.length) {\n @for (section of meta?.sections; track section?.id ?? $index) { @let sectionId\n = 'section-' + (section?.id ?? $index); @let descId = sectionId + '-desc';\n @let desc = section?.description; @let hasDesc = !!desc;\n\n <section class=\"form__section\" [attr.data-section-id]=\"sectionId\">\n @if (section?.name) { @if (collapsibleSections()) {\n <button\n type=\"button\"\n class=\"form__section-toggle\"\n (click)=\"openSection(section, $index)\"\n [attr.aria-expanded]=\"isSectionOpen(section, $index)\"\n [attr.aria-controls]=\"sectionId\"\n [attr.aria-describedby]=\"\n hasDesc && isSectionOpen(section, $index) ? descId : null\n \"\n >\n <span class=\"form__section-title\">{{ section.name }}</span>\n <span\n class=\"form__chevron\"\n [class.form__chevron--open]=\"isSectionOpen(section, $index)\"\n ></span>\n </button>\n } @else {\n <div class=\"form__field-group-name\">\n {{ section.name }}\n </div>\n @if (hasDesc) {\n <p class=\"form__section-description\" [id]=\"descId\">\n {{ desc }}\n </p>\n } } } @if (!collapsibleSections() || isSectionOpen(section, $index)) { @if\n (collapsibleSections() && hasDesc) {\n <p class=\"form__section-description\" [id]=\"descId\">\n {{ desc }}\n </p>\n }\n <div class=\"form__section-content\" [id]=\"sectionId\">\n @if (section.formFields?.length) { @for (field of\n getVisibleSectionFields(section); track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields available for this section.</div>\n } } @else {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n </div>\n }\n </section>\n } @empty { @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n } } } @else { @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n } } } @else {\n <div class=\"form__empty\">No metadata available</div>\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n } }\n</form>\n} @else {\n<!-- <form [formGroup]=\"form()\" class=\"{{ configuration().directionClassName }}\">\n <div class=\"form-name\">\n <h2>{{ configuration().formName }}</h2>\n </div>\n\n <div *ngFor=\"let field of sanitizedFields\" class=\"form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n </form> -->\n<form [formGroup]=\"form()\" [class]=\"configuration().directionClassName\">\n @if (configuration()?.formName) {\n <div class=\"form-name\">\n <h2>{{ configuration()?.formName }}</h2>\n </div>\n } @if (sanitizedFields?.length) { @for (field of sanitizedFields; track\n field?.id ?? $index) {\n <div class=\"form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } } @else {\n <div class=\"text-sm text-gray-500\">No fields to display.</div>\n }\n</form>\n}\n", styles: ["@charset \"UTF-8\";.form__section-toggle{width:100%;display:flex;align-items:center;justify-content:space-between;font-size:15px;font-weight:600;padding:14px 16px 16px;background-color:#e8edf2;color:#374151;border:0;cursor:pointer;text-align:left}.form__section-toggle:focus{outline:2px solid #93c5fd;outline-offset:2px}.form__section-title{pointer-events:none}.form__chevron{width:10px;height:10px;display:inline-block;margin-left:12px;-webkit-mask-image:linear-gradient(#000,#000);mask-image:linear-gradient(#000,#000);border-right:2px solid currentColor;border-bottom:2px solid currentColor;transform:rotate(-45deg);transition:transform .12s ease-in-out}.form__chevron--open{transform:rotate(45deg)}.form__section{border:1px solid #eee;margin-bottom:16px;background-color:#fff}.form__field-group-name{display:inline-flex;font-size:14px;font-weight:600;padding:8px 16px;background-color:#e8edf2;color:#374151}.form__section-content{padding:16px}.form__section-description{margin:5px 5px 15px;font-size:15px;line-height:1.5;color:#4b5563;white-space:pre-line}.form__section-description:before{content:\"\";display:inline-block;width:4px;height:.9em;margin-right:8px;vertical-align:-2px;background-color:#cbd5e1;border-radius:2px}\n"] }]
9457
+ args: [{ selector: 'ng-dhis2-ui-form', standalone: false, template: "<!-- <form [formGroup]=\"form()\" class=\"{{ configuration().directionClassName }}\">\n <div class=\"form-name\">\n <h2>{{ configuration().formName }}</h2>\n </div>\n\n <div>\n {{ formMetaData().sections }}\n </div>\n <div\n *ngFor=\"let field of sanitizedFields\"\n class=\"form-field-{{ configuration().direction }}\"\n >\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [program]=\"program()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n</form> -->\n\n<!-- <form [formGroup]=\"form()\" class=\"form {{ configuration().directionClassName }}\">\n <div class=\"form__header\">\n <h2 class=\"form__title\">{{ configuration().formName }}</h2>\n </div>\n\n @if (programEntryFormMetaData(); as meta) {\n\n @if (meta.programStageSections?.length) {\n @for (section of meta.programStageSections; track section?.id ?? $index) {\n <section class=\"form__section\">\n @if (section?.name) {\n <div class=\"form__field-group-name\">\n {{ section.name }}\n </div>\n }\n\n <div class=\"form__section-content\">\n @if (section.formFields?.length) {\n @for (field of section.formFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n } @else {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n </div>\n </section>\n } @empty {\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n } @else {\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n\n } @else {\n <div class=\"form__empty\">No metadata available</div>\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n</form> -->\n\n<!-- @if (programEntryFormConfig() && programEntryFormConfig()!.formType === 'EVENT') {\n <form [formGroup]=\"form()\" class=\"form {{ configuration().directionClassName }}\">\n <div class=\"form__header\">\n <h2 class=\"form__title\">{{ configuration().formName }}</h2>\n </div>\n\n @if (programEntryFormMetaData(); as meta) {\n @if (meta.programStageSections?.length) {\n @for (section of meta.programStageSections; track section?.id ?? $index) {\n <section class=\"form__section\">\n @if (section?.name) {\n @if (collapsibleSections()) {\n <button\n type=\"button\"\n class=\"form__section-toggle\"\n (click)=\"openSection(section, $index)\"\n [attr.aria-expanded]=\"isSectionOpen(section, $index)\"\n >\n <span class=\"form__section-title\">{{ section.name }}</span>\n <span\n class=\"form__chevron\"\n [class.form__chevron--open]=\"isSectionOpen(section, $index)\"\n ></span>\n </button>\n } @else {\n <div class=\"form__field-group-name\">\n {{ section.name }}\n </div>\n }\n }\n\n @if (!collapsibleSections() || isSectionOpen(section, $index)) {\n <div class=\"form__section-content\">\n @if (section.formFields?.length) {\n @for (field of section.formFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n } @else {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n </div>\n }\n </section>\n } @empty {\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n } @else {\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n\n } @else {\n <div class=\"form__empty\">No metadata available</div>\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n </form>\n} @else if (programEntryFormConfig() && programEntryFormConfig()!.formType === 'TRACKER') {\n <form [formGroup]=\"form()\" class=\"form {{ configuration().directionClassName }}\">\n <div class=\"form__header\">\n <h2 class=\"form__title\">{{ configuration().formName }}</h2>\n </div>\n\n @if (programEntryFormMetaData(); as meta) {\n @if (meta.sections?.length) {\n @for (section of meta.sections; track section?.id ?? $index) {\n <section class=\"form__section\">\n @if (section?.name) {\n @if (collapsibleSections()) {\n <button\n type=\"button\"\n class=\"form__section-toggle\"\n (click)=\"openSection(section, $index)\"\n [attr.aria-expanded]=\"isSectionOpen(section, $index)\"\n >\n <span class=\"form__section-title\">{{ section.name }}</span>\n <span\n class=\"form__chevron\"\n [class.form__chevron--open]=\"isSectionOpen(section, $index)\"\n ></span>\n </button>\n } @else {\n <div class=\"form__field-group-name\">\n {{ section.name }}\n </div>\n }\n }\n \n @if (!collapsibleSections() || isSectionOpen(section, $index)) {\n <div class=\"form__section-content\">\n \n @if (section.formFields?.length) {\n \n @for (field of section.formFields; track field?.id ?? $index) {\n <div>\n </div>\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n } @else {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n </div>\n }\n </section>\n } @empty {\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n } @else {\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n\n } @else {\n <div class=\"form__empty\">No metadata available</div>\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n </form>\n} @else {\n <form [formGroup]=\"form()\" class=\"{{ configuration().directionClassName }}\">\n <div class=\"form-name\">\n <h2>{{ configuration().formName }}</h2>\n </div>\n\n <div>\n {{ formMetaData().sections }}\n </div>\n <div\n *ngFor=\"let field of sanitizedFields\"\n class=\"form-field-{{ configuration().direction }}\"\n >\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n </form>\n} -->\n<!-- \n@if (programEntryFormConfig() && programEntryFormConfig()!.formType === 'EVENT')\n{\n<form\n [formGroup]=\"form()\"\n class=\"form {{ configuration().directionClassName }}\"\n>\n <div class=\"form__header\">\n <h2 class=\"form__title\">{{ configuration().formName }}</h2>\n </div>\n\n @if (programEntryFormMetaData(); as meta) { @if\n (meta?.programStageSections?.length) { @for (section of\n meta?.programStageSections; track section?.id ?? $index) { @let sectionId =\n 'section-' + (section?.id ?? $index); @let descId = sectionId + '-desc'; @let\n desc = section?.description; @let hasDesc = !!desc;\n\n <section class=\"form__section\" [attr.data-section-id]=\"sectionId\">\n @if (section?.name) { @if (collapsibleSections()) {\n <button\n type=\"button\"\n class=\"form__section-toggle\"\n (click)=\"openSection(section, $index)\"\n [attr.aria-expanded]=\"isSectionOpen(section, $index)\"\n [attr.aria-controls]=\"sectionId\"\n [attr.aria-describedby]=\"\n hasDesc && isSectionOpen(section, $index) ? descId : null\n \"\n >\n <span class=\"form__section-title\">{{ section.name }}</span>\n <span\n class=\"form__chevron\"\n [class.form__chevron--open]=\"isSectionOpen(section, $index)\"\n ></span>\n </button>\n } @else {\n <div class=\"form__field-group-name\">{{ section.name }} - {{ descId }}</div>\n @if (hasDesc) {\n <p class=\"form__section-description\" [id]=\"descId\">\n {{ desc }}\n </p>\n } } } @if (!collapsibleSections() || isSectionOpen(section, $index)) { @if\n (collapsibleSections() && hasDesc) {\n <p class=\"form__section-description\" [id]=\"descId\">\n {{ desc }}\n </p>\n }\n\n <div class=\"form__section-content\" [id]=\"sectionId\">\n @if (section.formFields?.length) { @for (field of\n getVisibleSectionFields(section); track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n \n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [optionCascadeConfigs]=\"optionCascadeConfigs()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields available for this section.</div>\n } } @else {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n </div>\n }\n </section>\n } @empty { @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n } } } @else { @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n } } } @else {\n <div class=\"form__empty\">No metadata available</div>\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n } }\n</form>\n} @else if (programEntryFormConfig() && programEntryFormConfig()!.formType ===\n'TRACKER') {\n<form\n [formGroup]=\"form()\"\n class=\"form {{ configuration().directionClassName }}\"\n>\n <div class=\"form__header\">\n <h2 class=\"form__title\">{{ configuration().formName }}</h2>\n </div>\n\n @if (programEntryFormMetaData(); as meta) { @if (meta?.sections?.length) {\n @for (section of meta?.sections; track section?.id ?? $index) { @let sectionId\n = 'section-' + (section?.id ?? $index); @let descId = sectionId + '-desc';\n @let desc = section?.description; @let hasDesc = !!desc;\n\n <section class=\"form__section\" [attr.data-section-id]=\"sectionId\">\n @if (section?.name) { @if (collapsibleSections()) {\n <button\n type=\"button\"\n class=\"form__section-toggle\"\n (click)=\"openSection(section, $index)\"\n [attr.aria-expanded]=\"isSectionOpen(section, $index)\"\n [attr.aria-controls]=\"sectionId\"\n [attr.aria-describedby]=\"\n hasDesc && isSectionOpen(section, $index) ? descId : null\n \"\n >\n <span class=\"form__section-title\">{{ section.name }}</span>\n <span\n class=\"form__chevron\"\n [class.form__chevron--open]=\"isSectionOpen(section, $index)\"\n ></span>\n </button>\n } @else {\n <div class=\"form__field-group-name\">\n {{ section.name }}\n </div>\n @if (hasDesc) {\n <p class=\"form__section-description\" [id]=\"descId\">\n {{ desc }}\n </p>\n } } } @if (!collapsibleSections() || isSectionOpen(section, $index)) { @if\n (collapsibleSections() && hasDesc) {\n <p class=\"form__section-description\" [id]=\"descId\">\n {{ desc }}\n </p>\n }\n <div class=\"form__section-content\" [id]=\"sectionId\">\n @if (section.formFields?.length) { @for (field of\n getVisibleSectionFields(section); track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields available for this section.</div>\n } } @else {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n </div>\n }\n </section>\n } @empty { @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n } } } @else { @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n } } } @else {\n <div class=\"form__empty\">No metadata available</div>\n @for (field of sanitizedFields; track field?.id ?? $index) {\n <div class=\"form__field form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n } }\n</form>\n} @else {\n<form [formGroup]=\"form()\" [class]=\"configuration().directionClassName\">\n @if (configuration()?.formName) {\n <div class=\"form-name\">\n <h2>{{ configuration()?.formName }}</h2>\n </div>\n } @if (sanitizedFields?.length) { @for (field of sanitizedFields; track\n field?.id ?? $index) {\n <div class=\"form-field-{{ configuration().direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"field\"\n [fieldConfig]=\"configuration().fieldConfig\"\n [form]=\"form()\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntities()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [optionCascadeConfigMap]=\"optionCascadeConfigMap()\"\n [programRuleActions]=\"programRuleActions()\"\n [isCheckBoxButton]=\"shouldRenderAsCheckBoxesButton()\"\n (fieldUpdate)=\"onFieldUpdate($event, field)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } } @else {\n <div class=\"text-sm text-gray-500\">No fields to display.</div>\n }\n</form>\n} -->\n\n@let entryFormConfig = programEntryFormConfig();\n@let entryFormMeta = programEntryFormMetaData();\n@let uiConfig = configuration();\n@let formGroupValue = form();\n\n@let isSectionsCollapsible = collapsibleSections();\n\n@let dataEntitiesValue = dataEntities();\n@let dataEntityId = dataId();\n@let orgUnitRootIds = customOrgUnitRoots();\n\n@let cascadeConfigMap = optionCascadeConfigMap();\n@let cascadeConfigs = optionCascadeConfigs();\n\n@let ruleActionList = programRuleActions();\n@let renderAsCheckboxButtons = shouldRenderAsCheckBoxesButton();\n\n@let entryFormCoordinatePickerGeoConfig = coordinatePickerGeoConfig();\n@let entryFormFieldControlKeyById = fieldControlKeyById();\n\n@if (entryFormConfig?.formType === 'EVENT') {\n <form [formGroup]=\"formGroupValue\" class=\"form {{ uiConfig.directionClassName }}\">\n <div class=\"form__header\">\n <h2 class=\"form__title\">{{ uiConfig.formName }}</h2>\n </div>\n\n @if (entryFormMeta?.programStageSections?.length) {\n @for (stageSection of entryFormMeta.programStageSections; track stageSection?.id ?? $index) {\n @let sectionKey = stageSection?.id ?? $index;\n @let sectionDomId = 'section-' + sectionKey;\n @let descriptionDomId = sectionDomId + '-desc';\n @let sectionDescription = stageSection?.description;\n @let hasDescription = !!sectionDescription;\n\n <section class=\"form__section\" [attr.data-section-id]=\"sectionDomId\">\n @if (stageSection?.name) {\n @if (isSectionsCollapsible) {\n @let isOpen = isSectionOpen(stageSection, $index);\n\n <button\n type=\"button\"\n class=\"form__section-toggle\"\n (click)=\"openSection(stageSection, $index)\"\n [attr.aria-expanded]=\"isOpen\"\n [attr.aria-controls]=\"sectionDomId\"\n [attr.aria-describedby]=\"hasDescription && isOpen ? descriptionDomId : null\"\n >\n <span class=\"form__section-title\">{{ stageSection.name }}</span>\n <span class=\"form__chevron\" [class.form__chevron--open]=\"isOpen\"></span>\n </button>\n } @else {\n <div class=\"form__field-group-name\">{{ stageSection.name }}</div>\n @if (hasDescription) {\n <p class=\"form__section-description\" [id]=\"descriptionDomId\">\n {{ sectionDescription }}\n </p>\n }\n }\n }\n\n @let isOpen = !isSectionsCollapsible || isSectionOpen(stageSection, $index);\n @if (isOpen) {\n @if (isSectionsCollapsible && hasDescription) {\n <p class=\"form__section-description\" [id]=\"descriptionDomId\">\n {{ sectionDescription }}\n </p>\n }\n\n <div class=\"form__section-content\" [id]=\"sectionDomId\">\n @if (stageSection?.formFields?.length) {\n @for (visibleField of getVisibleSectionFields(stageSection); track visibleField?.id ?? $index) {\n <div class=\"form__field form-field-{{ uiConfig.direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"visibleField\"\n [fieldConfig]=\"uiConfig.fieldConfig\"\n [form]=\"formGroupValue\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntitiesValue\"\n [dataId]=\"dataEntityId\"\n [customOrgUnitRoots]=\"orgUnitRootIds\"\n [optionCascadeConfigMap]=\"cascadeConfigMap\"\n [optionCascadeConfigs]=\"cascadeConfigs\"\n [coordinatePickerGeoConfig]=\"entryFormCoordinatePickerGeoConfig\"\n [fieldControlKeyById]=\"entryFormFieldControlKeyById\"\n [programRuleActions]=\"ruleActionList\"\n [isCheckBoxButton]=\"renderAsCheckboxButtons\"\n (fieldUpdate)=\"onFieldUpdate($event, visibleField)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n } @else {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n </div>\n }\n </section>\n } @empty {\n @for (fallbackField of sanitizedFields; track fallbackField?.id ?? $index) {\n <div class=\"form__field form-field-{{ uiConfig.direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"fallbackField\"\n [fieldConfig]=\"uiConfig.fieldConfig\"\n [form]=\"formGroupValue\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntitiesValue\"\n [dataId]=\"dataEntityId\"\n [customOrgUnitRoots]=\"orgUnitRootIds\"\n [optionCascadeConfigMap]=\"cascadeConfigMap\"\n [coordinatePickerGeoConfig]=\"entryFormCoordinatePickerGeoConfig\"\n [fieldControlKeyById]=\"entryFormFieldControlKeyById\"\n [programRuleActions]=\"ruleActionList\"\n [isCheckBoxButton]=\"renderAsCheckboxButtons\"\n (fieldUpdate)=\"onFieldUpdate($event, fallbackField)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n } @else {\n @for (fallbackField of sanitizedFields; track fallbackField?.id ?? $index) {\n <div class=\"form__field form-field-{{ uiConfig.direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"fallbackField\"\n [fieldConfig]=\"uiConfig.fieldConfig\"\n [form]=\"formGroupValue\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntitiesValue\"\n [dataId]=\"dataEntityId\"\n [customOrgUnitRoots]=\"orgUnitRootIds\"\n [optionCascadeConfigMap]=\"cascadeConfigMap\"\n [coordinatePickerGeoConfig]=\"entryFormCoordinatePickerGeoConfig\"\n [fieldControlKeyById]=\"entryFormFieldControlKeyById\"\n [programRuleActions]=\"ruleActionList\"\n [isCheckBoxButton]=\"renderAsCheckboxButtons\"\n (fieldUpdate)=\"onFieldUpdate($event, fallbackField)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n </form>\n\n} @else if (entryFormConfig?.formType === 'TRACKER') {\n\n <form [formGroup]=\"formGroupValue\" class=\"form {{ uiConfig.directionClassName }}\">\n <div class=\"form__header\">\n <h2 class=\"form__title\">{{ uiConfig.formName }}</h2>\n </div>\n\n @if (entryFormMeta?.sections?.length) {\n @for (teiSection of entryFormMeta.sections; track teiSection?.id ?? $index) {\n @let sectionKey = teiSection?.id ?? $index;\n @let sectionDomId = 'section-' + sectionKey;\n @let descriptionDomId = sectionDomId + '-desc';\n @let sectionDescription = teiSection?.description;\n @let hasDescription = !!sectionDescription;\n\n <section class=\"form__section\" [attr.data-section-id]=\"sectionDomId\">\n @if (teiSection?.name) {\n @if (isSectionsCollapsible) {\n @let isOpen = isSectionOpen(teiSection, $index);\n\n <button\n type=\"button\"\n class=\"form__section-toggle\"\n (click)=\"openSection(teiSection, $index)\"\n [attr.aria-expanded]=\"isOpen\"\n [attr.aria-controls]=\"sectionDomId\"\n [attr.aria-describedby]=\"hasDescription && isOpen ? descriptionDomId : null\"\n >\n <span class=\"form__section-title\">{{ teiSection.name }}</span>\n <span class=\"form__chevron\" [class.form__chevron--open]=\"isOpen\"></span>\n </button>\n } @else {\n <div class=\"form__field-group-name\">{{ teiSection.name }}</div>\n @if (hasDescription) {\n <p class=\"form__section-description\" [id]=\"descriptionDomId\">\n {{ sectionDescription }}\n </p>\n }\n }\n }\n\n @let isOpen = !isSectionsCollapsible || isSectionOpen(teiSection, $index);\n @if (isOpen) {\n @if (isSectionsCollapsible && hasDescription) {\n <p class=\"form__section-description\" [id]=\"descriptionDomId\">\n {{ sectionDescription }}\n </p>\n }\n\n <div class=\"form__section-content\" [id]=\"sectionDomId\">\n @if (teiSection?.formFields?.length) {\n @for (visibleField of getVisibleSectionFields(teiSection); track visibleField?.id ?? $index) {\n <div class=\"form__field form-field-{{ uiConfig.direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"visibleField\"\n [fieldConfig]=\"uiConfig.fieldConfig\"\n [form]=\"formGroupValue\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntitiesValue\"\n [dataId]=\"dataEntityId\"\n [customOrgUnitRoots]=\"orgUnitRootIds\"\n [optionCascadeConfigMap]=\"cascadeConfigMap\"\n [coordinatePickerGeoConfig]=\"entryFormCoordinatePickerGeoConfig\"\n [fieldControlKeyById]=\"entryFormFieldControlKeyById\"\n [programRuleActions]=\"ruleActionList\"\n [isCheckBoxButton]=\"renderAsCheckboxButtons\"\n (fieldUpdate)=\"onFieldUpdate($event, visibleField)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n } @else {\n <div class=\"form__empty\">No fields available for this section.</div>\n }\n </div>\n }\n </section>\n } @empty {\n @for (fallbackField of sanitizedFields; track fallbackField?.id ?? $index) {\n <div class=\"form__field form-field-{{ uiConfig.direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"fallbackField\"\n [fieldConfig]=\"uiConfig.fieldConfig\"\n [form]=\"formGroupValue\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntitiesValue\"\n [dataId]=\"dataEntityId\"\n [customOrgUnitRoots]=\"orgUnitRootIds\"\n [optionCascadeConfigMap]=\"cascadeConfigMap\"\n [coordinatePickerGeoConfig]=\"entryFormCoordinatePickerGeoConfig\"\n [fieldControlKeyById]=\"entryFormFieldControlKeyById\"\n [programRuleActions]=\"ruleActionList\"\n [isCheckBoxButton]=\"renderAsCheckboxButtons\"\n (fieldUpdate)=\"onFieldUpdate($event, fallbackField)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n } @else {\n <div class=\"form__empty\">No metadata available</div>\n @for (fallbackField of sanitizedFields; track fallbackField?.id ?? $index) {\n <div class=\"form__field form-field-{{ uiConfig.direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"fallbackField\"\n [fieldConfig]=\"uiConfig.fieldConfig\"\n [form]=\"formGroupValue\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntitiesValue\"\n [dataId]=\"dataEntityId\"\n [customOrgUnitRoots]=\"orgUnitRootIds\"\n [optionCascadeConfigMap]=\"cascadeConfigMap\"\n [coordinatePickerGeoConfig]=\"entryFormCoordinatePickerGeoConfig\"\n [fieldControlKeyById]=\"entryFormFieldControlKeyById\"\n [programRuleActions]=\"ruleActionList\"\n [isCheckBoxButton]=\"renderAsCheckboxButtons\"\n (fieldUpdate)=\"onFieldUpdate($event, fallbackField)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n } @empty {\n <div class=\"form__empty\">No fields to display.</div>\n }\n }\n </form>\n\n} @else {\n\n <form [formGroup]=\"formGroupValue\" [class]=\"uiConfig.directionClassName\">\n @if (uiConfig?.formName) {\n <div class=\"form-name\">\n <h2>{{ uiConfig.formName }}</h2>\n </div>\n }\n\n @if (sanitizedFields?.length) {\n @for (fallbackField of sanitizedFields; track fallbackField?.id ?? $index) {\n <div class=\"form-field-{{ uiConfig.direction }}\">\n <ng-dhis2-ui-form-field\n [field]=\"fallbackField\"\n [fieldConfig]=\"uiConfig.fieldConfig\"\n [form]=\"formGroupValue\"\n [fieldClass]=\"fieldClass()\"\n [dataEntities]=\"dataEntitiesValue\"\n [dataId]=\"dataEntityId\"\n [customOrgUnitRoots]=\"orgUnitRootIds\"\n [optionCascadeConfigMap]=\"cascadeConfigMap\"\n [coordinatePickerGeoConfig]=\"entryFormCoordinatePickerGeoConfig\"\n [fieldControlKeyById]=\"entryFormFieldControlKeyById\"\n [programRuleActions]=\"ruleActionList\"\n [isCheckBoxButton]=\"renderAsCheckboxButtons\"\n (fieldUpdate)=\"onFieldUpdate($event, fallbackField)\"\n (runtimeOptionChange)=\"onRunTimeOptionUpdate($event)\"\n />\n </div>\n }\n } @else {\n <div class=\"text-sm text-gray-500\">No fields to display.</div>\n }\n </form>\n\n}\n\n", styles: ["@charset \"UTF-8\";.form__section-toggle{width:100%;display:flex;align-items:center;justify-content:space-between;font-size:15px;font-weight:600;padding:14px 16px 16px;background-color:#e8edf2;color:#374151;border:0;cursor:pointer;text-align:left}.form__section-toggle:focus{outline:2px solid #93c5fd;outline-offset:2px}.form__section-title{pointer-events:none}.form__chevron{width:10px;height:10px;display:inline-block;margin-left:12px;-webkit-mask-image:linear-gradient(#000,#000);mask-image:linear-gradient(#000,#000);border-right:2px solid currentColor;border-bottom:2px solid currentColor;transform:rotate(-45deg);transition:transform .12s ease-in-out}.form__chevron--open{transform:rotate(45deg)}.form__section{border:1px solid #eee;margin-bottom:16px;background-color:#fff}.form__field-group-name{display:inline-flex;font-size:14px;font-weight:600;padding:8px 16px;background-color:#e8edf2;color:#374151}.form__section-content{padding:16px}.form__section-description{margin:5px 5px 15px;font-size:15px;line-height:1.5;color:#4b5563;white-space:pre-line}.form__section-description:before{content:\"\";display:inline-block;width:4px;height:.9em;margin-right:8px;vertical-align:-2px;background-color:#cbd5e1;border-radius:2px}\n"] }]
7700
9458
  }], ctorParameters: () => [], propDecorators: { formUpdate: [{
7701
9459
  type: Output
7702
9460
  }], formValidityUpdate: [{
@@ -8139,39 +9897,67 @@ class FormFieldGroup {
8139
9897
  }
8140
9898
  }
8141
9899
 
9900
+ // import {
9901
+ // Option,
9902
+ // ProgramRule,
9903
+ // ProgramRuleAction,
9904
+ // ProgramRuleVariable,
9905
+ // } from '@iapps/d2-web-sdk';
9906
+ // import { camelCase } from 'lodash';
9907
+ const RULE_VAR_REGEX = /(A|#|V)\{([^}]+)\}/g;
9908
+ function buildRuleVariableMap(ruleVariables) {
9909
+ const map = new Map();
9910
+ for (const v of ruleVariables ?? []) {
9911
+ if (!v?.name)
9912
+ continue;
9913
+ const code = camelCase(v?.dataElement?.code) ||
9914
+ v?.dataElement?.id ||
9915
+ camelCase(v?.trackedEntityAttribute?.code) ||
9916
+ v?.trackedEntityAttribute?.id;
9917
+ if (code)
9918
+ map.set(v.name, code);
9919
+ }
9920
+ return map;
9921
+ }
9922
+ function replaceRuleVariables(input, variableMap) {
9923
+ if (!input)
9924
+ return input;
9925
+ return input.replace(RULE_VAR_REGEX, (_match, _prefix, varName) => {
9926
+ const code = variableMap.get(varName);
9927
+ return code ? `{${code}}` : `{${varName}}`;
9928
+ });
9929
+ }
8142
9930
  class MetadataRuleAction {
8143
9931
  constructor(ruleAction, ruleVariables) {
8144
9932
  this.ruleAction = ruleAction;
8145
- this.ruleVariables = ruleVariables;
9933
+ this.variableMap = buildRuleVariableMap(ruleVariables);
8146
9934
  }
8147
9935
  get field() {
8148
- return (this.ruleAction.dataElement?.id ||
8149
- this.ruleAction.trackedEntityAttribute?.id);
9936
+ const fieldId = this.ruleAction?.dataElement?.id ||
9937
+ this.ruleAction?.trackedEntityAttribute?.id;
9938
+ if (!fieldId) {
9939
+ console.warn(`ProgramRuleAction is missing both dataElement.id and trackedEntityAttribute.id (action id: ${this.ruleAction?.id ?? 'unknown'})`);
9940
+ }
9941
+ return fieldId;
9942
+ }
9943
+ get programRule() {
9944
+ return { id: this.ruleAction.programRule?.id };
9945
+ }
9946
+ get evaluationTime() {
9947
+ return this.ruleAction?.evaluationTime ?? 'ALWAYS';
8150
9948
  }
8151
9949
  get actionType() {
8152
9950
  return this.ruleAction.programRuleActionType;
8153
9951
  }
8154
9952
  get assignedData() {
8155
- const regex = /(A|#|V)\{([^}]+)\}/g;
8156
- return this.ruleAction?.data?.replace(regex, (match, _, dataVariable) => {
8157
- const ruleVariableObject = this.ruleVariables?.find((variable) => variable.name === dataVariable);
8158
- if (!ruleVariableObject) {
8159
- return `{${dataVariable}}`;
8160
- }
8161
- const code = camelCase(ruleVariableObject?.dataElement?.code) ||
8162
- ruleVariableObject?.dataElement?.id ||
8163
- camelCase(ruleVariableObject?.trackedEntityAttribute?.code) ||
8164
- ruleVariableObject?.trackedEntityAttribute?.id;
8165
- return `{${code}}`;
8166
- });
9953
+ return replaceRuleVariables(this.ruleAction?.data, this.variableMap);
8167
9954
  }
8168
9955
  get displayedContent() {
8169
9956
  return this.ruleAction.displayContent;
8170
9957
  }
8171
9958
  get options() {
8172
- if (this.ruleAction.option) {
9959
+ if (this.ruleAction.option)
8173
9960
  return [this.ruleAction.option];
8174
- }
8175
9961
  return this.ruleAction.optionGroup?.options || [];
8176
9962
  }
8177
9963
  toJson() {
@@ -8179,37 +9965,36 @@ class MetadataRuleAction {
8179
9965
  field: this.field,
8180
9966
  actionType: this.actionType,
8181
9967
  assignedData: this.assignedData,
8182
- displayedContent: this.ruleAction.displayContent,
9968
+ displayedContent: this.displayedContent,
8183
9969
  options: this.options,
9970
+ evaluationTime: this.evaluationTime,
9971
+ programRule: this.programRule,
8184
9972
  };
8185
9973
  }
8186
9974
  }
8187
9975
  class MetadataRule {
8188
9976
  constructor(rule, ruleVariables) {
8189
9977
  this.rule = rule;
8190
- this.ruleVariables = ruleVariables;
9978
+ this.variableMap = buildRuleVariableMap(ruleVariables);
8191
9979
  }
8192
9980
  get actions() {
8193
- return (this.rule?.programRuleActions || []).map((action) => new MetadataRuleAction(action, this.ruleVariables));
9981
+ return (this.rule?.programRuleActions || [])
9982
+ .map((action) => new MetadataRuleAction(action, []))
9983
+ .map((a) => a.toJson());
9984
+ }
9985
+ get programRule() {
9986
+ return { id: this.rule.id };
8194
9987
  }
8195
9988
  get condition() {
8196
- const regex = /(A|#|V)\{([^}]+)\}/g;
8197
- return this.rule?.condition?.replace(regex, (match, _, ruleVariable) => {
8198
- const ruleVariableObject = this.ruleVariables?.find((variable) => variable.name === ruleVariable);
8199
- if (!ruleVariableObject) {
8200
- return `{${ruleVariable}}`;
8201
- }
8202
- const code = camelCase(ruleVariableObject?.dataElement?.code) ||
8203
- ruleVariableObject?.dataElement?.id ||
8204
- camelCase(ruleVariableObject?.trackedEntityAttribute?.code) ||
8205
- ruleVariableObject?.trackedEntityAttribute?.id;
8206
- return `{${code}}`;
8207
- });
9989
+ return (replaceRuleVariables(this.rule?.condition ?? '', this.variableMap) ?? '');
8208
9990
  }
8209
9991
  toJson() {
8210
9992
  return {
8211
- actions: this.actions.map((action) => action.toJson()),
9993
+ actions: (this.rule?.programRuleActions || [])
9994
+ .map((action) => new MetadataRuleAction(action, []))
9995
+ .map((a) => a.toJson()),
8212
9996
  condition: this.condition,
9997
+ programRule: { id: this.programRule.id ?? this.rule.id },
8213
9998
  };
8214
9999
  }
8215
10000
  }
@@ -8748,7 +10533,7 @@ class RepeatableFormComponent {
8748
10533
  };
8749
10534
  }
8750
10535
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: RepeatableFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
8751
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.3", 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: ["programEntryFormConfig", "formConfig", "fields", "form", "isFormHorizontal", "showSaveButton", "fieldsData", "formMetaData", "programEntryFormMetaData", "fieldClass", "shouldRenderAsCheckBoxesButton", "programRuleActions", "dataEntities", "dataId", "customOrgUnitRoots", "program", "collapsibleSections"], outputs: ["formUpdate", "formValidityUpdate"] }] }); }
10536
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.3", 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: ["programEntryFormConfig", "formConfig", "fields", "form", "isFormHorizontal", "showSaveButton", "fieldsData", "formMetaData", "programEntryFormMetaData", "fieldClass", "shouldRenderAsCheckBoxesButton", "programRuleActions", "dataEntities", "dataId", "customOrgUnitRoots", "optionCascadeConfigs", "coordinatePickerGeoConfig", "program", "collapsibleSections"], outputs: ["formUpdate", "formValidityUpdate"] }] }); }
8752
10537
  }
8753
10538
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: RepeatableFormComponent, decorators: [{
8754
10539
  type: Component,
@@ -8876,7 +10661,7 @@ class SectionFormComponent {
8876
10661
  return valueValidity || repeatableDataValidity;
8877
10662
  }
8878
10663
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: SectionFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
8879
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.3", 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", formValidityUpdate: "formValidityUpdate" }, 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.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: FormComponent, selector: "ng-dhis2-ui-form", inputs: ["programEntryFormConfig", "formConfig", "fields", "form", "isFormHorizontal", "showSaveButton", "fieldsData", "formMetaData", "programEntryFormMetaData", "fieldClass", "shouldRenderAsCheckBoxesButton", "programRuleActions", "dataEntities", "dataId", "customOrgUnitRoots", "program", "collapsibleSections"], outputs: ["formUpdate", "formValidityUpdate"] }, { 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"] }] }); }
10664
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.3", 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", formValidityUpdate: "formValidityUpdate" }, 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: ["programEntryFormConfig", "formConfig", "fields", "form", "isFormHorizontal", "showSaveButton", "fieldsData", "formMetaData", "programEntryFormMetaData", "fieldClass", "shouldRenderAsCheckBoxesButton", "programRuleActions", "dataEntities", "dataId", "customOrgUnitRoots", "optionCascadeConfigs", "coordinatePickerGeoConfig", "program", "collapsibleSections"], outputs: ["formUpdate", "formValidityUpdate"] }, { 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"] }] }); }
8880
10665
  }
8881
10666
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: SectionFormComponent, decorators: [{
8882
10667
  type: Component,
@@ -8904,6 +10689,7 @@ class BaseFormWrapperComponent {
8904
10689
  this.dataValues = input({}, ...(ngDevMode ? [{ debugName: "dataValues" }] : []));
8905
10690
  this.dataId = input(...(ngDevMode ? [undefined, { debugName: "dataId" }] : []));
8906
10691
  this.customOrgUnitRoots = input(...(ngDevMode ? [undefined, { debugName: "customOrgUnitRoots" }] : []));
10692
+ this.coordinatePickerGeoConfig = input(...(ngDevMode ? [undefined, { debugName: "coordinatePickerGeoConfig" }] : []));
8907
10693
  this.formMetaData = input(...(ngDevMode ? [undefined, { debugName: "formMetaData" }] : []));
8908
10694
  this.programEntryFormMetaData = input(...(ngDevMode ? [undefined, { debugName: "programEntryFormMetaData" }] : []));
8909
10695
  this.programStage = input(...(ngDevMode ? [undefined, { debugName: "programStage" }] : []));
@@ -8940,7 +10726,7 @@ class BaseFormWrapperComponent {
8940
10726
  this.ruleProcessor.destroy();
8941
10727
  }
8942
10728
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: BaseFormWrapperComponent, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
8943
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.1.3", type: BaseFormWrapperComponent, isStandalone: true, inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, fields: { classPropertyName: "fields", publicName: "fields", isSignal: true, isRequired: true, transformFunction: null }, rules: { classPropertyName: "rules", publicName: "rules", isSignal: true, isRequired: false, transformFunction: null }, dataValues: { classPropertyName: "dataValues", publicName: "dataValues", isSignal: true, isRequired: false, transformFunction: null }, dataId: { classPropertyName: "dataId", publicName: "dataId", isSignal: true, isRequired: false, transformFunction: null }, customOrgUnitRoots: { classPropertyName: "customOrgUnitRoots", publicName: "customOrgUnitRoots", isSignal: true, isRequired: false, transformFunction: null }, formMetaData: { classPropertyName: "formMetaData", publicName: "formMetaData", isSignal: true, isRequired: false, transformFunction: null }, programEntryFormMetaData: { classPropertyName: "programEntryFormMetaData", publicName: "programEntryFormMetaData", isSignal: true, isRequired: false, transformFunction: null }, programStage: { classPropertyName: "programStage", publicName: "programStage", isSignal: true, isRequired: false, transformFunction: null }, program: { classPropertyName: "program", publicName: "program", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { formSave: "formSave", formUpdate: "formUpdate", formCancel: "formCancel", formValidityUpdate: "formValidityUpdate" }, ngImport: i0 }); }
10729
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.1.3", type: BaseFormWrapperComponent, isStandalone: true, inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, fields: { classPropertyName: "fields", publicName: "fields", isSignal: true, isRequired: true, transformFunction: null }, rules: { classPropertyName: "rules", publicName: "rules", isSignal: true, isRequired: false, transformFunction: null }, dataValues: { classPropertyName: "dataValues", publicName: "dataValues", isSignal: true, isRequired: false, transformFunction: null }, dataId: { classPropertyName: "dataId", publicName: "dataId", isSignal: true, isRequired: false, transformFunction: null }, customOrgUnitRoots: { classPropertyName: "customOrgUnitRoots", publicName: "customOrgUnitRoots", isSignal: true, isRequired: false, transformFunction: null }, coordinatePickerGeoConfig: { classPropertyName: "coordinatePickerGeoConfig", publicName: "coordinatePickerGeoConfig", isSignal: true, isRequired: false, transformFunction: null }, formMetaData: { classPropertyName: "formMetaData", publicName: "formMetaData", isSignal: true, isRequired: false, transformFunction: null }, programEntryFormMetaData: { classPropertyName: "programEntryFormMetaData", publicName: "programEntryFormMetaData", isSignal: true, isRequired: false, transformFunction: null }, programStage: { classPropertyName: "programStage", publicName: "programStage", isSignal: true, isRequired: false, transformFunction: null }, program: { classPropertyName: "program", publicName: "program", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { formSave: "formSave", formUpdate: "formUpdate", formCancel: "formCancel", formValidityUpdate: "formValidityUpdate" }, ngImport: i0 }); }
8944
10730
  }
8945
10731
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: BaseFormWrapperComponent, decorators: [{
8946
10732
  type: Directive
@@ -8959,6 +10745,7 @@ class FlatFormComponent extends BaseFormWrapperComponent {
8959
10745
  super(...arguments);
8960
10746
  this.collapsibleSections = input(false, ...(ngDevMode ? [{ debugName: "collapsibleSections" }] : []));
8961
10747
  this.programEntryFormConfig = input.required(...(ngDevMode ? [{ debugName: "programEntryFormConfig" }] : []));
10748
+ this.optionCascadeConfigs = input([], ...(ngDevMode ? [{ debugName: "optionCascadeConfigs" }] : []));
8962
10749
  }
8963
10750
  ngOnInit() {
8964
10751
  this.formGroup = FormUtil.getFormGroup(this.fields(), this.dataValues());
@@ -8969,11 +10756,11 @@ class FlatFormComponent extends BaseFormWrapperComponent {
8969
10756
  this.updateFormValidity(this.formGroup.valid);
8970
10757
  }
8971
10758
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: FlatFormComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
8972
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.1.3", type: FlatFormComponent, isStandalone: false, selector: "ng-dhis2-ui-flat-form", inputs: { collapsibleSections: { classPropertyName: "collapsibleSections", publicName: "collapsibleSections", isSignal: true, isRequired: false, transformFunction: null }, programEntryFormConfig: { classPropertyName: "programEntryFormConfig", publicName: "programEntryFormConfig", isSignal: true, isRequired: true, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: "<ng-dhis2-ui-form\n [programEntryFormConfig]=\"programEntryFormConfig()\"\n [collapsibleSections]=\"collapsibleSections()\"\n [programEntryFormMetaData]=\"programEntryFormMetaData()\"\n [fields]=\"fields()\"\n [form]=\"formGroup\"\n [dataEntities]=\"dataValues()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"ruleActions()\"\n (formUpdate)=\"onFormUpdate()\"\n [program]=\"program()\"\n/>\n", dependencies: [{ kind: "component", type: FormComponent, selector: "ng-dhis2-ui-form", inputs: ["programEntryFormConfig", "formConfig", "fields", "form", "isFormHorizontal", "showSaveButton", "fieldsData", "formMetaData", "programEntryFormMetaData", "fieldClass", "shouldRenderAsCheckBoxesButton", "programRuleActions", "dataEntities", "dataId", "customOrgUnitRoots", "program", "collapsibleSections"], outputs: ["formUpdate", "formValidityUpdate"] }] }); }
10759
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.1.3", type: FlatFormComponent, isStandalone: false, selector: "ng-dhis2-ui-flat-form", inputs: { collapsibleSections: { classPropertyName: "collapsibleSections", publicName: "collapsibleSections", isSignal: true, isRequired: false, transformFunction: null }, programEntryFormConfig: { classPropertyName: "programEntryFormConfig", publicName: "programEntryFormConfig", isSignal: true, isRequired: true, transformFunction: null }, optionCascadeConfigs: { classPropertyName: "optionCascadeConfigs", publicName: "optionCascadeConfigs", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: "@let entryFormConfig = programEntryFormConfig();\n@let collapsibleSectionConfig = collapsibleSections();\n@let optionCascadeConfigMap = optionCascadeConfigs();\n@let entryFormMetaData = programEntryFormMetaData();\n@let entryFormFields = fields();\n@let formDataValues = dataValues();\n@let dataEntityId = dataId();\n@let customOrgUnitRootIds = customOrgUnitRoots();\n@let programRuleActionList = ruleActions();\n@let activeProgram = program();\n@let entryFormCoordinatePickerGeoConfig = coordinatePickerGeoConfig();\n\n<ng-dhis2-ui-form\n [programEntryFormConfig]=\"entryFormConfig\"\n [collapsibleSections]=\"collapsibleSectionConfig\"\n [optionCascadeConfigs]=\"optionCascadeConfigMap\"\n [programEntryFormMetaData]=\"entryFormMetaData\"\n [fields]=\"entryFormFields\"\n [form]=\"formGroup\"\n [dataEntities]=\"formDataValues\"\n [dataId]=\"dataEntityId\"\n [customOrgUnitRoots]=\"customOrgUnitRootIds\"\n [coordinatePickerGeoConfig]=\"entryFormCoordinatePickerGeoConfig\"\n [programRuleActions]=\"programRuleActionList\"\n [program]=\"activeProgram\"\n (formUpdate)=\"onFormUpdate()\"\n/>\n", dependencies: [{ kind: "component", type: FormComponent, selector: "ng-dhis2-ui-form", inputs: ["programEntryFormConfig", "formConfig", "fields", "form", "isFormHorizontal", "showSaveButton", "fieldsData", "formMetaData", "programEntryFormMetaData", "fieldClass", "shouldRenderAsCheckBoxesButton", "programRuleActions", "dataEntities", "dataId", "customOrgUnitRoots", "optionCascadeConfigs", "coordinatePickerGeoConfig", "program", "collapsibleSections"], outputs: ["formUpdate", "formValidityUpdate"] }] }); }
8973
10760
  }
8974
10761
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: FlatFormComponent, decorators: [{
8975
10762
  type: Component,
8976
- args: [{ selector: 'ng-dhis2-ui-flat-form', standalone: false, template: "<ng-dhis2-ui-form\n [programEntryFormConfig]=\"programEntryFormConfig()\"\n [collapsibleSections]=\"collapsibleSections()\"\n [programEntryFormMetaData]=\"programEntryFormMetaData()\"\n [fields]=\"fields()\"\n [form]=\"formGroup\"\n [dataEntities]=\"dataValues()\"\n [dataId]=\"dataId()\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [programRuleActions]=\"ruleActions()\"\n (formUpdate)=\"onFormUpdate()\"\n [program]=\"program()\"\n/>\n" }]
10763
+ args: [{ selector: 'ng-dhis2-ui-flat-form', standalone: false, template: "@let entryFormConfig = programEntryFormConfig();\n@let collapsibleSectionConfig = collapsibleSections();\n@let optionCascadeConfigMap = optionCascadeConfigs();\n@let entryFormMetaData = programEntryFormMetaData();\n@let entryFormFields = fields();\n@let formDataValues = dataValues();\n@let dataEntityId = dataId();\n@let customOrgUnitRootIds = customOrgUnitRoots();\n@let programRuleActionList = ruleActions();\n@let activeProgram = program();\n@let entryFormCoordinatePickerGeoConfig = coordinatePickerGeoConfig();\n\n<ng-dhis2-ui-form\n [programEntryFormConfig]=\"entryFormConfig\"\n [collapsibleSections]=\"collapsibleSectionConfig\"\n [optionCascadeConfigs]=\"optionCascadeConfigMap\"\n [programEntryFormMetaData]=\"entryFormMetaData\"\n [fields]=\"entryFormFields\"\n [form]=\"formGroup\"\n [dataEntities]=\"formDataValues\"\n [dataId]=\"dataEntityId\"\n [customOrgUnitRoots]=\"customOrgUnitRootIds\"\n [coordinatePickerGeoConfig]=\"entryFormCoordinatePickerGeoConfig\"\n [programRuleActions]=\"programRuleActionList\"\n [program]=\"activeProgram\"\n (formUpdate)=\"onFormUpdate()\"\n/>\n" }]
8977
10764
  }] });
8978
10765
 
8979
10766
  class D2FormModule {
@@ -9591,33 +11378,80 @@ class ProgramEntryFormFieldUtil {
9591
11378
  isOrgUnit: true,
9592
11379
  });
9593
11380
  }
11381
+ // #getGeometryField(): IFormField<string> | null {
11382
+ // const rawFeatureType = this.program?.featureType ?? '';
11383
+ // console.log(
11384
+ // 'REACHED HERE AND FEATURE TYPE ACTIVATED::: ',
11385
+ // JSON.stringify(rawFeatureType)
11386
+ // );
11387
+ // const featureType = rawFeatureType.toUpperCase() as
11388
+ // | 'NONE'
11389
+ // | 'POINT'
11390
+ // | 'POLYGON'
11391
+ // | 'MULTI_POLYGON'
11392
+ // | '';
11393
+ // const isGeometryProgram =
11394
+ // featureType === 'POINT' ||
11395
+ // featureType === 'POLYGON' ||
11396
+ // featureType === 'MULTI_POLYGON';
11397
+ // if (!isGeometryProgram) {
11398
+ // if (this.config?.hideGeometryField) {
11399
+ // return null;
11400
+ // }
11401
+ // return null;
11402
+ // }
11403
+ // const sharedOptions = {
11404
+ // required: true,
11405
+ // disabled: this.config?.disableRegistrationUnit ?? false,
11406
+ // isGeometryField: true as const,
11407
+ // };
11408
+ // const label =
11409
+ // featureType === 'POINT' ? 'Location (coordinates)' : 'Boundary (polygon)';
11410
+ // return new FormField<string>({
11411
+ // id: 'geometry',
11412
+ // key: 'geometry',
11413
+ // label,
11414
+ // code: 'geometry',
11415
+ // controlType: 'coordinate',
11416
+ // ...sharedOptions,
11417
+ // });
11418
+ // }
9594
11419
  #getGeometryField() {
9595
- const rawFeatureType = this.program?.featureType ?? '';
9596
- const featureType = rawFeatureType.toUpperCase();
9597
- const isGeometryProgram = featureType === 'POINT' ||
9598
- featureType === 'POLYGON' ||
9599
- featureType === 'MULTI_POLYGON';
9600
- if (!isGeometryProgram) {
9601
- if (this.config?.hideGeometryField) {
9602
- return null;
9603
- }
11420
+ if (this.config?.hideGeometryField)
9604
11421
  return null;
9605
- }
9606
- const sharedOptions = {
9607
- required: true,
9608
- disabled: this.config?.disableRegistrationUnit ?? false,
9609
- isGeometryField: true,
9610
- };
9611
- const label = featureType === 'POINT' ? 'Location (coordinates)' : 'Boundary (polygon)';
11422
+ const effectiveFeatureTypeRaw = this.#resolveEffectiveFeatureType();
11423
+ const normalizedFeatureType = effectiveFeatureTypeRaw.toUpperCase();
11424
+ const supportsGeometry = normalizedFeatureType === 'POINT' ||
11425
+ normalizedFeatureType === 'POLYGON' ||
11426
+ normalizedFeatureType === 'MULTI_POLYGON';
11427
+ if (!supportsGeometry)
11428
+ return null;
11429
+ const geometryFieldLabel = normalizedFeatureType === 'POINT'
11430
+ ? 'Location (coordinates)'
11431
+ : 'Boundary (polygon)';
9612
11432
  return new FormField({
9613
11433
  id: 'geometry',
9614
11434
  key: 'geometry',
9615
- label,
9616
11435
  code: 'geometry',
11436
+ label: geometryFieldLabel,
9617
11437
  controlType: 'coordinate',
9618
- ...sharedOptions,
11438
+ required: true,
11439
+ disabled: this.config?.disableRegistrationUnit ?? false,
11440
+ isGeometryField: true,
9619
11441
  });
9620
11442
  }
11443
+ #resolveEffectiveFeatureType() {
11444
+ const programMeta = this.program;
11445
+ const configuredProgramStageId = this.config?.programStage;
11446
+ if (configuredProgramStageId && programMeta?.programStages?.length) {
11447
+ const configuredStage = programMeta.programStages.find((stage) => stage?.id === configuredProgramStageId);
11448
+ const stageFeatureTypeRaw = configuredStage?.featureType ?? '';
11449
+ if (stageFeatureTypeRaw)
11450
+ return String(stageFeatureTypeRaw);
11451
+ }
11452
+ const programFeatureTypeRaw = programMeta?.featureType ?? '';
11453
+ return String(programFeatureTypeRaw);
11454
+ }
9621
11455
  #getEnrollmentDateField() {
9622
11456
  if (this.config.hideEnrollmentDate || this.config.programStage) {
9623
11457
  return null;
@@ -9700,8 +11534,8 @@ class ProgramEntryFormFieldUtil {
9700
11534
  get eventReportFields() {
9701
11535
  const fields = [
9702
11536
  this.#getOrgUniField(),
9703
- this.#getGeometryField(),
9704
11537
  this.#getEventDateField(),
11538
+ this.#getGeometryField(),
9705
11539
  ];
9706
11540
  return fields.filter((field) => field !== null);
9707
11541
  }
@@ -10688,6 +12522,7 @@ class ProgramEntryFormMetaData {
10688
12522
  'id',
10689
12523
  'programRuleActionType',
10690
12524
  'data',
12525
+ 'programRule',
10691
12526
  'displayContent',
10692
12527
  'content',
10693
12528
  ])
@@ -10713,6 +12548,7 @@ class ProgramEntryFormMetaData {
10713
12548
  'code',
10714
12549
  'displayName',
10715
12550
  ]), 'ToOne'))
12551
+ .paginate(new Pager({ paging: false }))
10716
12552
  .get(),
10717
12553
  ]);
10718
12554
  const [programResponse, programRuleResponse] = metaDataResponse;
@@ -11212,11 +13048,11 @@ class ProgramEntryFormModule {
11212
13048
  }
11213
13049
  }
11214
13050
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: ProgramEntryFormModule, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
11215
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.3", type: ProgramEntryFormModule, isStandalone: true, selector: "ng-dhis2-ui-program-entry-form", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null }, trackedEntity: { classPropertyName: "trackedEntity", publicName: "trackedEntity", isSignal: true, isRequired: false, transformFunction: null }, event: { classPropertyName: "event", publicName: "event", isSignal: true, isRequired: false, transformFunction: null }, enrollment: { classPropertyName: "enrollment", publicName: "enrollment", isSignal: true, isRequired: false, transformFunction: null }, orgUnit: { classPropertyName: "orgUnit", publicName: "orgUnit", isSignal: true, isRequired: false, transformFunction: null }, customOrgUnitRoots: { classPropertyName: "customOrgUnitRoots", publicName: "customOrgUnitRoots", isSignal: true, isRequired: false, transformFunction: null }, formMetaData: { classPropertyName: "formMetaData", publicName: "formMetaData", isSignal: true, isRequired: false, transformFunction: null }, collapsibleSections: { classPropertyName: "collapsibleSections", publicName: "collapsibleSections", isSignal: true, isRequired: false, transformFunction: null }, preprocess: { classPropertyName: "preprocess", publicName: "preprocess", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { instanceSave: "instanceSave", instanceSaveCompleted: "instanceSaveCompleted", instanceUpdate: "instanceUpdate", formValidityUpdate: "formValidityUpdate", formCancel: "formCancel" }, ngImport: i0, template: "@if (loading()) {\n<div className=\"program-entry__form-loader\">\n <ng-dhis2-ui-wrapper [component]=\"FormLoader\" />\n</div>\n} @else if(metaData()) {\n\n<div>\n <!-- Form content -->\n @switch (config().displayType) {\n\n <!-- Flat display -->\n @case ('FLAT') {\n <ng-dhis2-ui-flat-form\n [programEntryFormConfig]=\"config()\"\n [collapsibleSections]=\"collapsibleSections()\"\n [programEntryFormMetaData]=\"metaData()!\"\n [name]=\"metaData()!.name\"\n [dataValues]=\"instance() || {}\"\n [dataId]=\"dataId()\"\n [rules]=\"metaData()!.rules\"\n [fields]=\"metaData()!.formFields\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n (formUpdate)=\"onFormUpdate($event)\"\n (formValidityUpdate)=\"onValidityUpdate($event)\"\n />\n\n <!-- <ng-dhis2-ui-flat-form\n [name]=\"metaData()!.name\"\n [dataValues]=\"instance() || {}\"\n [dataId]=\"dataId()\"\n [rules]=\"metaData()!.rules\"\n [fields]=\"metaData()!.formFields\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [program]=\"config().program\"\n (formUpdate)=\"onFormUpdate($event)\"\n (formValidityUpdate)=\"onValidityUpdate($event)\"\n /> -->\n }\n\n <!-- SECTION display -->\n @case ('SECTION') { Section form }\n\n <!-- CUSTOM FORM -->\n @case ('CUSTOM') { } }\n\n <!-- Action buttons -->\n\n @if(!config().hideActionButtons) {\n <ng-dhis2-ui-wrapper [component]=\"FormActionButtons()\" />\n }\n</div>\n}\n", styles: ["::ng-deep .program-entry__form-loader{padding:8px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: D2FormModule }, { kind: "component", type: FlatFormComponent, selector: "ng-dhis2-ui-flat-form", inputs: ["collapsibleSections", "programEntryFormConfig"] }, { kind: "directive", type: ReactWrapperModule, selector: "ng-dhis2-ui-wrapper", inputs: ["props", "component"] }] }); }
13051
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.1.3", type: ProgramEntryFormModule, isStandalone: true, selector: "ng-dhis2-ui-program-entry-form", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null }, trackedEntity: { classPropertyName: "trackedEntity", publicName: "trackedEntity", isSignal: true, isRequired: false, transformFunction: null }, event: { classPropertyName: "event", publicName: "event", isSignal: true, isRequired: false, transformFunction: null }, enrollment: { classPropertyName: "enrollment", publicName: "enrollment", isSignal: true, isRequired: false, transformFunction: null }, orgUnit: { classPropertyName: "orgUnit", publicName: "orgUnit", isSignal: true, isRequired: false, transformFunction: null }, customOrgUnitRoots: { classPropertyName: "customOrgUnitRoots", publicName: "customOrgUnitRoots", isSignal: true, isRequired: false, transformFunction: null }, formMetaData: { classPropertyName: "formMetaData", publicName: "formMetaData", isSignal: true, isRequired: false, transformFunction: null }, collapsibleSections: { classPropertyName: "collapsibleSections", publicName: "collapsibleSections", isSignal: true, isRequired: false, transformFunction: null }, preprocess: { classPropertyName: "preprocess", publicName: "preprocess", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { instanceSave: "instanceSave", instanceSaveCompleted: "instanceSaveCompleted", instanceUpdate: "instanceUpdate", formValidityUpdate: "formValidityUpdate", formCancel: "formCancel" }, ngImport: i0, template: "@if (loading()) {\n<div className=\"program-entry__form-loader\">\n <ng-dhis2-ui-wrapper [component]=\"FormLoader\" />\n</div>\n} @else if(metaData()) {\n\n<div>\n <!-- Form content -->\n @switch (config().displayType) {\n\n <!-- Flat display -->\n @case ('FLAT') {\n <ng-dhis2-ui-flat-form\n [programEntryFormConfig]=\"config()\"\n [optionCascadeConfigs]=\"config().optionCascadeConfigs || []\"\n [collapsibleSections]=\"collapsibleSections()\"\n [programEntryFormMetaData]=\"metaData()!\"\n [name]=\"metaData()!.name\"\n [dataValues]=\"instance() || {}\"\n [dataId]=\"dataId()\"\n [rules]=\"metaData()!.rules\"\n [fields]=\"metaData()!.formFields\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [coordinatePickerGeoConfig]=\"config().coordinatePickerGeoConfig\"\n (formUpdate)=\"onFormUpdate($event)\"\n (formValidityUpdate)=\"onValidityUpdate($event)\"\n />\n\n <!-- <ng-dhis2-ui-flat-form\n [name]=\"metaData()!.name\"\n [dataValues]=\"instance() || {}\"\n [dataId]=\"dataId()\"\n [rules]=\"metaData()!.rules\"\n [fields]=\"metaData()!.formFields\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [program]=\"config().program\"\n (formUpdate)=\"onFormUpdate($event)\"\n (formValidityUpdate)=\"onValidityUpdate($event)\"\n /> -->\n }\n\n <!-- SECTION display -->\n @case ('SECTION') { Section form }\n\n <!-- CUSTOM FORM -->\n @case ('CUSTOM') { } }\n\n <!-- Action buttons -->\n\n @if(!config().hideActionButtons) {\n <ng-dhis2-ui-wrapper [component]=\"FormActionButtons()\" />\n }\n</div>\n}\n", styles: ["::ng-deep .program-entry__form-loader{padding:8px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: D2FormModule }, { kind: "component", type: FlatFormComponent, selector: "ng-dhis2-ui-flat-form", inputs: ["collapsibleSections", "programEntryFormConfig", "optionCascadeConfigs"] }, { kind: "directive", type: ReactWrapperModule, selector: "ng-dhis2-ui-wrapper", inputs: ["props", "component"] }] }); }
11216
13052
  }
11217
13053
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: ProgramEntryFormModule, decorators: [{
11218
13054
  type: Component,
11219
- args: [{ selector: 'ng-dhis2-ui-program-entry-form', imports: [CommonModule, D2FormModule, ReactWrapperModule], template: "@if (loading()) {\n<div className=\"program-entry__form-loader\">\n <ng-dhis2-ui-wrapper [component]=\"FormLoader\" />\n</div>\n} @else if(metaData()) {\n\n<div>\n <!-- Form content -->\n @switch (config().displayType) {\n\n <!-- Flat display -->\n @case ('FLAT') {\n <ng-dhis2-ui-flat-form\n [programEntryFormConfig]=\"config()\"\n [collapsibleSections]=\"collapsibleSections()\"\n [programEntryFormMetaData]=\"metaData()!\"\n [name]=\"metaData()!.name\"\n [dataValues]=\"instance() || {}\"\n [dataId]=\"dataId()\"\n [rules]=\"metaData()!.rules\"\n [fields]=\"metaData()!.formFields\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n (formUpdate)=\"onFormUpdate($event)\"\n (formValidityUpdate)=\"onValidityUpdate($event)\"\n />\n\n <!-- <ng-dhis2-ui-flat-form\n [name]=\"metaData()!.name\"\n [dataValues]=\"instance() || {}\"\n [dataId]=\"dataId()\"\n [rules]=\"metaData()!.rules\"\n [fields]=\"metaData()!.formFields\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [program]=\"config().program\"\n (formUpdate)=\"onFormUpdate($event)\"\n (formValidityUpdate)=\"onValidityUpdate($event)\"\n /> -->\n }\n\n <!-- SECTION display -->\n @case ('SECTION') { Section form }\n\n <!-- CUSTOM FORM -->\n @case ('CUSTOM') { } }\n\n <!-- Action buttons -->\n\n @if(!config().hideActionButtons) {\n <ng-dhis2-ui-wrapper [component]=\"FormActionButtons()\" />\n }\n</div>\n}\n", styles: ["::ng-deep .program-entry__form-loader{padding:8px}\n"] }]
13055
+ args: [{ selector: 'ng-dhis2-ui-program-entry-form', imports: [CommonModule, D2FormModule, ReactWrapperModule], template: "@if (loading()) {\n<div className=\"program-entry__form-loader\">\n <ng-dhis2-ui-wrapper [component]=\"FormLoader\" />\n</div>\n} @else if(metaData()) {\n\n<div>\n <!-- Form content -->\n @switch (config().displayType) {\n\n <!-- Flat display -->\n @case ('FLAT') {\n <ng-dhis2-ui-flat-form\n [programEntryFormConfig]=\"config()\"\n [optionCascadeConfigs]=\"config().optionCascadeConfigs || []\"\n [collapsibleSections]=\"collapsibleSections()\"\n [programEntryFormMetaData]=\"metaData()!\"\n [name]=\"metaData()!.name\"\n [dataValues]=\"instance() || {}\"\n [dataId]=\"dataId()\"\n [rules]=\"metaData()!.rules\"\n [fields]=\"metaData()!.formFields\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [coordinatePickerGeoConfig]=\"config().coordinatePickerGeoConfig\"\n (formUpdate)=\"onFormUpdate($event)\"\n (formValidityUpdate)=\"onValidityUpdate($event)\"\n />\n\n <!-- <ng-dhis2-ui-flat-form\n [name]=\"metaData()!.name\"\n [dataValues]=\"instance() || {}\"\n [dataId]=\"dataId()\"\n [rules]=\"metaData()!.rules\"\n [fields]=\"metaData()!.formFields\"\n [customOrgUnitRoots]=\"customOrgUnitRoots()\"\n [program]=\"config().program\"\n (formUpdate)=\"onFormUpdate($event)\"\n (formValidityUpdate)=\"onValidityUpdate($event)\"\n /> -->\n }\n\n <!-- SECTION display -->\n @case ('SECTION') { Section form }\n\n <!-- CUSTOM FORM -->\n @case ('CUSTOM') { } }\n\n <!-- Action buttons -->\n\n @if(!config().hideActionButtons) {\n <ng-dhis2-ui-wrapper [component]=\"FormActionButtons()\" />\n }\n</div>\n}\n", styles: ["::ng-deep .program-entry__form-loader{padding:8px}\n"] }]
11220
13056
  }], propDecorators: { instanceSave: [{
11221
13057
  type: Output
11222
13058
  }], instanceSaveCompleted: [{