@iapps/ng-dhis2-ui 1.2.133 → 1.2.134

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.
@@ -6536,6 +6536,157 @@ const CoordinatePickerField = ({ label, name, value, required, disabled, error,
6536
6536
  React__default.createElement(Button$1, { primary: true, onClick: handleConfirmFromMap, disabled: !pendingCoordinate }, "Use Selected Location")))))));
6537
6537
  };
6538
6538
 
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);
6582
+ }
6583
+ return digits.slice(0, 10);
6584
+ }
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);
6607
+ }
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);
6629
+ }
6630
+ else {
6631
+ setLeadingZeroWarning(null);
6632
+ }
6633
+ ui = ui.slice(0, 9);
6634
+ const stored = ui ? '0' + ui : '';
6635
+ setLocalNumber(ui);
6636
+ onChange(stored);
6637
+ }
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, { 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
+ };
6689
+
6539
6690
  // Copyright 2024 UDSM DHIS2 Lab. All rights reserved.
6540
6691
  // Use of this source code is governed by a BSD-style
6541
6692
  // license that can be found in the LICENSE file.
@@ -6661,7 +6812,6 @@ class BaseFormFieldComponent extends ReactWrapperModule {
6661
6812
  value &&
6662
6813
  value.length > 0 &&
6663
6814
  touched)) {
6664
- // if (this.field().unique && value && value.length > 0 && touched) {
6665
6815
  setCheckingUniqueness(true);
6666
6816
  setRecordExistError(undefined);
6667
6817
  try {
@@ -6684,6 +6834,18 @@ class BaseFormFieldComponent extends ReactWrapperModule {
6684
6834
  };
6685
6835
  const formFieldContent = () => {
6686
6836
  switch (this.field().controlType) {
6837
+ 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
+ } }));
6843
+ 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
+ } }));
6687
6849
  case 'coordinate':
6688
6850
  return (React__default.createElement("div", { style: { display: 'flex', flexDirection: 'column', gap: 12 } },
6689
6851
  React__default.createElement(NoticeBox, { title: "Location capture required" },
@@ -6772,9 +6934,7 @@ class BaseFormFieldComponent extends ReactWrapperModule {
6772
6934
  case 'date-time': {
6773
6935
  const field = this.field();
6774
6936
  const isDateTimeField = field.type === 'date-time';
6775
- const inputType = isDateTimeField
6776
- ? 'datetime-local'
6777
- : 'date';
6937
+ const inputType = isDateTimeField ? 'datetime-local' : 'date';
6778
6938
  // Value coming from DHIS2 store
6779
6939
  const htmlValue = this.formatValueForHtmlInputFromDhis(value, isDateTimeField);
6780
6940
  const htmlMin = field.min
@@ -7780,9 +7940,9 @@ class FieldUtil {
7780
7940
  case FieldType.TRUE_ONLY:
7781
7941
  return 'checkbox';
7782
7942
  case FieldType.NUMBER:
7783
- return 'textbox';
7943
+ return 'number';
7784
7944
  case FieldType.PHONE_NUMBER:
7785
- return 'textbox';
7945
+ return 'tel';
7786
7946
  case FieldType.ORG_UNIT:
7787
7947
  return 'org-unit';
7788
7948
  case FieldType.DATE:
@@ -7826,7 +7986,9 @@ class FieldControlTypeUtil {
7826
7986
  case FieldType.TRUE_ONLY:
7827
7987
  return 'checkbox';
7828
7988
  case FieldType.NUMBER:
7829
- return 'textbox';
7989
+ return 'number';
7990
+ case FieldType.PHONE_NUMBER:
7991
+ return 'tel';
7830
7992
  case FieldType.INTEGER_ZERO_OR_POSITIVE:
7831
7993
  return 'textbox';
7832
7994
  case FieldType.ORG_UNIT:
@@ -7864,6 +8026,8 @@ class FormFieldTypeUtil {
7864
8026
  return 'coordinate';
7865
8027
  case FieldType.DATE_TIME:
7866
8028
  return 'date-time';
8029
+ case FieldType.PHONE_NUMBER:
8030
+ return 'tel';
7867
8031
  default:
7868
8032
  return 'text';
7869
8033
  }