dce-reactkit 3.5.1-beta.1 → 3.5.3

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.
Files changed (191) hide show
  1. package/.eslintrc.js +0 -2
  2. package/dist/cjs/index.js +320 -27
  3. package/dist/cjs/index.js.map +1 -1
  4. package/dist/cjs/types/client/initClient.d.ts +1 -1
  5. package/dist/cjs/types/components/AppWrapper.d.ts +6 -6
  6. package/dist/cjs/types/components/ButtonInputGroup.d.ts +1 -1
  7. package/dist/cjs/types/components/CSVDownloadButton.d.ts +1 -1
  8. package/dist/cjs/types/components/CheckboxButton.d.ts +1 -1
  9. package/dist/cjs/types/components/CopiableBox.d.ts +1 -1
  10. package/dist/cjs/types/components/DBEntryManagerPanel/AddOrEditDBEntry/CreatableMultiselect.d.ts +7 -1
  11. package/dist/cjs/types/components/DBEntryManagerPanel/AddOrEditDBEntry/index.d.ts +5 -4
  12. package/dist/cjs/types/components/DBEntryManagerPanel/helpers/generateEndpointPath.d.ts +1 -1
  13. package/dist/cjs/types/components/DBEntryManagerPanel/index.d.ts +13 -2
  14. package/dist/cjs/types/components/DBEntryManagerPanel/types/DBEntry.d.ts +1 -1
  15. package/dist/cjs/types/components/DBEntryManagerPanel/types/DBEntryField.d.ts +1 -1
  16. package/dist/cjs/types/components/Drawer.d.ts +1 -1
  17. package/dist/cjs/types/components/ErrorBox.d.ts +1 -1
  18. package/dist/cjs/types/components/IntelliTable.d.ts +1 -1
  19. package/dist/cjs/types/components/ItemPicker/NestableItemList.d.ts +1 -1
  20. package/dist/cjs/types/components/ItemPicker/index.d.ts +1 -1
  21. package/dist/cjs/types/components/ItemPicker/types/PickableItem.d.ts +1 -1
  22. package/dist/cjs/types/components/LogReviewer.d.ts +1 -1
  23. package/dist/cjs/types/components/Modal.d.ts +1 -1
  24. package/dist/cjs/types/components/PopFailureMark.d.ts +1 -1
  25. package/dist/cjs/types/components/PopPendingMark.d.ts +1 -1
  26. package/dist/cjs/types/components/PopSuccessMark.d.ts +1 -1
  27. package/dist/cjs/types/components/RadioButton.d.ts +1 -1
  28. package/dist/cjs/types/components/SimpleDateChooser.d.ts +1 -1
  29. package/dist/cjs/types/components/TabBox.d.ts +1 -1
  30. package/dist/cjs/types/helpers/abbreviate.test.d.ts +5 -0
  31. package/dist/cjs/types/helpers/addDBEditorEndpoints.d.ts +4 -3
  32. package/dist/cjs/types/helpers/avg.test.d.ts +5 -0
  33. package/dist/cjs/types/helpers/canReviewLogs.d.ts +5 -0
  34. package/dist/cjs/types/helpers/canReviewLogs.test.d.ts +5 -0
  35. package/dist/cjs/types/helpers/ceilToNumDecimals.test.d.ts +5 -0
  36. package/dist/cjs/types/helpers/compareArraysByProp.d.ts +3 -2
  37. package/dist/cjs/types/helpers/compareArraysByProp.test.d.ts +5 -0
  38. package/dist/cjs/types/helpers/extractProp.test.d.ts +5 -0
  39. package/dist/cjs/types/helpers/floorToNumDecimals.test.d.ts +5 -0
  40. package/dist/cjs/types/helpers/forceNumIntoBounds.test.d.ts +5 -0
  41. package/dist/cjs/types/helpers/genCSV.test.d.ts +5 -0
  42. package/dist/cjs/types/helpers/genCommaList.d.ts +12 -0
  43. package/dist/cjs/types/helpers/genCommaList.test.d.ts +1 -0
  44. package/dist/cjs/types/helpers/genRouteHandler.d.ts +7 -7
  45. package/dist/cjs/types/helpers/getHumanReadableDate.d.ts +1 -1
  46. package/dist/cjs/types/helpers/getHumanReadableDate.test.d.ts +5 -0
  47. package/dist/cjs/types/helpers/getLocalTimeInfo.d.ts +1 -1
  48. package/dist/cjs/types/helpers/getLocalTimeInfo.test.d.ts +6 -0
  49. package/dist/cjs/types/helpers/getMonthName.test.d.ts +5 -0
  50. package/dist/cjs/types/helpers/getOrdinal.test.d.ts +5 -0
  51. package/dist/cjs/types/helpers/getPartOfDay.test.d.ts +5 -0
  52. package/dist/cjs/types/helpers/getTimeInfoInET.d.ts +1 -1
  53. package/dist/cjs/types/helpers/getTimeInfoInET.test.d.ts +5 -0
  54. package/dist/cjs/types/helpers/parallelLimit.d.ts +1 -1
  55. package/dist/cjs/types/helpers/validators/shared/constants/ERROR_MESSAGES.d.ts +10 -0
  56. package/dist/cjs/types/helpers/validators/shared/helpers/validateRegex.d.ts +19 -0
  57. package/dist/cjs/types/helpers/validators/shared/types/ValidationResult.d.ts +12 -0
  58. package/dist/cjs/types/helpers/validators/validateEmail.d.ts +11 -0
  59. package/dist/cjs/types/helpers/validators/validateEmail.test.d.ts +1 -0
  60. package/dist/cjs/types/helpers/validators/validatePhoneNumber.d.ts +11 -0
  61. package/dist/cjs/types/helpers/validators/validatePhoneNumber.test.d.ts +1 -0
  62. package/dist/cjs/types/helpers/validators/validateString.d.ts +22 -0
  63. package/dist/cjs/types/helpers/validators/validateString.test.d.ts +1 -0
  64. package/dist/cjs/types/index.d.ts +5 -1
  65. package/dist/cjs/types/server/initServer.d.ts +1 -1
  66. package/dist/cjs/types/types/IntelliTableColumn.d.ts +1 -1
  67. package/dist/cjs/types/types/Log/LogMainInfo.d.ts +1 -1
  68. package/dist/cjs/types/types/Log/LogSourceSpecificInfo.d.ts +1 -1
  69. package/dist/cjs/types/types/Log/LogTypeSpecificInfo.d.ts +1 -1
  70. package/dist/cjs/types/types/Log/index.d.ts +1 -1
  71. package/dist/cjs/types/types/LogFunction.d.ts +1 -1
  72. package/dist/cjs/types/types/LogMetadataContextMap.d.ts +1 -1
  73. package/dist/cjs/types/types/LogMetadataTagMap.d.ts +1 -1
  74. package/dist/cjs/types/types/LogMetadataTargetMap.d.ts +1 -1
  75. package/dist/cjs/types/types/LogMetadataType.d.ts +1 -1
  76. package/dist/esm/index.js +317 -28
  77. package/dist/esm/index.js.map +1 -1
  78. package/dist/esm/types/client/initClient.d.ts +1 -1
  79. package/dist/esm/types/components/AppWrapper.d.ts +6 -6
  80. package/dist/esm/types/components/ButtonInputGroup.d.ts +1 -1
  81. package/dist/esm/types/components/CSVDownloadButton.d.ts +1 -1
  82. package/dist/esm/types/components/CheckboxButton.d.ts +1 -1
  83. package/dist/esm/types/components/CopiableBox.d.ts +1 -1
  84. package/dist/esm/types/components/DBEntryManagerPanel/AddOrEditDBEntry/CreatableMultiselect.d.ts +7 -1
  85. package/dist/esm/types/components/DBEntryManagerPanel/AddOrEditDBEntry/index.d.ts +5 -4
  86. package/dist/esm/types/components/DBEntryManagerPanel/helpers/generateEndpointPath.d.ts +1 -1
  87. package/dist/esm/types/components/DBEntryManagerPanel/index.d.ts +13 -2
  88. package/dist/esm/types/components/DBEntryManagerPanel/types/DBEntry.d.ts +1 -1
  89. package/dist/esm/types/components/DBEntryManagerPanel/types/DBEntryField.d.ts +1 -1
  90. package/dist/esm/types/components/Drawer.d.ts +1 -1
  91. package/dist/esm/types/components/ErrorBox.d.ts +1 -1
  92. package/dist/esm/types/components/IntelliTable.d.ts +1 -1
  93. package/dist/esm/types/components/ItemPicker/NestableItemList.d.ts +1 -1
  94. package/dist/esm/types/components/ItemPicker/index.d.ts +1 -1
  95. package/dist/esm/types/components/ItemPicker/types/PickableItem.d.ts +1 -1
  96. package/dist/esm/types/components/LogReviewer.d.ts +1 -1
  97. package/dist/esm/types/components/Modal.d.ts +1 -1
  98. package/dist/esm/types/components/PopFailureMark.d.ts +1 -1
  99. package/dist/esm/types/components/PopPendingMark.d.ts +1 -1
  100. package/dist/esm/types/components/PopSuccessMark.d.ts +1 -1
  101. package/dist/esm/types/components/RadioButton.d.ts +1 -1
  102. package/dist/esm/types/components/SimpleDateChooser.d.ts +1 -1
  103. package/dist/esm/types/components/TabBox.d.ts +1 -1
  104. package/dist/esm/types/helpers/abbreviate.test.d.ts +5 -0
  105. package/dist/esm/types/helpers/addDBEditorEndpoints.d.ts +4 -3
  106. package/dist/esm/types/helpers/avg.test.d.ts +5 -0
  107. package/dist/esm/types/helpers/canReviewLogs.d.ts +5 -0
  108. package/dist/esm/types/helpers/canReviewLogs.test.d.ts +5 -0
  109. package/dist/esm/types/helpers/ceilToNumDecimals.test.d.ts +5 -0
  110. package/dist/esm/types/helpers/compareArraysByProp.d.ts +3 -2
  111. package/dist/esm/types/helpers/compareArraysByProp.test.d.ts +5 -0
  112. package/dist/esm/types/helpers/extractProp.test.d.ts +5 -0
  113. package/dist/esm/types/helpers/floorToNumDecimals.test.d.ts +5 -0
  114. package/dist/esm/types/helpers/forceNumIntoBounds.test.d.ts +5 -0
  115. package/dist/esm/types/helpers/genCSV.test.d.ts +5 -0
  116. package/dist/esm/types/helpers/genCommaList.d.ts +12 -0
  117. package/dist/esm/types/helpers/genCommaList.test.d.ts +1 -0
  118. package/dist/esm/types/helpers/genRouteHandler.d.ts +7 -7
  119. package/dist/esm/types/helpers/getHumanReadableDate.d.ts +1 -1
  120. package/dist/esm/types/helpers/getHumanReadableDate.test.d.ts +5 -0
  121. package/dist/esm/types/helpers/getLocalTimeInfo.d.ts +1 -1
  122. package/dist/esm/types/helpers/getLocalTimeInfo.test.d.ts +6 -0
  123. package/dist/esm/types/helpers/getMonthName.test.d.ts +5 -0
  124. package/dist/esm/types/helpers/getOrdinal.test.d.ts +5 -0
  125. package/dist/esm/types/helpers/getPartOfDay.test.d.ts +5 -0
  126. package/dist/esm/types/helpers/getTimeInfoInET.d.ts +1 -1
  127. package/dist/esm/types/helpers/getTimeInfoInET.test.d.ts +5 -0
  128. package/dist/esm/types/helpers/parallelLimit.d.ts +1 -1
  129. package/dist/esm/types/helpers/validators/shared/constants/ERROR_MESSAGES.d.ts +10 -0
  130. package/dist/esm/types/helpers/validators/shared/helpers/validateRegex.d.ts +19 -0
  131. package/dist/esm/types/helpers/validators/shared/types/ValidationResult.d.ts +12 -0
  132. package/dist/esm/types/helpers/validators/validateEmail.d.ts +11 -0
  133. package/dist/esm/types/helpers/validators/validateEmail.test.d.ts +1 -0
  134. package/dist/esm/types/helpers/validators/validatePhoneNumber.d.ts +11 -0
  135. package/dist/esm/types/helpers/validators/validatePhoneNumber.test.d.ts +1 -0
  136. package/dist/esm/types/helpers/validators/validateString.d.ts +22 -0
  137. package/dist/esm/types/helpers/validators/validateString.test.d.ts +1 -0
  138. package/dist/esm/types/index.d.ts +5 -1
  139. package/dist/esm/types/server/initServer.d.ts +1 -1
  140. package/dist/esm/types/types/IntelliTableColumn.d.ts +1 -1
  141. package/dist/esm/types/types/Log/LogMainInfo.d.ts +1 -1
  142. package/dist/esm/types/types/Log/LogSourceSpecificInfo.d.ts +1 -1
  143. package/dist/esm/types/types/Log/LogTypeSpecificInfo.d.ts +1 -1
  144. package/dist/esm/types/types/Log/index.d.ts +1 -1
  145. package/dist/esm/types/types/LogFunction.d.ts +1 -1
  146. package/dist/esm/types/types/LogMetadataContextMap.d.ts +1 -1
  147. package/dist/esm/types/types/LogMetadataTagMap.d.ts +1 -1
  148. package/dist/esm/types/types/LogMetadataTargetMap.d.ts +1 -1
  149. package/dist/esm/types/types/LogMetadataType.d.ts +1 -1
  150. package/dist/index.d.ts +134 -56
  151. package/package.json +14 -13
  152. package/src/components/ItemPicker/index.test.tsx +10 -10
  153. package/src/helpers/abbreviate.test.ts +26 -0
  154. package/src/helpers/avg.test.ts +24 -0
  155. package/src/helpers/canReviewLogs.test.ts +67 -0
  156. package/src/helpers/canReviewLogs.ts +20 -0
  157. package/src/helpers/ceilToNumDecimals.test.ts +39 -0
  158. package/src/helpers/compareArraysByProp.test.ts +147 -0
  159. package/src/helpers/compareArraysByProp.ts +41 -22
  160. package/src/helpers/extractProp.test.ts +34 -0
  161. package/src/helpers/floorToNumDecimals.test.ts +39 -0
  162. package/src/helpers/forceNumIntoBounds.test.ts +34 -0
  163. package/src/helpers/genCSV.test.ts +61 -0
  164. package/src/helpers/genCSV.ts +5 -2
  165. package/src/helpers/genCommaList.test.ts +57 -0
  166. package/src/helpers/genCommaList.ts +21 -0
  167. package/src/helpers/getHumanReadableDate.test.ts +29 -0
  168. package/src/helpers/getLocalTimeInfo.test.ts +48 -0
  169. package/src/helpers/getMonthName.test.ts +79 -0
  170. package/src/helpers/getOrdinal.test.ts +84 -0
  171. package/src/helpers/{getOrdinal.tsx → getOrdinal.ts} +1 -0
  172. package/src/helpers/getPartOfDay.test.ts +56 -0
  173. package/src/helpers/getTimeInfoInET.test.ts +72 -0
  174. package/src/helpers/validators/shared/constants/ERROR_MESSAGES.ts +18 -0
  175. package/src/helpers/validators/shared/helpers/validateRegex.ts +47 -0
  176. package/src/helpers/validators/shared/types/ValidationResult.ts +20 -0
  177. package/src/helpers/validators/validateEmail.test.ts +110 -0
  178. package/src/helpers/validators/validateEmail.ts +47 -0
  179. package/src/helpers/validators/validatePhoneNumber.test.ts +94 -0
  180. package/src/helpers/validators/validatePhoneNumber.ts +49 -0
  181. package/src/helpers/validators/validateString.test.ts +173 -0
  182. package/src/helpers/validators/validateString.ts +171 -0
  183. package/src/index.ts +8 -0
  184. package/tsconfig.json +6 -2
  185. /package/src/helpers/{abbreviate.tsx → abbreviate.ts} +0 -0
  186. /package/src/helpers/{avg.tsx → avg.ts} +0 -0
  187. /package/src/helpers/{ceilToNumDecimals.tsx → ceilToNumDecimals.ts} +0 -0
  188. /package/src/helpers/{floorToNumDecimals.tsx → floorToNumDecimals.ts} +0 -0
  189. /package/src/helpers/{forceNumIntoBounds.tsx → forceNumIntoBounds.ts} +0 -0
  190. /package/src/helpers/{getLocalTimeInfo.tsx → getLocalTimeInfo.ts} +0 -0
  191. /package/src/helpers/{getTimeInfoInET.tsx → getTimeInfoInET.ts} +0 -0
package/.eslintrc.js CHANGED
@@ -2,8 +2,6 @@ const config = {
2
2
  extends: [
3
3
  'airbnb',
4
4
  'airbnb/hooks',
5
- 'react-app',
6
- 'react-app/jest',
7
5
  ],
8
6
  overrides: [
9
7
  {
package/dist/cjs/index.js CHANGED
@@ -1301,6 +1301,7 @@ const getMonthName = (month) => {
1301
1301
  return ((_a = monthNames[month - 1]) !== null && _a !== void 0 ? _a : monthNames[0]);
1302
1302
  };
1303
1303
 
1304
+ // Constants
1304
1305
  const ORDINALS = ['th', 'st', 'nd', 'rd'];
1305
1306
  /**
1306
1307
  * Get a number's ordinal
@@ -2296,12 +2297,13 @@ const roundToNumDecimals = (num, numDecimals) => {
2296
2297
  * @returns escaped cell text
2297
2298
  */
2298
2299
  const escapeCellText = (text) => {
2299
- if (!String(text).includes(',')) {
2300
+ if (!String(text).includes(',')
2301
+ && !String(text).includes('"')) {
2300
2302
  // No need to escape
2301
2303
  return String(text);
2302
2304
  }
2303
2305
  // Perform escape
2304
- return `"${String(text).replace(/"/g, '""')}`;
2306
+ return `"${String(text).replace(/"/g, '""')}"`;
2305
2307
  };
2306
2308
  /**
2307
2309
  * Generate a CSV file
@@ -39457,7 +39459,12 @@ var CreatableSelect = /*#__PURE__*/React.forwardRef(function (props, ref) {
39457
39459
  });
39458
39460
  var CreatableSelect$1 = CreatableSelect;
39459
39461
 
39460
- // Import React
39462
+ /**
39463
+ * Multiselect component that allows the user to type in values and add them to
39464
+ * the multiselect component
39465
+ * @author Yuen Ler Chow
39466
+ * @author Gabe Abrams
39467
+ */
39461
39468
  /* ------------- Actions ------------ */
39462
39469
  // Types of actions
39463
39470
  var ActionType$2;
@@ -39470,6 +39477,7 @@ var ActionType$2;
39470
39477
  * @author Yuen Ler Chow
39471
39478
  * @param state current state
39472
39479
  * @param action action to execute
39480
+ * @returns updated state
39473
39481
  */
39474
39482
  const reducer$2 = (state, action) => {
39475
39483
  switch (action.type) {
@@ -39503,14 +39511,18 @@ const CreatableMultiselect = (props) => {
39503
39511
  * Creates an option for the multiselect component
39504
39512
  * @author Yuen Ler Chow
39505
39513
  * @param label label of the option
39514
+ * @returns the new option
39506
39515
  */
39507
39516
  const createOption = (label) => {
39508
39517
  // set the value to the label without special characters and spaces, and lowercase
39509
39518
  return {
39510
39519
  label,
39511
39520
  value: (label
39521
+ // Make lowercase
39512
39522
  .toLowerCase()
39523
+ // Replace special characters with nothing
39513
39524
  .replace(/\W/g, '')
39525
+ // Replace spaces with dashes
39514
39526
  .replace(' ', '-')),
39515
39527
  };
39516
39528
  };
@@ -39540,6 +39552,7 @@ const CreatableMultiselect = (props) => {
39540
39552
  return value === numberVal;
39541
39553
  });
39542
39554
  }));
39555
+ // Notify parent of new values
39543
39556
  onChange([...values, ...newValues]);
39544
39557
  }
39545
39558
  else {
@@ -39560,9 +39573,10 @@ const CreatableMultiselect = (props) => {
39560
39573
  return value === val;
39561
39574
  });
39562
39575
  }));
39576
+ // Notify parent of new values
39563
39577
  onChange([...values, ...newValues]);
39564
39578
  }
39565
- // resets text field to empty because the values have been added
39579
+ // Reset text field to empty because the values have been added
39566
39580
  dispatch({
39567
39581
  type: ActionType$2.SetInputValue,
39568
39582
  value: '',
@@ -39621,7 +39635,7 @@ const CreatableMultiselect = (props) => {
39621
39635
  // Update values based on type
39622
39636
  if (type === DBEntryFieldType$1.NumberArray) {
39623
39637
  const numberValues = newValues.map((val) => {
39624
- return Number(val.value);
39638
+ return Number.parseFloat(val.value);
39625
39639
  });
39626
39640
  onChange(numberValues);
39627
39641
  }
@@ -39643,6 +39657,7 @@ const CreatableMultiselect = (props) => {
39643
39657
  /**
39644
39658
  * Panel for adding a DBEntry to the database
39645
39659
  * @author Yuen Ler Chow
39660
+ * @author Gabe Abrams
39646
39661
  */
39647
39662
  /*------------------------------------------------------------------------*/
39648
39663
  /* -------------------------------- Style ------------------------------- */
@@ -39666,6 +39681,7 @@ var ActionType$1;
39666
39681
  * @author Yuen Ler Chow
39667
39682
  * @param state current state
39668
39683
  * @param action action to execute
39684
+ * @returns updated state
39669
39685
  */
39670
39686
  const reducer$1 = (state, action) => {
39671
39687
  switch (action.type) {
@@ -39716,7 +39732,10 @@ const AddOrEditDBEntry = (props) => {
39716
39732
  entry[field.objectKey] = field.defaultValue;
39717
39733
  }
39718
39734
  });
39719
- const modifiedEntry = modifyEntry ? modifyEntry(entry) : entry;
39735
+ // Modify entry if needed
39736
+ const modifiedEntry = (modifyEntry
39737
+ ? yield modifyEntry(entry)
39738
+ : entry);
39720
39739
  // add id key to entry so that when we delete the item, the key will always be "id"
39721
39740
  modifiedEntry.id = modifiedEntry[idPropName];
39722
39741
  // Send to server
@@ -39753,14 +39772,18 @@ const AddOrEditDBEntry = (props) => {
39753
39772
  for (let i = 0; i < fields.length; i += 1) {
39754
39773
  const field = fields[i];
39755
39774
  const value = entry[field.objectKey];
39756
- // Check if required field is empty. Field is automatically required if it is the idPropName
39775
+ // Check if required field is empty. Field is automatically required if
39776
+ // it is the idPropName
39757
39777
  if ((field.required || (field.objectKey === idPropName)) && !value) {
39758
39778
  validationError = `Please fill in the ${field.label} field`;
39759
39779
  return validationError;
39760
39780
  }
39761
39781
  // Check if unique field is unique
39762
39782
  if (field.objectKey === idPropName && !dbEntryToEdit) {
39763
- if (entries.find((e) => { return e[idPropName] === value; })) {
39783
+ const notUnique = entries.find((e) => {
39784
+ return e[idPropName] === value;
39785
+ });
39786
+ if (notUnique) {
39764
39787
  validationError = `An item with the ${field.label} ${value} already exists. ${field.label} must be unique.`;
39765
39788
  return validationError;
39766
39789
  }
@@ -39872,6 +39895,7 @@ const AddOrEditDBEntry = (props) => {
39872
39895
  * @author Yuen Ler Chow
39873
39896
  * @param field the entry field to render
39874
39897
  * @param disabled true if the field should be disabled
39898
+ * @returns rendered entry field
39875
39899
  */
39876
39900
  const renderEntryField = (field, disabled) => {
39877
39901
  if (field.type === DBEntryFieldType$1.String) {
@@ -39993,9 +40017,11 @@ const AddOrEditDBEntry = (props) => {
39993
40017
  }),
39994
40018
  React__default["default"].createElement("div", { className: "text-center mt-2" },
39995
40019
  React__default["default"].createElement("button", { type: "button", id: "AddOrEditDBEntry-save-changes-button", className: "btn btn-primary btn-lg me-1", "aria-label": "Save changes", onClick: () => __awaiter(void 0, void 0, void 0, function* () {
40020
+ // Show validation errors
39996
40021
  if (validationError && validationError.length > 0) {
39997
40022
  return alert$1('Please fix the following error', validationError);
39998
40023
  }
40024
+ // Run the included validator if it exists
39999
40025
  if (validateEntry) {
40000
40026
  try {
40001
40027
  yield validateEntry(entry);
@@ -40008,7 +40034,7 @@ const AddOrEditDBEntry = (props) => {
40008
40034
  }) },
40009
40035
  React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faSave, className: "me-1" }),
40010
40036
  "Save"),
40011
- React__default["default"].createElement("button", { type: "button", id: "AddOrEditDBEntry-cancel-button", className: "btn btn-secondary btn-lg me-1", "aria-label": "save changes", onClick: cancel }, "Cancel"))));
40037
+ React__default["default"].createElement("button", { type: "button", id: "AddOrEditDBEntry-cancel-button", className: "btn btn-secondary btn-lg", "aria-label": "save changes", onClick: cancel }, "Cancel"))));
40012
40038
  }
40013
40039
  /*----------------------------------------*/
40014
40040
  /* --------------- Main UI -------------- */
@@ -40035,6 +40061,7 @@ const generateEndpointPath = (collectionName, adminsOnly) => {
40035
40061
  /**
40036
40062
  * DB Entry Manager Panel
40037
40063
  * @author Yuen Ler Chow
40064
+ * @author Gabe Abrams
40038
40065
  */
40039
40066
  /* ------------- Actions ------------ */
40040
40067
  // Types of actions
@@ -40058,6 +40085,7 @@ var ActionType;
40058
40085
  * @author Yuen Ler Chow
40059
40086
  * @param state current state
40060
40087
  * @param action action to execute
40088
+ * @returns updated state
40061
40089
  */
40062
40090
  const reducer = (state, action) => {
40063
40091
  switch (action.type) {
@@ -41687,8 +41715,14 @@ const initLogCollection = (Collection) => {
41687
41715
  });
41688
41716
  };
41689
41717
 
41718
+ /*------------------------------------------------------------------------*/
41719
+ /* -------------------------------- Cache ------------------------------- */
41720
+ /*------------------------------------------------------------------------*/
41690
41721
  // Cache user's ability
41691
41722
  let canReview = undefined;
41723
+ /*------------------------------------------------------------------------*/
41724
+ /* -------------------------------- Main -------------------------------- */
41725
+ /*------------------------------------------------------------------------*/
41692
41726
  /**
41693
41727
  * Check if the current user can review logs
41694
41728
  * @author Gabe Abrams
@@ -41728,36 +41762,49 @@ const extractProp = (arr, prop) => {
41728
41762
  });
41729
41763
  };
41730
41764
 
41731
- // Import shared helpers
41732
41765
  /**
41733
41766
  * Compare two arrays of objects by only comparing the values in a specific
41734
41767
  * property (e.g. compare user arrays by comparing their user.id values)
41735
41768
  * @author Gabe Abrams
41736
41769
  * @param a the first array
41737
41770
  * @param b the second array
41738
- * @param prop the property to compare with
41771
+ * @param prop the property to compare with, or an array of props to compare
41772
+ * with (if array, all values associated with those props must match)
41739
41773
  * @returns true if the arrays contain the same objects as determined by
41740
41774
  * the values associated with each object's prop
41741
41775
  */
41742
41776
  const compareArraysByProp = (a, b, prop) => {
41743
- // Extract values for comparison
41744
- const aVals = new Set(extractProp(a, prop));
41745
- const bVals = new Set(extractProp(b, prop));
41746
- // Compare sizes first
41747
- if (aVals.size !== bVals.size) {
41777
+ // Immediately return if size of arrays is different
41778
+ if (a.length !== b.length) {
41748
41779
  return false;
41749
41780
  }
41750
- // Same number of items. Make sure every object in aVals appears in bVals
41751
- // (if so, they should be equivalent since the sizes are the same)
41752
- // > Create map of items in bVals
41753
- const inBVals = {}; // item => true if in bVals
41754
- Array.from(bVals.values()).forEach((item) => {
41755
- inBVals[item] = true;
41756
- });
41757
- // > Loop through aVals and make sure every item is in bVals
41758
- return Array.from(aVals.values()).every((item) => {
41759
- return inBVals[item];
41760
- });
41781
+ // Get all props
41782
+ const props = (Array.isArray(prop) ? prop : [prop]);
41783
+ // Clone second array so we can work on it
41784
+ const bCloned = [...b];
41785
+ // Remove elements from b as we find them in a
41786
+ for (let i = 0; i < a.length; i++) {
41787
+ // Find matching element in b
41788
+ const matchingIndex = bCloned.findIndex((bItem) => {
41789
+ // Compare based on all props
41790
+ return props.every((propToCompareBy) => {
41791
+ var _a;
41792
+ const aVal = ((_a = a[i]) !== null && _a !== void 0 ? _a : {})[propToCompareBy];
41793
+ const bVal = (bItem !== null && bItem !== void 0 ? bItem : {})[propToCompareBy];
41794
+ return aVal === bVal;
41795
+ });
41796
+ });
41797
+ // Check if no match
41798
+ const noMatch = (matchingIndex < 0);
41799
+ // If no match, there's no corresponding element in b
41800
+ if (noMatch) {
41801
+ return false;
41802
+ }
41803
+ // Remove the matching element
41804
+ bCloned.splice(matchingIndex, 1);
41805
+ }
41806
+ // If we made it here, all elements in a have a corresponding element in b
41807
+ return true;
41761
41808
  };
41762
41809
 
41763
41810
  /**
@@ -41815,9 +41862,11 @@ const getLocalTimeInfo = (dateOrTimestamp) => {
41815
41862
  * @param opts.app express app to add routes too
41816
41863
  * @param opts.collectionName the name of the collection
41817
41864
  * @param opts.adminsOnly true if the endpoint is for admins only
41865
+ * @param opts.collection dce-mango db collection
41818
41866
  */
41819
41867
  const addDBEditorEndpoints = (opts) => {
41820
41868
  const { app, collectionName, adminsOnly, collection, } = opts;
41869
+ // Generate the endpoint path
41821
41870
  const endpointPath = generateEndpointPath(collectionName, adminsOnly);
41822
41871
  /**
41823
41872
  * List all items in the collection
@@ -41866,6 +41915,246 @@ const addDBEditorEndpoints = (opts) => {
41866
41915
  }));
41867
41916
  };
41868
41917
 
41918
+ /**
41919
+ * Given an array of strings, create a single comma-separated string that includes
41920
+ * 'and' as well as an oxford comma.
41921
+ * Ex: ['apples'] => 'apples'
41922
+ * Ex: ['apples', 'bananas'] => 'apples and bananas'
41923
+ * Ex: ['apples', 'bananas', 'grapes'] => 'apples, bananas, and grapes'
41924
+ * @author Austen Money
41925
+ * @param list an array of elements to be made into a single comma-separated string.
41926
+ * @returns a comma-separated string.
41927
+ */
41928
+ const genCommaList = (list) => {
41929
+ const { length } = list;
41930
+ return (length < 2
41931
+ ? list.join('')
41932
+ : `${list.slice(0, length - 1).join(', ')}${length < 3 ? ' and ' : ', and '}${list[length - 1]}`);
41933
+ };
41934
+
41935
+ /*------------------------------------------------------------------------*/
41936
+ /* ------------------------------ Constants ----------------------------- */
41937
+ /*------------------------------------------------------------------------*/
41938
+ const INVALID_REGEX_ERROR = 'input does not follow the requested format';
41939
+ const INVALID_EMAIL_ERROR = 'Please provide a valid email address.';
41940
+ const INVALID_PHONE_ERROR = 'Please provide a valid phone number.';
41941
+ const INVALID_STRING_ERRORS = {
41942
+ MIN_LEN: (minLen) => {
41943
+ return `input must not be under ${minLen} character(s)`;
41944
+ },
41945
+ MAX_LEN: (maxLen) => {
41946
+ return `input must not be over ${maxLen} character(s)`;
41947
+ },
41948
+ LETTERS_ONLY: 'input must only contain letters',
41949
+ NUMBERS_ONLY: 'input must only contain numbers',
41950
+ MESSAGE_INTRO: 'The following error(s) occurred: ',
41951
+ };
41952
+
41953
+ // Import constants
41954
+ /**
41955
+ * Determines whether a given input string is considered valid based on
41956
+ * the provided regex.
41957
+ * @author Austen Money
41958
+ * @param opts object containing all args
41959
+ * @param opts.input user-provided input to validate
41960
+ * @param opts.regex regular expression to check against input
41961
+ * @param [opts.regexDescription] description of what regexString is checking
41962
+ * for, used to customize error message
41963
+ * @returns the unchanged input if valid, or a customized error message if
41964
+ * invalid
41965
+ */
41966
+ const validateRegex = (opts) => {
41967
+ // customize error message in case of invalid input
41968
+ const errorMessage = `${INVALID_REGEX_ERROR}${opts.regexDescription
41969
+ ? ': '
41970
+ : ''}${opts.regexDescription}`;
41971
+ // return error message if test is invalid, or input string if valid
41972
+ return (opts.regex.test(opts.input)
41973
+ ? {
41974
+ isValid: true,
41975
+ cleanedValue: opts.input,
41976
+ }
41977
+ : {
41978
+ isValid: false,
41979
+ errorMessage,
41980
+ });
41981
+ };
41982
+
41983
+ // Import helpers
41984
+ /**
41985
+ * Determines whether a given email address is valid.
41986
+ * @author Austen Money
41987
+ * @param email email address to validate
41988
+ * @returns whether email fulfills proper formatting requirements, includes a
41989
+ * cleaned version of the address without leading or trailing
41990
+ * whitespace if valid or an error message if invalid.
41991
+ */
41992
+ const validateEmail = (email) => {
41993
+ // validation regex, sourced from HTML living standard: http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#e-mail-state-(type=email)
41994
+ // eslint-disable-next-line max-len
41995
+ const emailRegex = /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
41996
+ // remove leading and trailing whitespace
41997
+ const cleanedValue = email.replace(/^\s+|\s+$/g, '');
41998
+ // validate email with regex, and return error if not valid
41999
+ return (validateRegex({
42000
+ input: cleanedValue,
42001
+ regex: emailRegex,
42002
+ }).isValid
42003
+ ? {
42004
+ isValid: true,
42005
+ cleanedValue,
42006
+ }
42007
+ : {
42008
+ isValid: false,
42009
+ errorMessage: INVALID_EMAIL_ERROR,
42010
+ });
42011
+ };
42012
+
42013
+ // Import helpers
42014
+ /**
42015
+ * Determines whether a given phone number is valid.
42016
+ * @author Austen Money
42017
+ * @param phoneNumber phone number to validate
42018
+ * @returns whether phone number is considered valid - if valid, also returns
42019
+ * a cleaned version of the number without any formatting. If invalid,
42020
+ * returns an error message.
42021
+ */
42022
+ const validatePhoneNumber = (phoneNumber) => {
42023
+ // regex to validate phone number
42024
+ const validationRegex = /^\s*(?:\+?(\d{1,3}))?[-. (]*(\d{3})[-. )]*(\d{3})[-. ]*(\d{4})(?: *x(\d+))?\s*$/;
42025
+ // validate phone number with regex
42026
+ const validationResponse = validateRegex({
42027
+ input: phoneNumber,
42028
+ regex: validationRegex,
42029
+ });
42030
+ // remove all non-digits from number
42031
+ const cleanedValue = phoneNumber.replace(/\D/g, '');
42032
+ // return cleaned value if valid, or error message if invalid
42033
+ return (validationResponse.isValid
42034
+ ? {
42035
+ isValid: true,
42036
+ cleanedValue,
42037
+ }
42038
+ : {
42039
+ isValid: false,
42040
+ errorMessage: INVALID_PHONE_ERROR,
42041
+ });
42042
+ };
42043
+
42044
+ // Import helpers
42045
+ /*------------------------------------------------------------------------*/
42046
+ /* ------------------------------ Constants ----------------------------- */
42047
+ /*------------------------------------------------------------------------*/
42048
+ // define minimum and maximum range for lowercase ASCII chars
42049
+ const LOWERCASE_MIN = 65;
42050
+ const LOWERCASE_MAX = 90;
42051
+ // define minimum and maximum range for uppercase ASCII chars
42052
+ const UPPERCASE_MIN = 97;
42053
+ const UPPERCASE_MAX = 122;
42054
+ // define minimum and maximum range for ASCII digits
42055
+ const DIGIT_MIN = 48;
42056
+ const DIGIT_MAX = 57;
42057
+ /*------------------------------------------------------------------------*/
42058
+ /* ---------------------------- Main Function --------------------------- */
42059
+ /*------------------------------------------------------------------------*/
42060
+ /**
42061
+ * Determines whether a given input string is considered valid based on
42062
+ * the provided requirements.
42063
+ * @author Austen Money
42064
+ * @param input input string
42065
+ * @param opts options for validation
42066
+ * @returns whether input is considered valid according to reqs - if
42067
+ * valid, returns a cleaned version of input; if invalid, returns
42068
+ * a string containing error messages describing which requirements
42069
+ * were not met.
42070
+ */
42071
+ const validateString = (input, opts) => {
42072
+ // stores all invalid input errors
42073
+ const errorMessages = [];
42074
+ // contains version of input that will be returned
42075
+ let cleanedValue = input;
42076
+ // remove whitespace if required
42077
+ if (opts.ignoreWhitespace) {
42078
+ cleanedValue = input.replace(/\s+/g, '');
42079
+ }
42080
+ // apply max char requirement
42081
+ if (opts.minLen) {
42082
+ if (cleanedValue.length < opts.minLen) {
42083
+ errorMessages.push(INVALID_STRING_ERRORS.MIN_LEN(opts.minLen));
42084
+ }
42085
+ }
42086
+ // apply max char requirement
42087
+ if (opts.maxLen) {
42088
+ if (cleanedValue.length > opts.maxLen) {
42089
+ errorMessages.push(INVALID_STRING_ERRORS.MAX_LEN(opts.maxLen));
42090
+ }
42091
+ }
42092
+ // apply alphabetical requirement
42093
+ if (opts.lettersOnly) {
42094
+ // remove diacritics
42095
+ cleanedValue = cleanedValue.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
42096
+ const containsNonLetters = (cleanedValue
42097
+ // split into characters
42098
+ .split('')
42099
+ // convert into character codes
42100
+ .map((curr) => {
42101
+ return curr.charCodeAt(0);
42102
+ })
42103
+ // check for non-letters
42104
+ .some((currCode) => {
42105
+ return (!(currCode >= LOWERCASE_MIN && currCode <= LOWERCASE_MAX)
42106
+ && !(currCode >= UPPERCASE_MIN && currCode <= UPPERCASE_MAX));
42107
+ }));
42108
+ if (containsNonLetters) {
42109
+ errorMessages.push(INVALID_STRING_ERRORS.LETTERS_ONLY);
42110
+ }
42111
+ }
42112
+ // apply numerical requirement
42113
+ if (opts.numbersOnly) {
42114
+ const containsNonNumbers = (cleanedValue
42115
+ // split into characters
42116
+ .split('')
42117
+ // convert into character codes
42118
+ .map((curr) => {
42119
+ return curr.charCodeAt(0);
42120
+ })
42121
+ // check for non-numbers
42122
+ .some((currCode) => {
42123
+ return (!(currCode >= DIGIT_MIN && currCode <= DIGIT_MAX));
42124
+ }));
42125
+ if (containsNonNumbers) {
42126
+ errorMessages.push(INVALID_STRING_ERRORS.NUMBERS_ONLY);
42127
+ }
42128
+ }
42129
+ // apply regex requirement
42130
+ if (opts.regexTest) {
42131
+ const regex = opts.regexTest;
42132
+ // validate and create customized error message if description is provided
42133
+ const result = validateRegex({
42134
+ input: cleanedValue,
42135
+ regex,
42136
+ regexDescription: opts.regexDescription,
42137
+ });
42138
+ // if string did not pass regex validation, add error message
42139
+ if (result.isValid === false) {
42140
+ errorMessages.push(result.errorMessage);
42141
+ }
42142
+ }
42143
+ // combine all error messages into one string to return
42144
+ const errorMessage = `${INVALID_STRING_ERRORS.MESSAGE_INTRO}${genCommaList(errorMessages)}.`;
42145
+ return (
42146
+ // if no error messages, string is valid; if not, it is invalid
42147
+ errorMessages.length === 0
42148
+ ? {
42149
+ isValid: true,
42150
+ cleanedValue,
42151
+ }
42152
+ : {
42153
+ isValid: false,
42154
+ errorMessage,
42155
+ });
42156
+ };
42157
+
41869
42158
  /**
41870
42159
  * Days of the week
41871
42160
  * @author Gabe Abrams
@@ -41930,6 +42219,7 @@ exports.extractProp = extractProp;
41930
42219
  exports.floorToNumDecimals = floorToNumDecimals;
41931
42220
  exports.forceNumIntoBounds = forceNumIntoBounds;
41932
42221
  exports.genCSV = genCSV;
42222
+ exports.genCommaList = genCommaList;
41933
42223
  exports.genRouteHandler = genRouteHandler;
41934
42224
  exports.getHumanReadableDate = getHumanReadableDate;
41935
42225
  exports.getLocalTimeInfo = getLocalTimeInfo;
@@ -41954,6 +42244,9 @@ exports.startMinWait = startMinWait;
41954
42244
  exports.stringsToHumanReadableList = stringsToHumanReadableList;
41955
42245
  exports.stubServerEndpoint = stubServerEndpoint;
41956
42246
  exports.sum = sum;
42247
+ exports.validateEmail = validateEmail;
42248
+ exports.validatePhoneNumber = validatePhoneNumber;
42249
+ exports.validateString = validateString;
41957
42250
  exports.visitServerEndpoint = visitServerEndpoint;
41958
42251
  exports.waitMs = waitMs;
41959
42252
  //# sourceMappingURL=index.js.map