nox-validation 1.5.9 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/helpers.js CHANGED
@@ -1456,6 +1456,74 @@ const getSelectedNodes = ({
1456
1456
  return result;
1457
1457
  };
1458
1458
 
1459
+ const getParts = (date, timeZone) => {
1460
+ const formatter = new Intl.DateTimeFormat("en-US", {
1461
+ timeZone,
1462
+ year: "numeric",
1463
+ month: "2-digit",
1464
+ day: "2-digit",
1465
+ hour: "2-digit",
1466
+ minute: "2-digit",
1467
+ second: "2-digit",
1468
+ hour12: true,
1469
+ });
1470
+
1471
+ const parts = {};
1472
+ formatter.formatToParts(new Date(date)).forEach(({ type, value }) => {
1473
+ parts[type] = value;
1474
+ });
1475
+
1476
+ return {
1477
+ year: parts.year,
1478
+ month: parts.month,
1479
+ day: parts.day,
1480
+ hour: parts.hour,
1481
+ minute: parts.minute,
1482
+ second: parts.second,
1483
+ dayPeriod: parts.dayPeriod, // AM/PM
1484
+ };
1485
+ };
1486
+
1487
+ const formatDate = ({
1488
+ date,
1489
+ timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone,
1490
+ format,
1491
+ }) => {
1492
+ const formats = [
1493
+ "MM/DD/YYYY h:mm A",
1494
+ "M/D/YYYY h:mm A",
1495
+ "YYYY-MM-DD HH:mm",
1496
+ "DD/MM/YYYY HH:mm",
1497
+ "DD-MM-YYYY HH:mm",
1498
+ "MM/DD/YYYY h:mm:ss A",
1499
+ "DD/MM/YYYY HH:mm:ss",
1500
+ "DD-MM-YYYY HH:mm:ss",
1501
+ "YYYY-MM-DD HH:mm:ss",
1502
+ "YYYY.MM.DD HH:mm:ss",
1503
+ ];
1504
+
1505
+ if (!formats.includes(format)) format = formats[0];
1506
+
1507
+ const { year, month, day, hour, minute, second, dayPeriod } = getParts(
1508
+ date,
1509
+ timeZone
1510
+ );
1511
+
1512
+ let hour24 = Number(hour);
1513
+ if (dayPeriod === "PM" && hour24 !== 12) hour24 += 12;
1514
+ if (dayPeriod === "AM" && hour24 === 12) hour24 = 0;
1515
+
1516
+ return format
1517
+ .replace("YYYY", year)
1518
+ .replace("MM", month)
1519
+ .replace("DD", day)
1520
+ .replace("HH", String(hour24).padStart(2, "0"))
1521
+ .replace("h", String(hour24 % 12 || 12))
1522
+ .replace("mm", minute)
1523
+ .replace("ss", second)
1524
+ .replace("A", dayPeriod);
1525
+ };
1526
+
1459
1527
  module.exports = {
1460
1528
  generateModifiedRules,
1461
1529
  getFieldsGroupBySchemaId,
@@ -1478,4 +1546,5 @@ module.exports = {
1478
1546
  getM2AItemParentPath,
1479
1547
  getSelectedNodes,
1480
1548
  remainingItems,
1549
+ formatDate,
1481
1550
  };
package/lib/validate.js CHANGED
@@ -12,6 +12,7 @@ const {
12
12
  getM2AItemParentPath,
13
13
  getSelectedNodes,
14
14
  remainingItems,
15
+ formatDate,
15
16
  } = require("./helpers");
16
17
 
17
18
  const choices = ["radio", "checkboxes", "dropdown_multiple", "dropdown"];
@@ -59,9 +60,20 @@ const typeChecks = {
59
60
  }
60
61
  return false;
61
62
  },
62
- [constants.types.TIME]: (val) =>
63
- typeof val === "string" &&
64
- /^([01]\d|2[0-3]):([0-5]\d):([0-5]\d)$/.test(val),
63
+ [constants.types.TIME]: (val, data) => {
64
+ if (val instanceof Date && !isNaN(val)) return true;
65
+ if (typeof val === "string") {
66
+ if (/^([01]\d|2[0-3]):([0-5]\d):([0-5]\d)$/.test(val)) return true;
67
+ const parsed = Date.parse(val);
68
+ if (!isNaN(parsed)) {
69
+ if (data && data?.key && data?.updateValue) {
70
+ data.updateValue(data.key, new Date(val));
71
+ }
72
+ return true;
73
+ }
74
+ }
75
+ return false;
76
+ },
65
77
  [constants.types.TIMESTAMP]: (val, data) => {
66
78
  if (val instanceof Date && !isNaN(val)) return true;
67
79
  if (typeof val === "string" && !isNaN(Date.parse(val))) {
@@ -410,6 +422,7 @@ const validateMetaRules = (
410
422
  if (
411
423
  (isEmpty(fieldValue) &&
412
424
  required &&
425
+ !field?.meta?.hidden &&
413
426
  ![
414
427
  constants.interfaces.FILES,
415
428
  constants.interfaces.FILE,
@@ -422,11 +435,13 @@ const validateMetaRules = (
422
435
  "none",
423
436
  ].includes(field?.meta?.interface)) ||
424
437
  (field?.meta?.interface === constants.interfaces.TRANSLATIONS &&
438
+ !field?.meta?.hidden &&
425
439
  language_codes?.length &&
426
440
  !onlyFormFields) ||
427
441
  ([constants.interfaces.OBJECT, constants.interfaces.ITEMS].includes(
428
442
  field?.meta?.interface
429
443
  ) &&
444
+ !field?.meta?.hidden &&
430
445
  !onlyFormFields &&
431
446
  getNodes)
432
447
  ) {
@@ -455,6 +470,7 @@ const validateMetaRules = (
455
470
  const message = error_messages.REQUIRED.replace("{field}", label);
456
471
 
457
472
  const buildError = (path, translated) => {
473
+ if (!isEmpty(getValue(formData, path))) return;
458
474
  let obj = {
459
475
  label,
460
476
  fieldPath: path,
@@ -625,10 +641,6 @@ const handleRegexValidation = (
625
641
  message = message
626
642
  ?.replace(`{field}`, fieldLabel)
627
643
  ?.replace(`{value}`, rule.value[0]);
628
- console.log(
629
- "[handleRegexValidation] Validation failed. Adding error. Message:",
630
- message
631
- );
632
644
  addError(
633
645
  currentPath,
634
646
  { label: fieldLabel, fieldPath: currentPath, description: "", message },
@@ -645,7 +657,8 @@ const validateOperatorRule = (
645
657
  currentPath,
646
658
  formData,
647
659
  error_messages,
648
- custom_message
660
+ custom_message,
661
+ timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone
649
662
  ) => {
650
663
  const { isFieldCompare = false } = rule?.options ?? {};
651
664
  let valid = false;
@@ -658,10 +671,40 @@ const validateOperatorRule = (
658
671
  const isTime = field.type === constants.types.TIME;
659
672
  const isArray = field.type === constants.types.ARRAY;
660
673
 
661
- const parseTime = (timeStr) => {
662
- if (!timeStr || typeof timeStr !== "string") return null;
663
- const [hh, mm, ss] = timeStr.split(":").map(Number);
664
- return hh * 3600 + mm * 60 + ss;
674
+ const parseTime = (value) => {
675
+ if (!value) return null;
676
+
677
+ const toSeconds = (str) => {
678
+ const [hh = 0, mm = 0, ss = 0] = str.split(":").map(Number);
679
+ return hh * 3600 + mm * 60 + ss;
680
+ };
681
+
682
+ if (value instanceof Date && !isNaN(value)) {
683
+ const timePart = formatDate({
684
+ date: value,
685
+ format: "DD/MM/YYYY HH:mm:ss",
686
+ timeZone,
687
+ }).split(" ")[1];
688
+ const totalSeconds = toSeconds(timePart);
689
+ return totalSeconds || null;
690
+ }
691
+
692
+ if (typeof value === "string") {
693
+ if (/^\d{1,2}:\d{2}:\d{2}$/.test(value)) {
694
+ return toSeconds(value);
695
+ }
696
+ if (!isNaN(Date.parse(value))) {
697
+ const timePart = formatDate({
698
+ date: value,
699
+ format: "DD/MM/YYYY HH:mm:ss",
700
+ timeZone,
701
+ }).split(" ")[1];
702
+ const totalSeconds = toSeconds(timePart);
703
+ return totalSeconds || null;
704
+ }
705
+ }
706
+
707
+ return null;
665
708
  };
666
709
 
667
710
  // Helper to parse date string to UTC midnight timestamp
@@ -698,7 +741,8 @@ const validateOperatorRule = (
698
741
  }
699
742
  if (isDateTime) {
700
743
  if (forMessage) {
701
- return value;
744
+ const format = field?.meta?.options?.format;
745
+ return formatDate({ date: value, format, timeZone });
702
746
  }
703
747
  // Return UTC timestamp for comparison
704
748
  return parseDateTimeToUTC(value);
@@ -889,7 +933,8 @@ const handleRule = (
889
933
  addError,
890
934
  currentPath,
891
935
  formData,
892
- error_messages
936
+ error_messages,
937
+ timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone
893
938
  ) => {
894
939
  const ruleValue = rule?.value;
895
940
  let messageValue = Array.isArray(ruleValue)
@@ -990,7 +1035,8 @@ const handleRule = (
990
1035
  currentPath,
991
1036
  formData,
992
1037
  error_messages,
993
- custom_message
1038
+ custom_message,
1039
+ timeZone
994
1040
  );
995
1041
  break;
996
1042
  default:
@@ -1011,7 +1057,8 @@ const validateField = (
1011
1057
  fieldOptions,
1012
1058
  language_codes,
1013
1059
  existingForm,
1014
- getNodes = true
1060
+ getNodes = true,
1061
+ timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone
1015
1062
  ) => {
1016
1063
  if (onlyFormFields == true && value === undefined) return;
1017
1064
 
@@ -1073,7 +1120,8 @@ const validateField = (
1073
1120
  fieldOptions,
1074
1121
  language_codes,
1075
1122
  existingForm,
1076
- false
1123
+ false,
1124
+ timeZone
1077
1125
  )
1078
1126
  );
1079
1127
  } else if (field.type === constants.types.ARRAY && Array.isArray(value)) {
@@ -1093,7 +1141,8 @@ const validateField = (
1093
1141
  addError,
1094
1142
  itemPath,
1095
1143
  formData,
1096
- error_messages
1144
+ error_messages,
1145
+ timeZone
1097
1146
  );
1098
1147
  }
1099
1148
 
@@ -1130,7 +1179,8 @@ const validateField = (
1130
1179
  fieldOptions,
1131
1180
  language_codes,
1132
1181
  existingForm,
1133
- false
1182
+ false,
1183
+ timeZone
1134
1184
  )
1135
1185
  );
1136
1186
  });
@@ -1143,7 +1193,8 @@ const validateField = (
1143
1193
  addError,
1144
1194
  currentPath,
1145
1195
  formData,
1146
- error_messages
1196
+ error_messages,
1197
+ timeZone
1147
1198
  )
1148
1199
  ) {
1149
1200
  addError(
@@ -1166,7 +1217,8 @@ const applyValidations = (
1166
1217
  addError,
1167
1218
  currentPath,
1168
1219
  formData,
1169
- error_messages
1220
+ error_messages,
1221
+ timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone
1170
1222
  ) => {
1171
1223
  if (
1172
1224
  !field.validations ||
@@ -1185,7 +1237,8 @@ const applyValidations = (
1185
1237
  addError,
1186
1238
  currentPath,
1187
1239
  formData,
1188
- error_messages
1240
+ error_messages,
1241
+ timeZone
1189
1242
  ) === false
1190
1243
  );
1191
1244
  };
@@ -1213,6 +1266,7 @@ const schema = {
1213
1266
  type: constants.types.ARRAY,
1214
1267
  array_type: constants.types.OBJECT_ID,
1215
1268
  },
1269
+ timeZone: { type: constants.types.STRING, array_type: null },
1216
1270
  };
1217
1271
 
1218
1272
  const validate = (data) => {
@@ -1239,6 +1293,7 @@ const validate = (data) => {
1239
1293
  maxLevel,
1240
1294
  onlyFormFields,
1241
1295
  existingForm = {},
1296
+ timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone,
1242
1297
  } = data;
1243
1298
 
1244
1299
  const error_messages =
@@ -1499,7 +1554,8 @@ const validate = (data) => {
1499
1554
  apiVersion,
1500
1555
  fieldOptions,
1501
1556
  data.language_codes,
1502
- existingForm
1557
+ existingForm,
1558
+ timeZone
1503
1559
  );
1504
1560
  });
1505
1561
  return result;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nox-validation",
3
- "version": "1.5.9",
3
+ "version": "1.6.1",
4
4
  "description": "validate dynamic schema",
5
5
  "main": "index.js",
6
6
  "scripts": {