@iapps/ng-dhis2-ui 1.2.153 → 1.2.155

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.
@@ -8818,6 +8818,84 @@ class BaseFormFieldComponent extends ReactWrapperModule {
8818
8818
  // Stable React key, avoids generateUUID re-mounting.
8819
8819
  return String(option?.value ?? option?.id ?? option?.code ?? option?.label ?? '');
8820
8820
  }
8821
+ formatValueForHtmlInputFromDhis(rawValue, isDateTimeField) {
8822
+ if (rawValue == null)
8823
+ return '';
8824
+ const trimmed = String(rawValue).trim();
8825
+ if (!trimmed)
8826
+ return '';
8827
+ const pad = (n) => String(n).padStart(2, '0');
8828
+ if (!isDateTimeField) {
8829
+ // Already in HTML date format
8830
+ if (/^\d{4}-\d{2}-\d{2}$/.test(trimmed)) {
8831
+ return trimmed;
8832
+ }
8833
+ // ISO-like datetime -> preserve calendar date portion directly
8834
+ const datePartMatch = trimmed.match(/^(\d{4}-\d{2}-\d{2})[T\s]/);
8835
+ if (datePartMatch) {
8836
+ return datePartMatch[1];
8837
+ }
8838
+ // Fallback parse only if needed
8839
+ const date = new Date(trimmed);
8840
+ if (Number.isNaN(date.getTime())) {
8841
+ return '';
8842
+ }
8843
+ return (`${date.getFullYear()}-` +
8844
+ `${pad(date.getMonth() + 1)}-` +
8845
+ `${pad(date.getDate())}`);
8846
+ }
8847
+ // Already in HTML datetime-local format
8848
+ if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$/.test(trimmed)) {
8849
+ return trimmed;
8850
+ }
8851
+ // ISO-like datetime with optional seconds/timezone -> keep YYYY-MM-DDTHH:mm only
8852
+ const dateTimeMatch = trimmed.match(/^(\d{4}-\d{2}-\d{2})[T\s](\d{2}):(\d{2})/);
8853
+ if (dateTimeMatch) {
8854
+ return `${dateTimeMatch[1]}T${dateTimeMatch[2]}:${dateTimeMatch[3]}`;
8855
+ }
8856
+ const parsedDate = new Date(trimmed);
8857
+ if (Number.isNaN(parsedDate.getTime())) {
8858
+ return '';
8859
+ }
8860
+ const year = parsedDate.getFullYear();
8861
+ const month = pad(parsedDate.getMonth() + 1);
8862
+ const day = pad(parsedDate.getDate());
8863
+ const hours = pad(parsedDate.getHours());
8864
+ const minutes = pad(parsedDate.getMinutes());
8865
+ return `${year}-${month}-${day}T${hours}:${minutes}`;
8866
+ }
8867
+ pickEarlierDateLimit(metadataMax, systemMax) {
8868
+ if (!metadataMax && !systemMax)
8869
+ return undefined;
8870
+ if (!metadataMax)
8871
+ return systemMax;
8872
+ if (!systemMax)
8873
+ return metadataMax;
8874
+ return metadataMax < systemMax ? metadataMax : systemMax;
8875
+ }
8876
+ getNowForHtmlDateInput(isDateTimeField) {
8877
+ const now = new Date();
8878
+ const pad = (n) => String(n).padStart(2, '0');
8879
+ const datePart = `${now.getFullYear()}-` +
8880
+ `${pad(now.getMonth() + 1)}-` +
8881
+ `${pad(now.getDate())}`;
8882
+ if (!isDateTimeField) {
8883
+ return datePart;
8884
+ }
8885
+ const timePart = `${pad(now.getHours())}:${pad(now.getMinutes())}`;
8886
+ return `${datePart}T${timePart}`;
8887
+ }
8888
+ resolveHtmlMax(field, isDateTimeField) {
8889
+ // When future dates are allowed, do not limit picker selection at all
8890
+ if (field.allowFutureDate === true) {
8891
+ return undefined;
8892
+ }
8893
+ const metadataMax = field.max
8894
+ ? this.formatValueForHtmlInputFromDhis(String(field.max), isDateTimeField)
8895
+ : undefined;
8896
+ const systemMax = this.getNowForHtmlDateInput(isDateTimeField);
8897
+ return this.pickEarlierDateLimit(metadataMax, systemMax);
8898
+ }
8821
8899
  #getInputField() {
8822
8900
  return () => {
8823
8901
  const fg = this.form();
@@ -9025,18 +9103,23 @@ class BaseFormFieldComponent extends ReactWrapperModule {
9025
9103
  case 'date':
9026
9104
  case 'date-time': {
9027
9105
  const isDateTimeField = f.type === 'date-time';
9028
- const inputType = isDateTimeField ? 'datetime-local' : 'date';
9029
- const htmlValue = this.formatValueForHtmlInputFromDhis(value, isDateTimeField);
9030
- const htmlMin = f.min
9106
+ const inputType = isDateTimeField
9107
+ ? 'datetime-local'
9108
+ : 'date';
9109
+ const allowFutureDate = f.allowFutureDate === true;
9110
+ const htmlValue = value != null && String(value).trim() !== ''
9111
+ ? this.formatValueForHtmlInputFromDhis(String(value), isDateTimeField)
9112
+ : '';
9113
+ const htmlMin = f.min != null && String(f.min).trim() !== ''
9031
9114
  ? this.formatValueForHtmlInputFromDhis(String(f.min), isDateTimeField)
9032
9115
  : undefined;
9033
- const metadataMax = f.max
9034
- ? this.formatValueForHtmlInputFromDhis(String(f.max), isDateTimeField)
9035
- : undefined;
9036
- const systemMax = this.getNowForHtmlDateInput(isDateTimeField);
9037
- const htmlMax = this.pickEarlierDateLimit(metadataMax, systemMax);
9116
+ const htmlMax = allowFutureDate
9117
+ ? undefined
9118
+ : f.max
9119
+ ? this.pickEarlierDateLimit(this.formatValueForHtmlInputFromDhis(String(f.max), isDateTimeField), this.getNowForHtmlDateInput(isDateTimeField))
9120
+ : this.getNowForHtmlDateInput(isDateTimeField);
9038
9121
  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 }) => {
9039
- const normalized = this.normalizeDateValueFromHtmlInput(newValue, isDateTimeField, true);
9122
+ const normalized = this.normalizeDateValueFromHtmlInput(newValue, isDateTimeField, allowFutureDate);
9040
9123
  onValueChange(normalized);
9041
9124
  }, onBlur: () => checkValueUniqueness() }));
9042
9125
  }
@@ -9085,57 +9168,6 @@ class BaseFormFieldComponent extends ReactWrapperModule {
9085
9168
  `${pad(date.getHours())}:` +
9086
9169
  `${pad(date.getMinutes())}`);
9087
9170
  }
9088
- formatValueForHtmlInputFromDhis(rawValue, isDateTimeField) {
9089
- if (!rawValue)
9090
- return '';
9091
- const trimmed = rawValue.trim();
9092
- if (!trimmed)
9093
- return '';
9094
- const pad = (n) => String(n).padStart(2, '0');
9095
- if (!isDateTimeField) {
9096
- if (/^\d{4}-\d{2}-\d{2}$/.test(trimmed)) {
9097
- return trimmed;
9098
- }
9099
- const date = new Date(trimmed);
9100
- if (Number.isNaN(date.getTime())) {
9101
- return '';
9102
- }
9103
- return (`${date.getFullYear()}-` +
9104
- `${pad(date.getMonth() + 1)}-` +
9105
- `${pad(date.getDate())}`);
9106
- }
9107
- const parsedDate = new Date(trimmed);
9108
- if (Number.isNaN(parsedDate.getTime())) {
9109
- return '';
9110
- }
9111
- const year = parsedDate.getFullYear();
9112
- const month = pad(parsedDate.getMonth() + 1);
9113
- const day = pad(parsedDate.getDate());
9114
- const hours = pad(parsedDate.getHours());
9115
- const minutes = pad(parsedDate.getMinutes());
9116
- return `${year}-${month}-${day}T${hours}:${minutes}`;
9117
- }
9118
- getNowForHtmlDateInput(isDateTimeField) {
9119
- const now = new Date();
9120
- const pad = (n) => String(n).padStart(2, '0');
9121
- const datePart = `${now.getFullYear()}-` +
9122
- `${pad(now.getMonth() + 1)}-` +
9123
- `${pad(now.getDate())}`;
9124
- if (!isDateTimeField) {
9125
- return datePart;
9126
- }
9127
- const timePart = `${pad(now.getHours())}:` + `${pad(now.getMinutes())}`;
9128
- return `${datePart}T${timePart}`;
9129
- }
9130
- pickEarlierDateLimit(metadataMax, systemMax) {
9131
- if (!metadataMax && !systemMax)
9132
- return undefined;
9133
- if (!metadataMax)
9134
- return systemMax;
9135
- if (!systemMax)
9136
- return metadataMax;
9137
- return metadataMax < systemMax ? metadataMax : systemMax;
9138
- }
9139
9171
  /**
9140
9172
  * Normalizes value from the HTML input into DHIS storage format.
9141
9173
  *
@@ -9147,9 +9179,9 @@ class BaseFormFieldComponent extends ReactWrapperModule {
9147
9179
  * - Input: "YYYY-MM-DDTHH:mm" (local)
9148
9180
  * - Output: ISO string in UTC: "YYYY-MM-DDTHH:mm:ss.sssZ"
9149
9181
  *
9150
- * If disallowFuture = true, any value beyond "now" is clamped to now.
9182
+ * If allowFutureDate = false, any value beyond "now" is clamped to now.
9151
9183
  */
9152
- normalizeDateValueFromHtmlInput(inputValue, isDateTimeField, disallowFuture) {
9184
+ normalizeDateValueFromHtmlInput(inputValue, isDateTimeField, allowFutureDate) {
9153
9185
  const trimmed = (inputValue ?? '').trim();
9154
9186
  if (!trimmed)
9155
9187
  return null;
@@ -9157,7 +9189,7 @@ class BaseFormFieldComponent extends ReactWrapperModule {
9157
9189
  if (!/^\d{4}-\d{2}-\d{2}$/.test(trimmed)) {
9158
9190
  return null;
9159
9191
  }
9160
- if (disallowFuture) {
9192
+ if (!allowFutureDate) {
9161
9193
  const todayStr = this.getNowForHtmlDateInput(false);
9162
9194
  if (trimmed > todayStr) {
9163
9195
  return todayStr;
@@ -9170,22 +9202,38 @@ class BaseFormFieldComponent extends ReactWrapperModule {
9170
9202
  if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$/.test(trimmed)) {
9171
9203
  return null;
9172
9204
  }
9173
- // Interpret as LOCAL time
9174
- const localDate = new Date(trimmed);
9175
- if (Number.isNaN(localDate.getTime())) {
9205
+ // Interpret selected datetime as EAT, not UTC/GMT
9206
+ const eatDateTimeValue = `${trimmed}:00.000+03:00`;
9207
+ const eatDate = new Date(eatDateTimeValue);
9208
+ if (Number.isNaN(eatDate.getTime())) {
9176
9209
  return null;
9177
9210
  }
9178
- if (disallowFuture) {
9211
+ if (!allowFutureDate) {
9179
9212
  const now = new Date();
9180
- if (localDate.getTime() > now.getTime()) {
9181
- // Option A: clamp to now
9182
- return now.toISOString();
9183
- // Option B: reject:
9184
- // return null;
9213
+ if (eatDate.getTime() > now.getTime()) {
9214
+ return this.getNowInEatIsoString();
9185
9215
  }
9186
9216
  }
9187
- // Store as UTC ISO string with millis, e.g. "2025-11-26T21:01:00.000Z"
9188
- return localDate.toISOString();
9217
+ return eatDateTimeValue;
9218
+ }
9219
+ getNowInEatIsoString() {
9220
+ const formatter = new Intl.DateTimeFormat('en-GB', {
9221
+ timeZone: 'Africa/Dar_es_Salaam',
9222
+ year: 'numeric',
9223
+ month: '2-digit',
9224
+ day: '2-digit',
9225
+ hour: '2-digit',
9226
+ minute: '2-digit',
9227
+ second: '2-digit',
9228
+ hourCycle: 'h23',
9229
+ });
9230
+ const parts = formatter.formatToParts(new Date()).reduce((acc, part) => {
9231
+ if (part.type !== 'literal') {
9232
+ acc[part.type] = part.value;
9233
+ }
9234
+ return acc;
9235
+ }, {});
9236
+ return `${parts['year']}-${parts['month']}-${parts['day']}T${parts['hour']}:${parts['minute']}:${parts['second']}.000+03:00`;
9189
9237
  }
9190
9238
  async searchForDuplicates(value) {
9191
9239
  const d2 = window.d2Web;
@@ -10219,6 +10267,7 @@ class FormFieldGroup {
10219
10267
  controlType: FieldUtil.getFieldControlType(fieldMetaData['valueType'], hasOptions),
10220
10268
  metaType: fieldMetaData['metaType'],
10221
10269
  stepId: fieldMetaData['stepId'],
10270
+ allowFutureDate: fieldMetaData['allowFutureDate'],
10222
10271
  extension,
10223
10272
  });
10224
10273
  })
@@ -10804,6 +10853,7 @@ class FormUtil {
10804
10853
  min: field.min,
10805
10854
  max: field.max,
10806
10855
  maxLength: field.maxLength,
10856
+ allowFutureDate: field.allowFutureDate,
10807
10857
  });
10808
10858
  });
10809
10859
  }
@@ -11921,6 +11971,8 @@ class ProgramEntryFormFieldUtil {
11921
11971
  controlType: FieldUtil.getFieldControlType(field.valueType, hasOptions),
11922
11972
  metaType: field.metaType,
11923
11973
  stepId: field.stepId,
11974
+ allowFutureDate: field
11975
+ .allowFutureDate,
11924
11976
  extension,
11925
11977
  });
11926
11978
  })
@@ -11957,334 +12009,6 @@ class ProgramStageEntryFormSection {
11957
12009
  }
11958
12010
  }
11959
12011
 
11960
- /* eslint-disable @typescript-eslint/no-explicit-any */
11961
- // // // Copyright 2025 UDSM DHIS2 Lab. All rights reserved.
11962
- // // // Use of this source code is governed by a BSD-style
11963
- // // // license that can be found in the LICENSE file.
11964
- // import { camelCase, isUndefined } from 'lodash';
11965
- // import { Program, ProgramStage, ProgramStageSection } from '@iapps/d2-web-sdk';
11966
- // import {
11967
- // IProgramStageEntryFormSection,
11968
- // ProgramStageEntryFormSection,
11969
- // } from '../models/program-stage-entry-form-section.model';
11970
- // import { ProgramEntryFormConfig } from '../models/program-entry-form.config';
11971
- // import { IFormField } from '../../form/interfaces/form-field.interface';
11972
- // import { FieldDropdown } from '../../form/models/field-dropdown.model';
11973
- // import { FormField } from '../../form/models/form-field.model';
11974
- // import { FieldUtil } from '../../form/utils';
11975
- // import { ProgramEntryFormFieldUtil } from './program-entry-form-field.util';
11976
- // // import {
11977
- // // IProgramStageEntryFormSection,
11978
- // // ProgramEntryFormConfig,
11979
- // // ProgramStageEntryFormSection,
11980
- // // } from '../models';
11981
- // // TODO: START - DEPRECATED APPROACH
11982
- // // import { Program, ProgramStage, ProgramStageSection } from '@iapps/d2-web-sdk';
11983
- // // import {
11984
- // // IProgramStageEntryFormSection,
11985
- // // ProgramEntryFormConfig,
11986
- // // ProgramStageEntryFormSection,
11987
- // // } from '../models';
11988
- // // export class ProgramStageEntryFormSectionUtil {
11989
- // // constructor(
11990
- // // private program: Program,
11991
- // // private config: ProgramEntryFormConfig
11992
- // // ) {}
11993
- // // // get getProgramStageSections(): IProgramStageEntryFormSection[] {
11994
- // // // return (this.program.programStages || []).flatMap((stage) =>
11995
- // // // (stage.programStageSections || []).map(
11996
- // // // (programStageSection: ProgramStageSection) =>
11997
- // // // new ProgramStageSection(programStageSection)
11998
- // // // )
11999
- // // // );
12000
- // // // }
12001
- // // get programStageEntryFormSections(): IProgramStageEntryFormSection[] {
12002
- // // return (this.program.programStages || []).flatMap((stage: ProgramStage) =>
12003
- // // (stage.programStageSections || []).map(
12004
- // // (section: ProgramStageSection) =>
12005
- // // new ProgramStageEntryFormSection({
12006
- // // id: section.id,
12007
- // // name: section.displayName,
12008
- // // description: '',
12009
- // // formFields: fieldsForSection(stage, section),
12010
- // // orientation: 'HORIZONTAL',
12011
- // // })
12012
- // // )
12013
- // // );
12014
- // // }
12015
- // // }
12016
- // // TODO: END - DEPRECATED APPROACH
12017
- // // export class ProgramStageEntryFormSectionUtil {
12018
- // // constructor(
12019
- // // private program: Program,
12020
- // // private config: ProgramEntryFormConfig
12021
- // // ) {}
12022
- // // get programStageEntryFormSections(): IProgramStageEntryFormSection[] {
12023
- // // const stageId = this.#getStageIdFromConfig();
12024
- // // if (!stageId) return [];
12025
- // // const programStage = this.#findStageById(stageId);
12026
- // // if (!programStage) return [];
12027
- // // return (programStage.programStageSections || []).map(
12028
- // // (section: ProgramStageSection) =>
12029
- // // new ProgramStageEntryFormSection({
12030
- // // id: section.id,
12031
- // // name: section.displayName,
12032
- // // description: section?.description,
12033
- // // formFields: this.#mapSectionToFormFields(programStage, section),
12034
- // // orientation: 'HORIZONTAL',
12035
- // // })
12036
- // // );
12037
- // // }
12038
- // // #getStageIdFromConfig(): string | null {
12039
- // // const programStageRef: any = (this.config as any)?.programStage;
12040
- // // if (!programStageRef) return null;
12041
- // // if (typeof programStageRef === 'string' && programStageRef.trim()) {
12042
- // // return programStageRef.trim();
12043
- // // }
12044
- // // const candidateId =
12045
- // // programStageRef.id ??
12046
- // // programStageRef.stageId ??
12047
- // // programStageRef.programStageId ??
12048
- // // programStageRef.value?.id ??
12049
- // // null;
12050
- // // return typeof candidateId === 'string' && candidateId.trim()
12051
- // // ? candidateId.trim()
12052
- // // : null;
12053
- // // }
12054
- // // #findStageById(stageId: string): ProgramStage | null {
12055
- // // return (
12056
- // // (this.program.programStages || []).find(
12057
- // // (stage: ProgramStage) => (stage as any)?.id === stageId
12058
- // // ) ?? null
12059
- // // );
12060
- // // }
12061
- // // #mapSectionToFormFields(
12062
- // // stage: ProgramStage,
12063
- // // section: ProgramStageSection
12064
- // // ): IFormField<string>[] {
12065
- // // const stageDataElements: any[] =
12066
- // // (stage as any).programStageDataElements || [];
12067
- // // const sectionElementIds: string[] =
12068
- // // (section as any).dataElements?.map((d: { id: string }) => d.id) ??
12069
- // // (section as any).dataElementsIds ??
12070
- // // [];
12071
- // // const relevantStageElements = sectionElementIds.length
12072
- // // ? stageDataElements.filter((pde) =>
12073
- // // sectionElementIds.includes(pde?.dataElement?.id)
12074
- // // )
12075
- // // : stageDataElements;
12076
- // // const mappedFields = relevantStageElements
12077
- // // .map((pde) => this.#mapDataElementToFormField(pde, stage.id))
12078
- // // .filter((field): field is IFormField<string> => field != null)
12079
- // // .sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
12080
- // // const extraReportFields = (this as any)?.reportFields ?? [];
12081
- // // return [...extraReportFields, ...mappedFields];
12082
- // // }
12083
- // // #mapDataElementToFormField(
12084
- // // pde: any,
12085
- // // stageId: string
12086
- // // ): IFormField<string> | null {
12087
- // // const dataElement = pde?.dataElement;
12088
- // // if (!dataElement?.id) return null;
12089
- // // const baseField = {
12090
- // // id: dataElement.id,
12091
- // // code: dataElement.code,
12092
- // // formName: dataElement.formName,
12093
- // // name: dataElement.displayName,
12094
- // // mandatory: !!pde.compulsory,
12095
- // // valueType: dataElement.valueType,
12096
- // // sortOrder: pde.sortOrder,
12097
- // // stepId: stageId,
12098
- // // optionSet: dataElement.optionSet,
12099
- // // };
12100
- // // const options = FieldDropdown.getDropdownOptions(baseField);
12101
- // // const hasOptions = options?.length > 0;
12102
- // // const fieldExtension = this.config.formFieldExtensions?.find(
12103
- // // (fx: any) => fx?.id === baseField.id
12104
- // // );
12105
- // // const autoAssignedValue = this.#getAutoAssignedValue(baseField);
12106
- // // if (
12107
- // // !isUndefined(autoAssignedValue) &&
12108
- // // this.config.hideCustomAssignedFields
12109
- // // ) {
12110
- // // return null;
12111
- // // }
12112
- // // return new FormField<string>({
12113
- // // ...baseField,
12114
- // // label: baseField.formName || baseField.name,
12115
- // // key: baseField.code ? camelCase(baseField.code) : baseField.id,
12116
- // // required: baseField.mandatory,
12117
- // // type: FieldUtil.getFieldType(baseField.valueType),
12118
- // // options,
12119
- // // disabled: this.#getDisabledStatus(baseField),
12120
- // // order: baseField.sortOrder,
12121
- // // hasOptions,
12122
- // // controlType: FieldUtil.getFieldControlType(
12123
- // // baseField.valueType,
12124
- // // hasOptions
12125
- // // ),
12126
- // // extension: fieldExtension,
12127
- // // });
12128
- // // }
12129
- // // #getAutoAssignedValue(field: any): unknown {
12130
- // // const impl = (this as any)?.['#getAutoAssignedValue'];
12131
- // // return typeof impl === 'function' ? impl.call(this, field) : undefined;
12132
- // // }
12133
- // // #getDisabledStatus(field: any): boolean {
12134
- // // const impl = (this as any)?.['#getDisabledStatus'];
12135
- // // return typeof impl === 'function' ? impl.call(this, field) : false;
12136
- // // }
12137
- // // }
12138
- // export class ProgramStageEntryFormSectionUtil {
12139
- // private readonly fieldUtil: ProgramEntryFormFieldUtil;
12140
- // constructor(
12141
- // private readonly program: Program,
12142
- // private readonly config: ProgramEntryFormConfig
12143
- // ) {
12144
- // this.fieldUtil = new ProgramEntryFormFieldUtil(program, config);
12145
- // }
12146
- // get programStageEntryFormSections(): IProgramStageEntryFormSection[] {
12147
- // const stageId = this.#getStageIdFromConfig();
12148
- // if (!stageId || !this.program) {
12149
- // return [];
12150
- // }
12151
- // const programStage = this.#findStageById(stageId);
12152
- // if (!programStage) {
12153
- // return [];
12154
- // }
12155
- // const sections: IProgramStageEntryFormSection[] = [];
12156
- // const basicDetailsFields = this.fieldUtil.eventReportFields;
12157
- // if (basicDetailsFields?.length) {
12158
- // sections.push(
12159
- // new ProgramStageEntryFormSection({
12160
- // id: `${programStage.id}_basic_information`,
12161
- // name: 'Basic Information',
12162
- // description: '',
12163
- // formFields: basicDetailsFields,
12164
- // orientation: 'VERTICAL',
12165
- // })
12166
- // );
12167
- // }
12168
- // const stageSections = programStage.programStageSections ?? [];
12169
- // for (const section of stageSections) {
12170
- // const sectionFormFields = this.#mapSectionToFormFields(
12171
- // programStage,
12172
- // section
12173
- // );
12174
- // if (!sectionFormFields.length) {
12175
- // continue;
12176
- // }
12177
- // sections.push(
12178
- // new ProgramStageEntryFormSection({
12179
- // id: section.id,
12180
- // name: section.displayName,
12181
- // description: section?.description,
12182
- // formFields: sectionFormFields,
12183
- // orientation: 'HORIZONTAL',
12184
- // })
12185
- // );
12186
- // }
12187
- // return sections;
12188
- // }
12189
- // #getStageIdFromConfig(): string | null {
12190
- // const programStageRef: any = (this.config as any)?.programStage;
12191
- // if (!programStageRef) return null;
12192
- // if (typeof programStageRef === 'string' && programStageRef.trim()) {
12193
- // return programStageRef.trim();
12194
- // }
12195
- // const candidateId =
12196
- // programStageRef.id ??
12197
- // programStageRef.stageId ??
12198
- // programStageRef.programStageId ??
12199
- // programStageRef.value?.id ??
12200
- // null;
12201
- // return typeof candidateId === 'string' && candidateId.trim()
12202
- // ? candidateId.trim()
12203
- // : null;
12204
- // }
12205
- // #findStageById(stageId: string): ProgramStage | null {
12206
- // return (
12207
- // (this.program.programStages || []).find(
12208
- // (stage: ProgramStage) => (stage as any)?.id === stageId
12209
- // ) ?? null
12210
- // );
12211
- // }
12212
- // #mapSectionToFormFields(
12213
- // stage: ProgramStage,
12214
- // section: ProgramStageSection
12215
- // ): IFormField<string>[] {
12216
- // const stageDataElements: any[] =
12217
- // (stage as any).programStageDataElements || [];
12218
- // const sectionElementIds: string[] =
12219
- // (section as any).dataElements?.map((d: { id: string }) => d.id) ??
12220
- // (section as any).dataElementsIds ??
12221
- // [];
12222
- // const relevantStageElements = sectionElementIds.length
12223
- // ? stageDataElements.filter((pde) =>
12224
- // sectionElementIds.includes(pde?.dataElement?.id)
12225
- // )
12226
- // : stageDataElements;
12227
- // const mappedFields = relevantStageElements
12228
- // .map((pde) => this.#mapDataElementToFormField(pde, stage.id))
12229
- // .filter((field): field is IFormField<string> => field != null)
12230
- // .sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
12231
- // return mappedFields;
12232
- // }
12233
- // #mapDataElementToFormField(
12234
- // pde: any,
12235
- // stageId: string
12236
- // ): IFormField<string> | null {
12237
- // const dataElement = pde?.dataElement;
12238
- // if (!dataElement?.id) return null;
12239
- // const baseField = {
12240
- // id: dataElement.id,
12241
- // code: dataElement.code,
12242
- // formName: dataElement.formName,
12243
- // name: dataElement.displayName,
12244
- // mandatory: !!pde.compulsory,
12245
- // valueType: dataElement.valueType,
12246
- // sortOrder: pde.sortOrder,
12247
- // stepId: stageId,
12248
- // optionSet: dataElement.optionSet,
12249
- // };
12250
- // const options = FieldDropdown.getDropdownOptions(baseField);
12251
- // const hasOptions = options?.length > 0;
12252
- // const fieldExtension = this.config.formFieldExtensions?.find(
12253
- // (fx: any) => fx?.id === baseField.id
12254
- // );
12255
- // const autoAssignedValue = this.#getAutoAssignedValue(baseField);
12256
- // if (
12257
- // !isUndefined(autoAssignedValue) &&
12258
- // this.config.hideCustomAssignedFields
12259
- // ) {
12260
- // return null;
12261
- // }
12262
- // return new FormField<string>({
12263
- // ...baseField,
12264
- // label: baseField.formName || baseField.name,
12265
- // key: baseField.code ? camelCase(baseField.code) : baseField.id,
12266
- // required: baseField.mandatory,
12267
- // type: FieldUtil.getFieldType(baseField.valueType),
12268
- // options,
12269
- // disabled: this.#getDisabledStatus(baseField),
12270
- // order: baseField.sortOrder,
12271
- // hasOptions,
12272
- // controlType: FieldUtil.getFieldControlType(
12273
- // baseField.valueType,
12274
- // hasOptions
12275
- // ),
12276
- // extension: fieldExtension,
12277
- // });
12278
- // }
12279
- // #getAutoAssignedValue(field: any): unknown {
12280
- // const impl = (this as any)?.['#getAutoAssignedValue'];
12281
- // return typeof impl === 'function' ? impl.call(this, field) : undefined;
12282
- // }
12283
- // #getDisabledStatus(field: any): boolean {
12284
- // const impl = (this as any)?.['#getDisabledStatus'];
12285
- // return typeof impl === 'function' ? impl.call(this, field) : false;
12286
- // }
12287
- // }
12288
12012
  class ProgramStageEntryFormSectionUtil {
12289
12013
  #sortedCanonicalStageFieldsCache = null;
12290
12014
  constructor(program, config) {
@@ -12397,6 +12121,7 @@ class ProgramStageEntryFormSectionUtil {
12397
12121
  valueType: dataElementDefinition.valueType,
12398
12122
  sortOrder: programStageDataElement.sortOrder,
12399
12123
  stepId: programStageId,
12124
+ allowFutureDate: programStageDataElement.allowFutureDate,
12400
12125
  optionSet: dataElementDefinition.optionSet,
12401
12126
  };
12402
12127
  const dropdownOptions = FieldDropdown.getDropdownOptions(fieldBaseConfig);