@medplum/react 0.9.27 → 0.9.30

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 (250) hide show
  1. package/dist/cjs/AddressDisplay.d.ts +6 -0
  2. package/dist/cjs/AddressInput.d.ts +8 -0
  3. package/dist/cjs/AnnotationInput.d.ts +8 -0
  4. package/dist/cjs/AttachmentArrayDisplay.d.ts +7 -0
  5. package/dist/cjs/AttachmentArrayInput.d.ts +9 -0
  6. package/dist/cjs/AttachmentDisplay.d.ts +7 -0
  7. package/dist/cjs/AttachmentInput.d.ts +9 -0
  8. package/dist/cjs/Autocomplete.d.ts +20 -0
  9. package/dist/cjs/Avatar.d.ts +12 -0
  10. package/dist/cjs/BackboneElementDisplay.d.ts +9 -0
  11. package/dist/cjs/BackboneElementInput.d.ts +9 -0
  12. package/dist/cjs/Button.d.ts +15 -0
  13. package/dist/cjs/CalendarInput.d.ts +16 -0
  14. package/dist/cjs/Checkbox.d.ts +12 -0
  15. package/dist/cjs/CheckboxFormSection.d.ts +9 -0
  16. package/dist/cjs/CodeInput.d.ts +9 -0
  17. package/dist/cjs/CodeableConceptDisplay.d.ts +6 -0
  18. package/dist/cjs/CodeableConceptInput.d.ts +9 -0
  19. package/dist/cjs/CodingDisplay.d.ts +6 -0
  20. package/dist/cjs/CodingInput.d.ts +9 -0
  21. package/dist/cjs/ContactDetailDisplay.d.ts +6 -0
  22. package/dist/cjs/ContactDetailInput.d.ts +8 -0
  23. package/dist/cjs/ContactPointDisplay.d.ts +6 -0
  24. package/dist/cjs/ContactPointInput.d.ts +8 -0
  25. package/dist/cjs/DateTimeInput.d.ts +23 -0
  26. package/dist/cjs/DefaultResourceTimeline.d.ts +6 -0
  27. package/dist/cjs/DescriptionList.d.ts +12 -0
  28. package/dist/cjs/DiagnosticReportDisplay.d.ts +12 -0
  29. package/dist/cjs/Dialog.d.ts +10 -0
  30. package/dist/cjs/Document.d.ts +7 -0
  31. package/dist/cjs/EncounterTimeline.d.ts +6 -0
  32. package/dist/cjs/ErrorBoundary.d.ts +18 -0
  33. package/dist/cjs/ExtensionInput.d.ts +8 -0
  34. package/dist/cjs/FhirPathDisplay.d.ts +9 -0
  35. package/dist/cjs/FhirPathTable.d.ts +29 -0
  36. package/dist/cjs/FooterLinks.d.ts +6 -0
  37. package/dist/cjs/Form.d.ts +8 -0
  38. package/dist/cjs/FormSection.d.ts +11 -0
  39. package/dist/cjs/FormUtils.d.ts +5 -0
  40. package/dist/cjs/GoogleButton.d.ts +8 -0
  41. package/dist/cjs/Header.d.ts +12 -0
  42. package/dist/cjs/HeaderSearchInput.d.ts +10 -0
  43. package/dist/cjs/HumanNameDisplay.d.ts +8 -0
  44. package/dist/cjs/HumanNameInput.d.ts +8 -0
  45. package/dist/cjs/IdentifierDisplay.d.ts +6 -0
  46. package/dist/cjs/IdentifierInput.d.ts +8 -0
  47. package/dist/cjs/Input.d.ts +22 -0
  48. package/dist/cjs/InputRow.d.ts +7 -0
  49. package/dist/cjs/Loading.d.ts +3 -0
  50. package/dist/cjs/Logo.d.ts +6 -0
  51. package/dist/cjs/MedplumLink.d.ts +13 -0
  52. package/dist/cjs/MedplumProvider.d.ts +34 -0
  53. package/dist/cjs/MenuItem.d.ts +9 -0
  54. package/dist/cjs/MenuSeparator.d.ts +3 -0
  55. package/dist/cjs/PatientTimeline.d.ts +6 -0
  56. package/dist/cjs/PeriodInput.d.ts +8 -0
  57. package/dist/cjs/PlanDefinitionBuilder.d.ts +7 -0
  58. package/dist/cjs/Popup.d.ts +14 -0
  59. package/dist/cjs/QuantityDisplay.d.ts +7 -0
  60. package/dist/cjs/QuantityInput.d.ts +8 -0
  61. package/dist/cjs/QuestionnaireBuilder.d.ts +8 -0
  62. package/dist/cjs/QuestionnaireForm.d.ts +14 -0
  63. package/dist/cjs/QuestionnaireUtils.d.ts +30 -0
  64. package/dist/cjs/RangeDisplay.d.ts +7 -0
  65. package/dist/cjs/RangeInput.d.ts +14 -0
  66. package/dist/cjs/RatioDisplay.d.ts +6 -0
  67. package/dist/cjs/RatioInput.d.ts +14 -0
  68. package/dist/cjs/ReferenceDisplay.d.ts +7 -0
  69. package/dist/cjs/ReferenceInput.d.ts +9 -0
  70. package/dist/cjs/RegisterForm.d.ts +18 -0
  71. package/dist/cjs/RequestGroupDisplay.d.ts +9 -0
  72. package/dist/cjs/ResourceArrayDisplay.d.ts +11 -0
  73. package/dist/cjs/ResourceArrayInput.d.ts +11 -0
  74. package/dist/cjs/ResourceBadge.d.ts +9 -0
  75. package/dist/cjs/ResourceBlame.d.ts +10 -0
  76. package/dist/cjs/ResourceDiff.d.ts +9 -0
  77. package/dist/cjs/ResourceDiffTable.d.ts +9 -0
  78. package/dist/cjs/ResourceForm.d.ts +10 -0
  79. package/dist/cjs/ResourceHistoryTable.d.ts +9 -0
  80. package/dist/cjs/ResourceInput.d.ts +12 -0
  81. package/dist/cjs/ResourceName.d.ts +7 -0
  82. package/dist/cjs/ResourcePropertyDisplay.d.ts +24 -0
  83. package/dist/cjs/ResourcePropertyInput.d.ts +21 -0
  84. package/dist/cjs/ResourceTable.d.ts +7 -0
  85. package/dist/cjs/ResourceTimeline.d.ts +11 -0
  86. package/dist/cjs/Scheduler.d.ts +7 -0
  87. package/dist/cjs/Scrollable.d.ts +9 -0
  88. package/dist/cjs/SearchControl.d.ts +40 -0
  89. package/dist/cjs/SearchControlField.d.ts +41 -0
  90. package/dist/cjs/SearchFieldEditor.d.ts +11 -0
  91. package/dist/cjs/SearchFilterEditor.d.ts +11 -0
  92. package/dist/cjs/SearchFilterValueDialog.d.ts +15 -0
  93. package/dist/cjs/SearchFilterValueDisplay.d.ts +7 -0
  94. package/dist/cjs/SearchFilterValueInput.d.ts +12 -0
  95. package/dist/cjs/SearchPopupMenu.d.ts +15 -0
  96. package/dist/cjs/SearchUtils.d.ts +174 -0
  97. package/dist/cjs/Select.d.ts +16 -0
  98. package/dist/cjs/ServiceRequestTimeline.d.ts +6 -0
  99. package/dist/cjs/SignInForm.d.ts +17 -0
  100. package/dist/cjs/StatusBadge.d.ts +6 -0
  101. package/dist/cjs/SubMenu.d.ts +7 -0
  102. package/dist/cjs/Tab.d.ts +12 -0
  103. package/dist/cjs/TabList.d.ts +10 -0
  104. package/dist/cjs/TabPanel.d.ts +6 -0
  105. package/dist/cjs/TabSwitch.d.ts +6 -0
  106. package/dist/cjs/TextArea.d.ts +18 -0
  107. package/dist/cjs/Timeline.d.ts +17 -0
  108. package/dist/cjs/TimingInput.d.ts +8 -0
  109. package/dist/cjs/TitleBar.d.ts +6 -0
  110. package/dist/cjs/UploadButton.d.ts +7 -0
  111. package/dist/cjs/constants.d.ts +1 -0
  112. package/dist/cjs/index.d.ts +87 -0
  113. package/dist/cjs/index.js +387 -196
  114. package/dist/cjs/index.js.map +1 -1
  115. package/dist/cjs/index.min.js +1 -1
  116. package/dist/cjs/index.min.js.map +1 -1
  117. package/dist/cjs/stories/AddressInput.stories.d.ts +6 -0
  118. package/dist/cjs/stories/AttachmentArrayInput.stories.d.ts +6 -0
  119. package/dist/cjs/stories/AttachmentInput.stories.d.ts +6 -0
  120. package/dist/cjs/stories/Autocomplete.stories.d.ts +9 -0
  121. package/dist/cjs/stories/Avatar.stories.d.ts +10 -0
  122. package/dist/cjs/stories/Button.stories.d.ts +9 -0
  123. package/dist/cjs/stories/CodeableConceptDisplay.stories.d.ts +8 -0
  124. package/dist/cjs/stories/DiagnosticReportDisplay.stories.d.ts +5 -0
  125. package/dist/cjs/stories/Dialog.stories.d.ts +5 -0
  126. package/dist/cjs/stories/EncounterTimeline.stories.d.ts +5 -0
  127. package/dist/cjs/stories/FhirPathDisplay.stories.d.ts +7 -0
  128. package/dist/cjs/stories/FormSection.stories.d.ts +6 -0
  129. package/dist/cjs/stories/Header.stories.d.ts +8 -0
  130. package/dist/cjs/stories/Input.stories.d.ts +6 -0
  131. package/dist/cjs/stories/Loading.stories.d.ts +5 -0
  132. package/dist/cjs/stories/Logo.stories.d.ts +5 -0
  133. package/dist/cjs/stories/PatientTimeline.stories.d.ts +5 -0
  134. package/dist/cjs/stories/PlanDefinitionBuilder.stories.d.ts +5 -0
  135. package/dist/cjs/stories/QuestionnaireBuilder.stories.d.ts +7 -0
  136. package/dist/cjs/stories/QuestionnaireForm.stories.d.ts +11 -0
  137. package/dist/cjs/stories/ReferenceInput.stories.d.ts +6 -0
  138. package/dist/cjs/stories/RegisterForm.stories.d.ts +7 -0
  139. package/dist/cjs/stories/RequestGroupDisplay.stories.d.ts +5 -0
  140. package/dist/cjs/stories/ResourceBlame.stories.d.ts +5 -0
  141. package/dist/cjs/stories/ResourceForm.stories.d.ts +12 -0
  142. package/dist/cjs/stories/ResourceHistoryTable.stories.d.ts +5 -0
  143. package/dist/cjs/stories/ResourceTable.stories.d.ts +7 -0
  144. package/dist/cjs/stories/Scheduler.stories.d.ts +5 -0
  145. package/dist/cjs/stories/SearchControl.stories.d.ts +13 -0
  146. package/dist/cjs/stories/Select.stories.d.ts +6 -0
  147. package/dist/cjs/stories/SignInForm.stories.d.ts +8 -0
  148. package/dist/cjs/stories/StatusBadge.stories.d.ts +5 -0
  149. package/dist/cjs/stories/Tabs.stories.d.ts +6 -0
  150. package/dist/cjs/stories/Timeline.stories.d.ts +5 -0
  151. package/dist/cjs/stories/TimingInput.stories.d.ts +6 -0
  152. package/dist/cjs/stories/UploadButton.stories.d.ts +6 -0
  153. package/dist/cjs/styles.css +135 -130
  154. package/dist/cjs/test.setup.d.ts +1 -0
  155. package/dist/cjs/useResource.d.ts +8 -0
  156. package/dist/cjs/utils/blame.d.ts +8 -0
  157. package/dist/cjs/utils/date.d.ts +6 -0
  158. package/dist/cjs/utils/diff.d.ts +16 -0
  159. package/dist/cjs/utils/dom.d.ts +15 -0
  160. package/dist/cjs/utils/outcomes.d.ts +2 -0
  161. package/dist/cjs/utils/recaptcha.d.ts +12 -0
  162. package/dist/cjs/utils.d.ts +5 -0
  163. package/dist/esm/Autocomplete.d.ts +1 -0
  164. package/dist/esm/Autocomplete.js +5 -8
  165. package/dist/esm/Autocomplete.js.map +1 -1
  166. package/dist/esm/CalendarInput.d.ts +1 -0
  167. package/dist/esm/CalendarInput.js +6 -5
  168. package/dist/esm/CalendarInput.js.map +1 -1
  169. package/dist/esm/CodeInput.js +1 -1
  170. package/dist/esm/CodeInput.js.map +1 -1
  171. package/dist/esm/CodeableConceptDisplay.js +4 -2
  172. package/dist/esm/CodeableConceptDisplay.js.map +1 -1
  173. package/dist/esm/CodeableConceptInput.js +1 -1
  174. package/dist/esm/CodeableConceptInput.js.map +1 -1
  175. package/dist/esm/CodingInput.js +1 -1
  176. package/dist/esm/CodingInput.js.map +1 -1
  177. package/dist/esm/DateTimeInput.js +1 -3
  178. package/dist/esm/DateTimeInput.js.map +1 -1
  179. package/dist/esm/DiagnosticReportDisplay.js +2 -4
  180. package/dist/esm/DiagnosticReportDisplay.js.map +1 -1
  181. package/dist/esm/FhirPathTable.js +5 -2
  182. package/dist/esm/FhirPathTable.js.map +1 -1
  183. package/dist/esm/GoogleButton.js +2 -2
  184. package/dist/esm/GoogleButton.js.map +1 -1
  185. package/dist/esm/Header.js +7 -3
  186. package/dist/esm/Header.js.map +1 -1
  187. package/dist/esm/PlanDefinitionBuilder.js +108 -39
  188. package/dist/esm/PlanDefinitionBuilder.js.map +1 -1
  189. package/dist/esm/QuestionnaireBuilder.js +1 -1
  190. package/dist/esm/QuestionnaireBuilder.js.map +1 -1
  191. package/dist/esm/QuestionnaireForm.js +5 -1
  192. package/dist/esm/QuestionnaireForm.js.map +1 -1
  193. package/dist/esm/RegisterForm.js +2 -2
  194. package/dist/esm/RegisterForm.js.map +1 -1
  195. package/dist/esm/RequestGroupDisplay.js +3 -4
  196. package/dist/esm/RequestGroupDisplay.js.map +1 -1
  197. package/dist/esm/ResourceArrayInput.js +1 -2
  198. package/dist/esm/ResourceArrayInput.js.map +1 -1
  199. package/dist/esm/ResourceBlame.js +1 -1
  200. package/dist/esm/ResourceBlame.js.map +1 -1
  201. package/dist/esm/ResourceDiffTable.js +1 -1
  202. package/dist/esm/ResourceDiffTable.js.map +1 -1
  203. package/dist/esm/ResourceForm.js +1 -1
  204. package/dist/esm/ResourceForm.js.map +1 -1
  205. package/dist/esm/ResourceHistoryTable.js +6 -4
  206. package/dist/esm/ResourceHistoryTable.js.map +1 -1
  207. package/dist/esm/ResourceInput.d.ts +1 -0
  208. package/dist/esm/ResourceInput.js +4 -3
  209. package/dist/esm/ResourceInput.js.map +1 -1
  210. package/dist/esm/ResourcePropertyDisplay.js +5 -5
  211. package/dist/esm/ResourcePropertyDisplay.js.map +1 -1
  212. package/dist/esm/ResourcePropertyInput.js +3 -0
  213. package/dist/esm/ResourcePropertyInput.js.map +1 -1
  214. package/dist/esm/ResourceTable.js +1 -1
  215. package/dist/esm/ResourceTable.js.map +1 -1
  216. package/dist/esm/ResourceTimeline.js +13 -7
  217. package/dist/esm/ResourceTimeline.js.map +1 -1
  218. package/dist/esm/Scheduler.js +13 -6
  219. package/dist/esm/Scheduler.js.map +1 -1
  220. package/dist/esm/SearchControl.js +5 -2
  221. package/dist/esm/SearchControl.js.map +1 -1
  222. package/dist/esm/SearchFilterValueDisplay.js +2 -2
  223. package/dist/esm/SearchFilterValueDisplay.js.map +1 -1
  224. package/dist/esm/SearchUtils.js +2 -3
  225. package/dist/esm/SearchUtils.js.map +1 -1
  226. package/dist/esm/SignInForm.js +39 -2
  227. package/dist/esm/SignInForm.js.map +1 -1
  228. package/dist/esm/Timeline.js +2 -4
  229. package/dist/esm/Timeline.js.map +1 -1
  230. package/dist/esm/TimingInput.d.ts +8 -0
  231. package/dist/esm/TimingInput.js +90 -0
  232. package/dist/esm/TimingInput.js.map +1 -0
  233. package/dist/esm/index.d.ts +1 -1
  234. package/dist/esm/index.js +1 -1
  235. package/dist/esm/index.min.js +1 -1
  236. package/dist/esm/index.min.js.map +1 -1
  237. package/dist/esm/stories/Autocomplete.stories.d.ts +1 -0
  238. package/dist/esm/stories/CodeableConceptDisplay.stories.d.ts +8 -0
  239. package/dist/esm/stories/TimingInput.stories.d.ts +6 -0
  240. package/dist/esm/styles.css +135 -130
  241. package/dist/esm/utils/recaptcha.js +10 -4
  242. package/dist/esm/utils/recaptcha.js.map +1 -1
  243. package/package.json +6 -6
  244. package/stats.html +4034 -0
  245. package/dist/esm/DateTimeDisplay.d.ts +0 -5
  246. package/dist/esm/DateTimeDisplay.js +0 -11
  247. package/dist/esm/DateTimeDisplay.js.map +0 -1
  248. package/dist/esm/PeriodDisplay.d.ts +0 -6
  249. package/dist/esm/PeriodDisplay.js +0 -16
  250. package/dist/esm/PeriodDisplay.js.map +0 -1
package/dist/cjs/index.js CHANGED
@@ -333,7 +333,7 @@
333
333
  var _a, _b;
334
334
  const inputRef = React.useRef(null);
335
335
  const [focused, setFocused] = React.useState(false);
336
- const [lastValue, setLastValue] = React.useState('');
336
+ const [lastValue, setLastValue] = React.useState(undefined);
337
337
  const [timer, setTimer] = React.useState();
338
338
  const [dropDownVisible, setDropDownVisible] = React.useState(false);
339
339
  const [values, setValues] = React.useState((_a = props.defaultValue) !== null && _a !== void 0 ? _a : []);
@@ -387,8 +387,12 @@
387
387
  }
388
388
  function handleFocus() {
389
389
  setFocused(true);
390
+ if (props.loadOnFocus) {
391
+ handleInput();
392
+ }
390
393
  }
391
394
  function handleBlur() {
395
+ tryAddOption();
392
396
  setFocused(false);
393
397
  dismissOnDelay();
394
398
  }
@@ -526,13 +530,6 @@
526
530
  // Nothing has changed, move on
527
531
  return;
528
532
  }
529
- if (!value) {
530
- setDropDownVisible(false);
531
- setLastValue('');
532
- setOptions([]);
533
- setSelectedIndex(-1);
534
- return;
535
- }
536
533
  setLastValue(value);
537
534
  const newAbortController = new AbortController();
538
535
  setAbortController(newAbortController);
@@ -752,7 +749,7 @@
752
749
  React.useEffect(() => {
753
750
  if (defaultValue) {
754
751
  setValue(JSON.parse(JSON.stringify(defaultValue)));
755
- medplum.requestSchema(defaultValue.resourceType).then(setSchema);
752
+ medplum.requestSchema(defaultValue.resourceType).then(setSchema).catch(console.log);
756
753
  }
757
754
  }, [medplum, defaultValue]);
758
755
  if (!schema || !value) {
@@ -845,8 +842,10 @@
845
842
  if (value.text) {
846
843
  return React__default["default"].createElement(React__default["default"].Fragment, null, value.text);
847
844
  }
848
- if (value.coding && value.coding.length > 0) {
849
- return React__default["default"].createElement(CodingDisplay, { value: value.coding[0] });
845
+ if (value.coding) {
846
+ return (React__default["default"].createElement(React__default["default"].Fragment, null, value.coding.map((coding, index) => (React__default["default"].createElement(React__default["default"].Fragment, { key: 'coding-' + index },
847
+ index > 0 && React__default["default"].createElement(React__default["default"].Fragment, null, ', '),
848
+ React__default["default"].createElement(CodingDisplay, { value: coding }))))));
850
849
  }
851
850
  return null;
852
851
  }
@@ -888,13 +887,6 @@
888
887
  _a.map((telecom, index) => (React__default["default"].createElement(ContactPointDisplay, { key: 'telecom-' + index, value: telecom })))));
889
888
  }
890
889
 
891
- function DateTimeDisplay(props) {
892
- if (!props.value) {
893
- return null;
894
- }
895
- return React__default["default"].createElement(React__default["default"].Fragment, null, new Date(props.value).toLocaleString());
896
- }
897
-
898
890
  function HumanNameDisplay(props) {
899
891
  const name = props.value;
900
892
  if (!name) {
@@ -911,17 +903,6 @@
911
903
  _b.value));
912
904
  }
913
905
 
914
- function PeriodDisplay(props) {
915
- const value = props.value;
916
- if (!value || (!value.start && !value.end)) {
917
- return null;
918
- }
919
- return (React__default["default"].createElement("span", null,
920
- React__default["default"].createElement(DateTimeDisplay, { value: value.start }),
921
- "-",
922
- React__default["default"].createElement(DateTimeDisplay, { value: value.end })));
923
- }
924
-
925
906
  function QuantityDisplay(props) {
926
907
  return React__default["default"].createElement(React__default["default"].Fragment, null, formatQuantityString(props.value));
927
908
  }
@@ -1023,7 +1004,7 @@
1023
1004
  return React__default["default"].createElement(ReferenceDisplay, { value: { reference: value }, link: props.link });
1024
1005
  case core.PropertyType.dateTime:
1025
1006
  case core.PropertyType.instant:
1026
- return React__default["default"].createElement(DateTimeDisplay, { value: value });
1007
+ return React__default["default"].createElement("div", null, core.formatDateTime(value));
1027
1008
  case core.PropertyType.markdown:
1028
1009
  return React__default["default"].createElement("pre", null, value);
1029
1010
  case core.PropertyType.Address:
@@ -1045,7 +1026,7 @@
1045
1026
  case core.PropertyType.Identifier:
1046
1027
  return React__default["default"].createElement(IdentifierDisplay, { value: value });
1047
1028
  case core.PropertyType.Period:
1048
- return React__default["default"].createElement(PeriodDisplay, { value: value });
1029
+ return React__default["default"].createElement("div", null, core.formatPeriod(value));
1049
1030
  case core.PropertyType.Quantity:
1050
1031
  return React__default["default"].createElement(QuantityDisplay, { value: value });
1051
1032
  case core.PropertyType.Range:
@@ -1054,6 +1035,8 @@
1054
1035
  return React__default["default"].createElement(RatioDisplay, { value: value });
1055
1036
  case core.PropertyType.Reference:
1056
1037
  return React__default["default"].createElement(ReferenceDisplay, { value: value, link: props.link });
1038
+ case core.PropertyType.Timing:
1039
+ return React__default["default"].createElement("div", null, core.formatTiming(value));
1057
1040
  default:
1058
1041
  if (!(property === null || property === void 0 ? void 0 : property.path)) {
1059
1042
  throw Error(`Displaying property of type ${props.propertyType} requires element definition path`);
@@ -1124,7 +1107,7 @@
1124
1107
  return medplum.searchValueSet(system, input).then((valueSet) => {
1125
1108
  return valueSet.expansion.contains.map(valueSetElementToCodeableConcept);
1126
1109
  });
1127
- }, buildUnstructured: buildUnstructured, getId: getId, getDisplay: getDisplay, name: props.name, defaultValue: defaultValue, onChange: (values) => {
1110
+ }, buildUnstructured: buildUnstructured, getId: getId, getDisplay: getDisplay, name: props.name, defaultValue: defaultValue, loadOnFocus: true, onChange: (values) => {
1128
1111
  if (props.onChange) {
1129
1112
  props.onChange(values[0]);
1130
1113
  }
@@ -1172,7 +1155,7 @@
1172
1155
  contains.forEach((e) => (cachedDisplayValues[e.code] = e.display));
1173
1156
  return contains.map((e) => e.code);
1174
1157
  });
1175
- }, buildUnstructured: (str) => str, getId: (item) => item, getDisplay: (item) => React__default["default"].createElement(React__default["default"].Fragment, null, cachedDisplayValues[item] || item), name: props.name, defaultValue: defaultValue, onChange: (values) => {
1158
+ }, buildUnstructured: (str) => str, getId: (item) => item, getDisplay: (item) => React__default["default"].createElement(React__default["default"].Fragment, null, cachedDisplayValues[item] || item), name: props.name, defaultValue: defaultValue, loadOnFocus: true, onChange: (values) => {
1176
1159
  if (props.onChange) {
1177
1160
  props.onChange(values[0]);
1178
1161
  }
@@ -1195,7 +1178,7 @@
1195
1178
  display: e.display,
1196
1179
  }));
1197
1180
  });
1198
- }, buildUnstructured: (str) => ({ code: str }), getId: (item) => item.code, getDisplay: (item) => React__default["default"].createElement(CodingDisplay, { value: item }), name: props.name, defaultValue: defaultValue, onChange: (values) => {
1181
+ }, buildUnstructured: (str) => ({ code: str }), getId: (item) => item.code, getDisplay: (item) => React__default["default"].createElement(CodingDisplay, { value: item }), name: props.name, defaultValue: defaultValue, loadOnFocus: true, onChange: (values) => {
1199
1182
  if (props.onChange) {
1200
1183
  props.onChange(values[0]);
1201
1184
  }
@@ -1313,7 +1296,7 @@
1313
1296
  // See: https://developer.mozilla.org/en-US/docs/Web/HTML/Date_and_time_formats#local_date_and_time_strings
1314
1297
  // See: https://stackoverflow.com/a/60368477
1315
1298
  const date = new Date(isoString);
1316
- if (!isValidDate(date)) {
1299
+ if (!core.isValidDate(date)) {
1317
1300
  // If the input string was malformed, return an empty string.
1318
1301
  return '';
1319
1302
  }
@@ -1332,15 +1315,12 @@
1332
1315
  // JavaScript's Date() constructor defaults to the local time zone.
1333
1316
  // The Date() constructor will throw if the value is malformed.
1334
1317
  const date = new Date(localString);
1335
- if (!isValidDate(date)) {
1318
+ if (!core.isValidDate(date)) {
1336
1319
  // If the input string was malformed, return an empty string.
1337
1320
  return '';
1338
1321
  }
1339
1322
  return date.toISOString();
1340
1323
  }
1341
- function isValidDate(date) {
1342
- return date instanceof Date && !isNaN(date.getTime());
1343
- }
1344
1324
 
1345
1325
  function TextArea(props) {
1346
1326
  const className = 'medplum-textarea' + (props.monospace ? ' monospace' : '');
@@ -1493,6 +1473,31 @@
1493
1473
  React__default["default"].createElement(QuantityInput, { name: props.name + '-denominator', defaultValue: value === null || value === void 0 ? void 0 : value.denominator, onChange: (v) => setValueWrapper(Object.assign(Object.assign({}, value), { denominator: v })) })));
1494
1474
  }
1495
1475
 
1476
+ /******************************************************************************
1477
+ Copyright (c) Microsoft Corporation.
1478
+
1479
+ Permission to use, copy, modify, and/or distribute this software for any
1480
+ purpose with or without fee is hereby granted.
1481
+
1482
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
1483
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
1484
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
1485
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
1486
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
1487
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
1488
+ PERFORMANCE OF THIS SOFTWARE.
1489
+ ***************************************************************************** */
1490
+
1491
+ function __awaiter(thisArg, _arguments, P, generator) {
1492
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
1493
+ return new (P || (P = Promise))(function (resolve, reject) {
1494
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
1495
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
1496
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
1497
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
1498
+ });
1499
+ }
1500
+
1496
1501
  function ResourceName(props) {
1497
1502
  const resource = useResource(props.value);
1498
1503
  if (!resource) {
@@ -1517,18 +1522,18 @@
1517
1522
  props.onChange(newValue);
1518
1523
  }
1519
1524
  }
1520
- return (React__default["default"].createElement(Autocomplete, { loadOptions: (input) => {
1525
+ return (React__default["default"].createElement(Autocomplete, { loadOptions: (input) => __awaiter(this, void 0, void 0, function* () {
1521
1526
  return medplum
1522
1527
  .search(resourceTypeRef.current, 'name=' + encodeURIComponent(input) + '&_count=10')
1523
1528
  .then((bundle) => bundle.entry.map((entry) => entry.resource));
1524
- }, getId: (item) => {
1529
+ }), getId: (item) => {
1525
1530
  return item.id;
1526
1531
  }, getIcon: (item) => React__default["default"].createElement(Avatar, { value: item }), getDisplay: (item) => React__default["default"].createElement(ResourceName, { value: item }), getHelpText: (item) => {
1527
1532
  if (item.resourceType === 'Patient' && item.birthDate) {
1528
1533
  return 'DoB: ' + item.birthDate;
1529
1534
  }
1530
1535
  return undefined;
1531
- }, name: props.name, defaultValue: value ? [value] : undefined, className: props.className, placeholder: props.placeholder, onChange: (items) => {
1536
+ }, name: props.name, defaultValue: value ? [value] : undefined, className: props.className, placeholder: props.placeholder, loadOnFocus: props.loadOnFocus, onChange: (items) => {
1532
1537
  setValueWrapper(items.length > 0 ? items[0] : undefined);
1533
1538
  } }));
1534
1539
  }
@@ -1567,8 +1572,7 @@
1567
1572
  }
1568
1573
 
1569
1574
  function ResourceArrayInput(props) {
1570
- var _a;
1571
- const [values, setValues] = React.useState((_a = props.defaultValue) !== null && _a !== void 0 ? _a : []);
1575
+ const [values, setValues] = React.useState(props.defaultValue && Array.isArray(props.defaultValue) ? props.defaultValue : []);
1572
1576
  const valuesRef = React.useRef();
1573
1577
  valuesRef.current = values;
1574
1578
  function setValuesWrapper(newValues) {
@@ -1607,6 +1611,120 @@
1607
1611
  } }, "Add"))))));
1608
1612
  }
1609
1613
 
1614
+ function Dialog(props) {
1615
+ const [x, setX] = React.useState(100);
1616
+ const [y, setY] = React.useState(100);
1617
+ if (!props.visible) {
1618
+ return null;
1619
+ }
1620
+ function handleMouseDown(downEvent) {
1621
+ killEvent(downEvent);
1622
+ const dragX = downEvent.clientX - x;
1623
+ const dragY = downEvent.clientY - y;
1624
+ function handleMouseMove(moveEvent) {
1625
+ killEvent(moveEvent);
1626
+ setX(moveEvent.clientX - dragX);
1627
+ setY(moveEvent.clientY - dragY);
1628
+ }
1629
+ function handleMouseUp(upEvent) {
1630
+ killEvent(upEvent);
1631
+ document.removeEventListener('mouseup', handleMouseUp, true);
1632
+ document.removeEventListener('mousemove', handleMouseMove, true);
1633
+ }
1634
+ document.addEventListener('mouseup', handleMouseUp, true);
1635
+ document.addEventListener('mousemove', handleMouseMove, true);
1636
+ }
1637
+ return (React__default["default"].createElement(React__default["default"].Fragment, null,
1638
+ React__default["default"].createElement("div", { className: "modal-dialog-bg" }),
1639
+ React__default["default"].createElement("div", { className: "modal-dialog", "data-testid": "dialog", tabIndex: 0, style: { left: x + 'px', top: y + 'px' } },
1640
+ React__default["default"].createElement("div", { className: "modal-dialog-title", onMouseDown: (e) => handleMouseDown(e) },
1641
+ React__default["default"].createElement("span", { className: "modal-dialog-title-text" }, props.title),
1642
+ React__default["default"].createElement("span", { className: "modal-dialog-title-close", tabIndex: 0, onClick: props.onCancel },
1643
+ React__default["default"].createElement("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor" },
1644
+ React__default["default"].createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" })))),
1645
+ React__default["default"].createElement("div", { className: "modal-dialog-content" }, props.children),
1646
+ React__default["default"].createElement("div", { className: "modal-dialog-buttons" },
1647
+ React__default["default"].createElement(Button, { testid: "dialog-ok", onClick: props.onOk }, "OK"),
1648
+ React__default["default"].createElement(Button, { testid: "dialog-cancel", onClick: props.onCancel }, "Cancel")))));
1649
+ }
1650
+
1651
+ const daysOfWeek = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
1652
+ function TimingInput(props) {
1653
+ const [value, setValue] = React.useState(props.defaultValue || {});
1654
+ const [open, setOpen] = React.useState(false);
1655
+ const valueRef = React.useRef();
1656
+ valueRef.current = value;
1657
+ return (React__default["default"].createElement(React__default["default"].Fragment, null,
1658
+ React__default["default"].createElement(InputRow, null,
1659
+ React__default["default"].createElement("span", null, core.formatTiming(valueRef.current) || 'No repeat'),
1660
+ React__default["default"].createElement(Button, { onClick: () => setOpen(true) }, "Edit")),
1661
+ React__default["default"].createElement(TimingEditorDialog, { visible: open, defaultValue: valueRef.current, onOk: (newValue) => {
1662
+ if (props.onChange) {
1663
+ props.onChange(newValue);
1664
+ }
1665
+ setValue(newValue);
1666
+ setOpen(false);
1667
+ }, onCancel: () => setOpen(false) })));
1668
+ }
1669
+ function TimingEditorDialog(props) {
1670
+ var _a, _b;
1671
+ const [value, setValue] = React.useState(props.defaultValue || {});
1672
+ const valueRef = React.useRef();
1673
+ valueRef.current = value;
1674
+ function setStart(newStart) {
1675
+ setValue(Object.assign(Object.assign({}, valueRef.current), { event: [newStart] }));
1676
+ }
1677
+ function setRepeat(repeat) {
1678
+ setValue(Object.assign(Object.assign({}, valueRef.current), { repeat }));
1679
+ }
1680
+ function setPeriod(newPeriod) {
1681
+ var _a;
1682
+ setRepeat(Object.assign(Object.assign({}, (_a = valueRef.current) === null || _a === void 0 ? void 0 : _a.repeat), { period: newPeriod }));
1683
+ }
1684
+ function setPeriodUnit(newPeriodUnit) {
1685
+ var _a;
1686
+ setRepeat(Object.assign(Object.assign({}, (_a = valueRef.current) === null || _a === void 0 ? void 0 : _a.repeat), { periodUnit: newPeriodUnit }));
1687
+ }
1688
+ function setDayOfWeek(day, enabled) {
1689
+ if (enabled) {
1690
+ addDayOfWeek(day);
1691
+ }
1692
+ else {
1693
+ removeDayOfWeek(day);
1694
+ }
1695
+ }
1696
+ function addDayOfWeek(day) {
1697
+ var _a, _b, _c;
1698
+ const existing = ((_b = (_a = valueRef.current) === null || _a === void 0 ? void 0 : _a.repeat) === null || _b === void 0 ? void 0 : _b.dayOfWeek) || [];
1699
+ if (!existing.includes(day)) {
1700
+ setRepeat(Object.assign(Object.assign({}, (_c = valueRef.current) === null || _c === void 0 ? void 0 : _c.repeat), { dayOfWeek: [...existing, day] }));
1701
+ }
1702
+ }
1703
+ function removeDayOfWeek(day) {
1704
+ var _a, _b, _c;
1705
+ const existing = ((_b = (_a = valueRef.current) === null || _a === void 0 ? void 0 : _a.repeat) === null || _b === void 0 ? void 0 : _b.dayOfWeek) || [];
1706
+ if (existing.includes(day)) {
1707
+ setRepeat(Object.assign(Object.assign({}, (_c = valueRef.current) === null || _c === void 0 ? void 0 : _c.repeat), { dayOfWeek: existing.filter((d) => d !== day) }));
1708
+ }
1709
+ }
1710
+ return (React__default["default"].createElement(Dialog, { title: "Timing", visible: props.visible, onOk: () => props.onOk(value), onCancel: () => props.onCancel() },
1711
+ React__default["default"].createElement("div", { style: { padding: '5px 20px', textAlign: 'left' } },
1712
+ React__default["default"].createElement(FormSection, { title: "Starts on", htmlFor: 'timing-dialog-start' },
1713
+ React__default["default"].createElement(DateTimeInput, { name: 'timing-dialog-start', onChange: (newValue) => setStart(newValue) })),
1714
+ React__default["default"].createElement(FormSection, { title: "Repeat every", htmlFor: 'timing-dialog-period' },
1715
+ React__default["default"].createElement(InputRow, null,
1716
+ React__default["default"].createElement(Input, { type: "number", step: 1, name: 'timing-dialog-period', defaultValue: (_a = value === null || value === void 0 ? void 0 : value.repeat) === null || _a === void 0 ? void 0 : _a.period, onChange: (newValue) => setPeriod(parseInt(newValue)) }),
1717
+ React__default["default"].createElement(Select, { name: 'timing-dialog-periodUnit', defaultValue: (_b = value === null || value === void 0 ? void 0 : value.repeat) === null || _b === void 0 ? void 0 : _b.periodUnit, onChange: (newValue) => setPeriodUnit(newValue) },
1718
+ React__default["default"].createElement("option", { value: "d" }, "day"),
1719
+ React__default["default"].createElement("option", { value: "wk" }, "week"),
1720
+ React__default["default"].createElement("option", { value: "mo" }, "month"),
1721
+ React__default["default"].createElement("option", { value: "a" }, "year")))),
1722
+ React__default["default"].createElement(FormSection, { title: "Repeat on" },
1723
+ React__default["default"].createElement(InputRow, null, daysOfWeek.map((day) => (React__default["default"].createElement(React__default["default"].Fragment, { key: day },
1724
+ React__default["default"].createElement("label", { htmlFor: 'timing-dialog-repeat-' + day }, day.charAt(0).toUpperCase()),
1725
+ React__default["default"].createElement(Checkbox, { name: 'timing-dialog-repeat-' + day, onChange: (newValue) => setDayOfWeek(day, newValue) })))))))));
1726
+ }
1727
+
1610
1728
  function ResourcePropertyInput(props) {
1611
1729
  var _a, _b, _c;
1612
1730
  const property = props.property;
@@ -1719,6 +1837,8 @@
1719
1837
  return React__default["default"].createElement(RatioInput, { name: name, defaultValue: value, onChange: props.onChange });
1720
1838
  case core.PropertyType.Reference:
1721
1839
  return (React__default["default"].createElement(ReferenceInput, { name: name, defaultValue: value, targetTypes: getTargetTypes(property), onChange: props.onChange }));
1840
+ case core.PropertyType.Timing:
1841
+ return React__default["default"].createElement(TimingInput, { name: name, defaultValue: value, onChange: props.onChange });
1722
1842
  default:
1723
1843
  return (React__default["default"].createElement(BackboneElementInput, { typeName: core.buildTypeName((_a = property.path) === null || _a === void 0 ? void 0 : _a.split('.')), defaultValue: value, onChange: props.onChange, outcome: props.outcome }));
1724
1844
  }
@@ -1808,8 +1928,7 @@
1808
1928
  React__default["default"].createElement(ResourceBadge, { value: interpreter, link: true }))))),
1809
1929
  diagnosticReport.issued && (React__default["default"].createElement("dl", null,
1810
1930
  React__default["default"].createElement("dt", null, "Issued"),
1811
- React__default["default"].createElement("dd", null,
1812
- React__default["default"].createElement(DateTimeDisplay, { value: diagnosticReport.issued })))),
1931
+ React__default["default"].createElement("dd", null, core.formatDateTime(diagnosticReport.issued)))),
1813
1932
  diagnosticReport.status && (React__default["default"].createElement("dl", null,
1814
1933
  React__default["default"].createElement("dt", null, "Status"),
1815
1934
  React__default["default"].createElement("dd", null, core.capitalize(diagnosticReport.status))))),
@@ -1938,7 +2057,7 @@
1938
2057
  const medplum = useMedplum();
1939
2058
  const [schema, setSchema] = React.useState();
1940
2059
  React.useEffect(() => {
1941
- medplum.requestSchema(props.original.resourceType).then(setSchema);
2060
+ medplum.requestSchema(props.original.resourceType).then(setSchema).catch(console.log);
1942
2061
  }, [medplum, props.original.resourceType]);
1943
2062
  if (!schema) {
1944
2063
  return null;
@@ -1991,7 +2110,7 @@
1991
2110
  const [schema, setSchema] = React.useState();
1992
2111
  React.useEffect(() => {
1993
2112
  if (value) {
1994
- medplum.requestSchema(value.resourceType).then(setSchema);
2113
+ medplum.requestSchema(value.resourceType).then(setSchema).catch(console.log);
1995
2114
  }
1996
2115
  }, [medplum, value]);
1997
2116
  if (!schema || !value) {
@@ -2104,8 +2223,7 @@
2104
2223
  React__default["default"].createElement("div", { className: "medplum-timeline-item-title" },
2105
2224
  React__default["default"].createElement(ResourceName, { value: author, link: true }),
2106
2225
  React__default["default"].createElement("div", { className: "medplum-timeline-item-subtitle" },
2107
- React__default["default"].createElement(MedplumLink, { to: props.resource },
2108
- React__default["default"].createElement(DateTimeDisplay, { value: (_c = props.resource.meta) === null || _c === void 0 ? void 0 : _c.lastUpdated })),
2226
+ React__default["default"].createElement(MedplumLink, { to: props.resource }, core.formatDateTime((_c = props.resource.meta) === null || _c === void 0 ? void 0 : _c.lastUpdated)),
2109
2227
  React__default["default"].createElement("span", null, "\u00B7"),
2110
2228
  React__default["default"].createElement(MedplumLink, { to: props.resource }, props.resource.resourceType))),
2111
2229
  props.popupMenuItems && (React__default["default"].createElement("div", { className: "medplum-timeline-item-actions" },
@@ -2190,7 +2308,7 @@
2190
2308
  setHistory({});
2191
2309
  return;
2192
2310
  }
2193
- medplum.executeBatch(buildSearchRequests(resource)).then(handleBatchResponse);
2311
+ medplum.executeBatch(buildSearchRequests(resource)).then(handleBatchResponse).catch(console.log);
2194
2312
  }, [medplum, resource, buildSearchRequests]);
2195
2313
  React.useEffect(() => {
2196
2314
  loadTimeline();
@@ -2241,9 +2359,12 @@
2241
2359
  // Encounter not loaded yet
2242
2360
  return;
2243
2361
  }
2244
- medplum.createResource(props.createCommunication(resource, sender, contentString)).then((result) => {
2362
+ medplum
2363
+ .createResource(props.createCommunication(resource, sender, contentString))
2364
+ .then((result) => {
2245
2365
  addResources([result]);
2246
- });
2366
+ })
2367
+ .catch(console.log);
2247
2368
  }
2248
2369
  /**
2249
2370
  * Adds a Media resource to the timeline.
@@ -2254,18 +2375,21 @@
2254
2375
  // Encounter not loaded yet
2255
2376
  return;
2256
2377
  }
2257
- medplum.createResource(props.createMedia(resource, sender, attachment)).then((result) => {
2378
+ medplum
2379
+ .createResource(props.createMedia(resource, sender, attachment))
2380
+ .then((result) => {
2258
2381
  addResources([result]);
2259
- });
2382
+ })
2383
+ .catch(console.log);
2260
2384
  }
2261
2385
  function setPriority(communication, priority) {
2262
2386
  return medplum.updateResource(Object.assign(Object.assign({}, communication), { priority }));
2263
2387
  }
2264
2388
  function onPin(communication) {
2265
- setPriority(communication, 'stat').then(loadTimeline);
2389
+ setPriority(communication, 'stat').then(loadTimeline).catch(console.log);
2266
2390
  }
2267
2391
  function onUnpin(communication) {
2268
- setPriority(communication, 'routine').then(loadTimeline);
2392
+ setPriority(communication, 'routine').then(loadTimeline).catch(console.log);
2269
2393
  }
2270
2394
  function onDetails(timelineItem) {
2271
2395
  navigate(`/${timelineItem.resourceType}/${timelineItem.id}`);
@@ -2551,43 +2675,6 @@
2551
2675
  return { name };
2552
2676
  }
2553
2677
 
2554
- function Dialog(props) {
2555
- const [x, setX] = React.useState(100);
2556
- const [y, setY] = React.useState(100);
2557
- if (!props.visible) {
2558
- return null;
2559
- }
2560
- function handleMouseDown(downEvent) {
2561
- killEvent(downEvent);
2562
- const dragX = downEvent.clientX - x;
2563
- const dragY = downEvent.clientY - y;
2564
- function handleMouseMove(moveEvent) {
2565
- killEvent(moveEvent);
2566
- setX(moveEvent.clientX - dragX);
2567
- setY(moveEvent.clientY - dragY);
2568
- }
2569
- function handleMouseUp(upEvent) {
2570
- killEvent(upEvent);
2571
- document.removeEventListener('mouseup', handleMouseUp, true);
2572
- document.removeEventListener('mousemove', handleMouseMove, true);
2573
- }
2574
- document.addEventListener('mouseup', handleMouseUp, true);
2575
- document.addEventListener('mousemove', handleMouseMove, true);
2576
- }
2577
- return (React__default["default"].createElement(React__default["default"].Fragment, null,
2578
- React__default["default"].createElement("div", { className: "modal-dialog-bg" }),
2579
- React__default["default"].createElement("div", { className: "modal-dialog", "data-testid": "dialog", tabIndex: 0, style: { left: x + 'px', top: y + 'px' } },
2580
- React__default["default"].createElement("div", { className: "modal-dialog-title", onMouseDown: (e) => handleMouseDown(e) },
2581
- React__default["default"].createElement("span", { className: "modal-dialog-title-text" }, props.title),
2582
- React__default["default"].createElement("span", { className: "modal-dialog-title-close", tabIndex: 0, onClick: props.onCancel },
2583
- React__default["default"].createElement("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor" },
2584
- React__default["default"].createElement("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" })))),
2585
- React__default["default"].createElement("div", { className: "modal-dialog-content" }, props.children),
2586
- React__default["default"].createElement("div", { className: "modal-dialog-buttons" },
2587
- React__default["default"].createElement(Button, { testid: "dialog-ok", onClick: props.onOk }, "OK"),
2588
- React__default["default"].createElement(Button, { testid: "dialog-cancel", onClick: props.onCancel }, "Cancel")))));
2589
- }
2590
-
2591
2678
  const searchParamToOperators = {
2592
2679
  string: [core.Operator.EQUALS, core.Operator.NOT, core.Operator.CONTAINS, core.Operator.EXACT],
2593
2680
  fulltext: [core.Operator.EQUALS, core.Operator.NOT, core.Operator.CONTAINS, core.Operator.EXACT],
@@ -3023,7 +3110,7 @@
3023
3110
  return (_a = resource.meta) === null || _a === void 0 ? void 0 : _a.versionId;
3024
3111
  }
3025
3112
  if (key === '_lastUpdated') {
3026
- return React__default["default"].createElement(DateTimeDisplay, { value: (_b = resource.meta) === null || _b === void 0 ? void 0 : _b.lastUpdated });
3113
+ return core.formatDateTime((_b = resource.meta) === null || _b === void 0 ? void 0 : _b.lastUpdated);
3027
3114
  }
3028
3115
  // Priority 1: ElementDefinition by exact match
3029
3116
  if (field.elementDefinition && `${resource.resourceType}.${field.name}` === field.elementDefinition.path) {
@@ -3263,7 +3350,7 @@
3263
3350
  return React__default["default"].createElement(ResourceName, { value: { reference: filter.value } });
3264
3351
  }
3265
3352
  if (props.filter.code === '_lastUpdated' || (searchParam === null || searchParam === void 0 ? void 0 : searchParam.type) === 'datetime') {
3266
- return React__default["default"].createElement(DateTimeDisplay, { value: filter.value });
3353
+ return React__default["default"].createElement(React__default["default"].Fragment, null, core.formatDateTime(filter.value));
3267
3354
  }
3268
3355
  return React__default["default"].createElement(React__default["default"].Fragment, null, filter.value);
3269
3356
  }
@@ -3727,11 +3814,14 @@
3727
3814
  }
3728
3815
  }
3729
3816
  React.useEffect(() => {
3730
- medplum.requestSchema(props.search.resourceType).then((newSchema) => {
3817
+ medplum
3818
+ .requestSchema(props.search.resourceType)
3819
+ .then((newSchema) => {
3731
3820
  // The schema could have the same object identity,
3732
3821
  // so need to use the spread operator to kick React re-render.
3733
3822
  setSchema(Object.assign({}, newSchema));
3734
- });
3823
+ })
3824
+ .catch(console.log);
3735
3825
  }, [medplum, props.search.resourceType]);
3736
3826
  const typeSchema = (_a = schema === null || schema === void 0 ? void 0 : schema.types) === null || _a === void 0 ? void 0 : _a[props.search.resourceType];
3737
3827
  if (!typeSchema) {
@@ -3915,11 +4005,14 @@
3915
4005
  }
3916
4006
  }
3917
4007
  React.useEffect(() => {
3918
- medplum.requestSchema(props.resourceType).then((newSchema) => {
4008
+ medplum
4009
+ .requestSchema(props.resourceType)
4010
+ .then((newSchema) => {
3919
4011
  // The schema could have the same object identity,
3920
4012
  // so need to use the spread operator to kick React re-render.
3921
4013
  setSchema(Object.assign({}, newSchema));
3922
- });
4014
+ })
4015
+ .catch(console.log);
3923
4016
  }, [medplum, props.resourceType]);
3924
4017
  const typeSchema = (_a = schema === null || schema === void 0 ? void 0 : schema.types) === null || _a === void 0 ? void 0 : _a[props.resourceType];
3925
4018
  if (!typeSchema) {
@@ -3951,31 +4044,6 @@
3951
4044
  return React__default["default"].createElement("div", { className: "medplum-footer" }, props.children);
3952
4045
  }
3953
4046
 
3954
- /******************************************************************************
3955
- Copyright (c) Microsoft Corporation.
3956
-
3957
- Permission to use, copy, modify, and/or distribute this software for any
3958
- purpose with or without fee is hereby granted.
3959
-
3960
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
3961
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
3962
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
3963
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
3964
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
3965
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
3966
- PERFORMANCE OF THIS SOFTWARE.
3967
- ***************************************************************************** */
3968
-
3969
- function __awaiter(thisArg, _arguments, P, generator) {
3970
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3971
- return new (P || (P = Promise))(function (resolve, reject) {
3972
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
3973
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
3974
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
3975
- step((generator = generator.apply(thisArg, _arguments || [])).next());
3976
- });
3977
- }
3978
-
3979
4047
  function HeaderSearchInput(props) {
3980
4048
  const medplum = useMedplum();
3981
4049
  return (React__default["default"].createElement(Autocomplete, { loadOptions: (input, signal) => __awaiter(this, void 0, void 0, function* () {
@@ -4186,9 +4254,13 @@
4186
4254
  logins.map((login) => {
4187
4255
  var _a, _b, _c, _d;
4188
4256
  return ((_a = login.profile) === null || _a === void 0 ? void 0 : _a.reference) !== core.getReferenceString(context.profile) && (React__default["default"].createElement("div", { className: "medplum-nav-menu-profile", key: (_b = login.profile) === null || _b === void 0 ? void 0 : _b.reference, onClick: () => {
4189
- medplum.setActiveLogin(login);
4190
- setUserMenuVisible(false);
4191
- window.location.reload();
4257
+ medplum
4258
+ .setActiveLogin(login)
4259
+ .then(() => {
4260
+ setUserMenuVisible(false);
4261
+ window.location.reload();
4262
+ })
4263
+ .catch(console.log);
4192
4264
  } },
4193
4265
  React__default["default"].createElement("div", { className: "medplum-nav-menu-profile-icon" },
4194
4266
  React__default["default"].createElement(Avatar, null)),
@@ -4274,14 +4346,33 @@
4274
4346
  }
4275
4347
 
4276
4348
  function PlanDefinitionBuilder(props) {
4349
+ const medplum = useMedplum();
4277
4350
  const defaultValue = useResource(props.value);
4351
+ const [schema, setSchema] = React.useState(undefined);
4352
+ const [selectedKey, setSelectedKey] = React.useState();
4353
+ const [hoverKey, setHoverKey] = React.useState();
4278
4354
  const [value, setValue] = React.useState();
4355
+ function handleDocumentMouseOver() {
4356
+ setHoverKey(undefined);
4357
+ }
4358
+ function handleDocumentClick() {
4359
+ setSelectedKey(undefined);
4360
+ }
4279
4361
  const valueRef = React.useRef();
4280
4362
  valueRef.current = value;
4363
+ React.useEffect(() => {
4364
+ medplum.requestSchema('PlanDefinition').then(setSchema).catch(console.log);
4365
+ }, [medplum]);
4281
4366
  React.useEffect(() => {
4282
4367
  setValue(ensurePlanDefinitionKeys(defaultValue !== null && defaultValue !== void 0 ? defaultValue : { resourceType: 'PlanDefinition' }));
4368
+ document.addEventListener('mouseover', handleDocumentMouseOver);
4369
+ document.addEventListener('click', handleDocumentClick);
4370
+ return () => {
4371
+ document.removeEventListener('mouseover', handleDocumentMouseOver);
4372
+ document.removeEventListener('click', handleDocumentClick);
4373
+ };
4283
4374
  }, [defaultValue]);
4284
- if (!value) {
4375
+ if (!schema || !value) {
4285
4376
  return null;
4286
4377
  }
4287
4378
  function changeProperty(property, newValue) {
@@ -4289,9 +4380,9 @@
4289
4380
  }
4290
4381
  return (React__default["default"].createElement("div", { className: "medplum-questionnaire-builder" },
4291
4382
  React__default["default"].createElement(Form, { testid: "questionnaire-form", onSubmit: () => props.onSubmit(value) },
4292
- React__default["default"].createElement(FormSection, { title: "Plan Title", description: "The display name of the 'Plan', something that can be ordered.", htmlFor: "title" },
4383
+ React__default["default"].createElement(FormSection, { title: "Plan Title", htmlFor: "title" },
4293
4384
  React__default["default"].createElement(Input, { defaultValue: value.title, onChange: (newValue) => changeProperty('title', newValue) })),
4294
- React__default["default"].createElement(ActionArrayBuilder, { actions: value.action || [], onChange: (x) => changeProperty('action', x) }),
4385
+ React__default["default"].createElement(ActionArrayBuilder, { actions: value.action || [], selectedKey: selectedKey, setSelectedKey: setSelectedKey, hoverKey: hoverKey, setHoverKey: setHoverKey, onChange: (x) => changeProperty('action', x) }),
4295
4386
  React__default["default"].createElement(Button, { type: "submit", size: "large" }, "Save"))));
4296
4387
  }
4297
4388
  function ActionArrayBuilder(props) {
@@ -4302,75 +4393,102 @@
4302
4393
  }
4303
4394
  function addAction(addedAction) {
4304
4395
  props.onChange([...actionsRef.current, addedAction]);
4396
+ props.setSelectedKey(addedAction.id);
4305
4397
  }
4306
4398
  function removeAction(removedAction) {
4307
4399
  props.onChange(actionsRef.current.filter((i) => i !== removedAction));
4308
4400
  }
4309
4401
  return (React__default["default"].createElement("div", { className: "section" },
4310
- props.actions.map((i) => (React__default["default"].createElement("div", { key: i.id },
4311
- React__default["default"].createElement(ActionBuilder, { action: i, onChange: changeAction, onRemove: () => removeAction(i) })))),
4402
+ props.actions.map((action) => (React__default["default"].createElement("div", { key: action.id },
4403
+ React__default["default"].createElement(ActionBuilder, { action: action, selectedKey: props.selectedKey, setSelectedKey: props.setSelectedKey, hoverKey: props.hoverKey, setHoverKey: props.setHoverKey, onChange: changeAction, onRemove: () => removeAction(action) })))),
4312
4404
  React__default["default"].createElement("div", { className: "bottom-actions" },
4313
4405
  React__default["default"].createElement("a", { href: "#", onClick: (e) => {
4314
- e.preventDefault();
4406
+ killEvent(e);
4315
4407
  addAction({ id: generateId$1() });
4316
4408
  } }, "Add action"))));
4317
4409
  }
4318
4410
  function ActionBuilder(props) {
4319
4411
  const { action } = props;
4320
- const [actionType, setActionType] = React.useState(getInitialActionType(action));
4321
- const actionRef = React.useRef();
4322
- actionRef.current = props.action;
4412
+ const actionType = getInitialActionType(action);
4413
+ const editing = props.selectedKey === props.action.id;
4414
+ const hovering = props.hoverKey === props.action.id;
4415
+ function onClick(e) {
4416
+ e.stopPropagation();
4417
+ props.setSelectedKey(props.action.id);
4418
+ }
4419
+ function onHover(e) {
4420
+ killEvent(e);
4421
+ props.setHoverKey(props.action.id);
4422
+ }
4423
+ const className = editing ? 'section editing' : hovering ? 'section hovering' : 'section';
4424
+ return (React__default["default"].createElement("div", { "data-testid": action.id, className: className, onClick: onClick, onMouseOver: onHover },
4425
+ editing ? (React__default["default"].createElement(ActionEditor, { action: action, actionType: actionType, onChange: props.onChange, selectedKey: props.selectedKey, setSelectedKey: props.setSelectedKey, hoverKey: props.hoverKey, setHoverKey: props.setHoverKey, onRemove: props.onRemove })) : (React__default["default"].createElement(ActionDisplay, { action: action, actionType: actionType })),
4426
+ React__default["default"].createElement("div", { className: "bottom-actions" },
4427
+ React__default["default"].createElement("a", { href: "#", onClick: (e) => {
4428
+ e.preventDefault();
4429
+ props.onRemove();
4430
+ } }, "Remove"))));
4431
+ }
4432
+ const timingProperty = {
4433
+ path: 'PlanDefinition.action.timing[x]',
4434
+ min: 0,
4435
+ max: '1',
4436
+ type: [{ code: 'dateTime' }, { code: 'Period' }, { code: 'Range' }, { code: 'Timing' }],
4437
+ };
4438
+ function ActionDisplay(props) {
4439
+ const { action, actionType } = props;
4440
+ const [propertyValue, propertyType] = getActionTiming(action);
4441
+ return (React__default["default"].createElement("div", null,
4442
+ React__default["default"].createElement("div", null,
4443
+ action.title || 'Untitled',
4444
+ " ",
4445
+ actionType && `(${actionType})`),
4446
+ action.definitionCanonical && (React__default["default"].createElement("div", null,
4447
+ React__default["default"].createElement(ReferenceDisplay, { value: { reference: action.definitionCanonical } }))),
4448
+ propertyValue && (React__default["default"].createElement("div", null,
4449
+ React__default["default"].createElement(ResourcePropertyDisplay, { property: timingProperty, propertyType: propertyType, value: propertyValue })))));
4450
+ }
4451
+ function ActionEditor(props) {
4452
+ const { action } = props;
4453
+ const [actionType, setActionType] = React.useState(props.actionType);
4323
4454
  function changeProperty(property, value) {
4324
- props.onChange(Object.assign(Object.assign({}, actionRef.current), { [property]: value }));
4455
+ props.onChange(Object.assign(Object.assign({}, action), { [property]: value }));
4325
4456
  }
4326
- return (React__default["default"].createElement("div", { className: "section" },
4327
- React__default["default"].createElement(FormSection, { title: "Action Title", description: "The name of the action, an operational task to be completed.", htmlFor: `actionTitle-${action.id}` },
4457
+ return (React__default["default"].createElement(React__default["default"].Fragment, null,
4458
+ React__default["default"].createElement(FormSection, { title: "Title", htmlFor: `actionTitle-${action.id}` },
4328
4459
  React__default["default"].createElement(Input, { name: `actionTitle-${action.id}`, defaultValue: action.title, onChange: (newValue) => changeProperty('title', newValue) })),
4329
- React__default["default"].createElement(FormSection, { title: "Action Type", description: "The type of the action to be performed.", htmlFor: `actionType-${action.id}` },
4460
+ React__default["default"].createElement(FormSection, { title: "Type of Action", description: "The type of the action to be performed.", htmlFor: `actionType-${action.id}` },
4330
4461
  React__default["default"].createElement(Select, { name: `actionType-${action.id}`, defaultValue: actionType, onChange: setActionType },
4331
4462
  React__default["default"].createElement("option", null),
4332
4463
  React__default["default"].createElement("option", { value: "appointment" }, "Appointment"),
4333
- React__default["default"].createElement("option", { value: "documentation" }, "Documentation"),
4334
4464
  React__default["default"].createElement("option", { value: "lab" }, "Lab"),
4335
4465
  React__default["default"].createElement("option", { value: "questionnaire" }, "Questionnaire"),
4336
- React__default["default"].createElement("option", { value: "shipping" }, "Shipping"),
4337
4466
  React__default["default"].createElement("option", { value: "task" }, "Task"))),
4338
- action.action && action.action.length > 0 && (React__default["default"].createElement(ActionArrayBuilder, { actions: action.action, onChange: (x) => changeProperty('action', x) })),
4467
+ action.action && action.action.length > 0 && (React__default["default"].createElement(ActionArrayBuilder, { actions: action.action, selectedKey: props.selectedKey, setSelectedKey: props.setSelectedKey, hoverKey: props.hoverKey, setHoverKey: props.setHoverKey, onChange: (x) => changeProperty('action', x) })),
4339
4468
  (() => {
4340
4469
  switch (actionType) {
4341
4470
  case 'appointment':
4342
- return React__default["default"].createElement("div", null, "Appointment details");
4343
- case 'documentation':
4344
- return React__default["default"].createElement("div", null, "Documentation details");
4471
+ return (React__default["default"].createElement(ActionResourceTypeBuilder, { title: "Appointment", description: "The subject must schedule an appointment from the schedule.", resourceType: "Schedule", action: action, onChange: props.onChange }));
4345
4472
  case 'lab':
4346
- return React__default["default"].createElement(LabActionBuilder, { action: action, onChange: props.onChange });
4473
+ return (React__default["default"].createElement(ActionResourceTypeBuilder, { title: "Lab", description: "The subject must complete the following lab panel.", resourceType: "ActivityDefinition", action: action, onChange: props.onChange }));
4347
4474
  case 'questionnaire':
4348
- return React__default["default"].createElement(QuestionnaireActionBuilder, { action: action, onChange: props.onChange });
4349
- case 'shipping':
4350
- return React__default["default"].createElement("div", null, "Shipping details");
4475
+ return (React__default["default"].createElement(ActionResourceTypeBuilder, { title: "Questionnaire", description: "The subject must complete the selected questionnaire.", resourceType: "Questionnaire", action: action, onChange: props.onChange }));
4351
4476
  case 'task':
4352
- return React__default["default"].createElement("div", null, "Task details");
4477
+ return (React__default["default"].createElement(ActionResourceTypeBuilder, { title: "Task", description: "The subject must complete the following task.", resourceType: "ActivityDefinition", action: action, onChange: props.onChange }));
4353
4478
  default:
4354
4479
  return null;
4355
4480
  }
4356
4481
  })(),
4357
- React__default["default"].createElement("div", { className: "bottom-actions" },
4358
- React__default["default"].createElement("a", { href: "#", onClick: (e) => {
4359
- e.preventDefault();
4360
- props.onRemove();
4361
- } }, "Remove"))));
4482
+ React__default["default"].createElement(FormSection, { title: "Timing", description: "When the action should take place.", htmlFor: 'timing-' + action.id },
4483
+ React__default["default"].createElement(ActionTimingInput, { name: 'timing-' + action.id, action: action, onChange: props.onChange }))));
4362
4484
  }
4363
- function LabActionBuilder(props) {
4364
- return (React__default["default"].createElement(FormSection, { title: "Lab Details", description: "Choose observations definitions", htmlFor: props.action.id },
4365
- React__default["default"].createElement("a", { href: "#", onClick: () => props.onChange(props.action) }, "Add")));
4366
- }
4367
- function QuestionnaireActionBuilder(props) {
4485
+ function ActionResourceTypeBuilder(props) {
4368
4486
  const { id, definitionCanonical } = props.action;
4369
- const questionnaireRef = (definitionCanonical === null || definitionCanonical === void 0 ? void 0 : definitionCanonical.startsWith('Questionnaire/'))
4487
+ const reference = (definitionCanonical === null || definitionCanonical === void 0 ? void 0 : definitionCanonical.startsWith(props.resourceType + '/'))
4370
4488
  ? { reference: definitionCanonical }
4371
4489
  : undefined;
4372
- return (React__default["default"].createElement(FormSection, { title: "Questionnaire", description: "Choose questionnaire", htmlFor: id },
4373
- React__default["default"].createElement(ResourceInput, { name: id, resourceType: "Questionnaire", defaultValue: questionnaireRef, onChange: (newValue) => {
4490
+ return (React__default["default"].createElement(FormSection, { title: props.title, description: props.description, htmlFor: id },
4491
+ React__default["default"].createElement(ResourceInput, { name: id, resourceType: props.resourceType, defaultValue: reference, loadOnFocus: true, onChange: (newValue) => {
4374
4492
  if (newValue) {
4375
4493
  props.onChange(Object.assign(Object.assign({}, props.action), { definitionCanonical: core.getReferenceString(newValue) }));
4376
4494
  }
@@ -4379,13 +4497,30 @@
4379
4497
  }
4380
4498
  } })));
4381
4499
  }
4500
+ function ActionTimingInput(props) {
4501
+ const value = props.action;
4502
+ const key = 'timing';
4503
+ const [propertyValue, propertyType] = getActionTiming(value);
4504
+ return (React__default["default"].createElement(ResourcePropertyInput, { property: timingProperty, name: "timing[x]", defaultValue: propertyValue, defaultPropertyType: propertyType, onChange: (newValue, propName) => {
4505
+ props.onChange(setPropertyValue(value, key, propName !== null && propName !== void 0 ? propName : key, timingProperty, newValue));
4506
+ } }));
4507
+ }
4382
4508
  function getInitialActionType(action) {
4383
- var _a;
4384
- if ((_a = action.definitionCanonical) === null || _a === void 0 ? void 0 : _a.startsWith('Questionnaire/')) {
4509
+ var _a, _b, _c;
4510
+ if ((_a = action.definitionCanonical) === null || _a === void 0 ? void 0 : _a.startsWith('Schedule')) {
4511
+ return 'appointment';
4512
+ }
4513
+ if ((_b = action.definitionCanonical) === null || _b === void 0 ? void 0 : _b.startsWith('Questionnaire/')) {
4385
4514
  return 'questionnaire';
4386
4515
  }
4516
+ if ((_c = action.definitionCanonical) === null || _c === void 0 ? void 0 : _c.startsWith('ActivityDefinition/')) {
4517
+ return 'task';
4518
+ }
4387
4519
  return undefined;
4388
4520
  }
4521
+ function getActionTiming(action) {
4522
+ return getValueAndType({ type: 'PlanDefinitionAction', value: action }, 'timing');
4523
+ }
4389
4524
  let nextId$1 = 1;
4390
4525
  /**
4391
4526
  * Generates a unique ID.
@@ -4522,7 +4657,7 @@
4522
4657
  const questionnaire = useResource(props.questionnaire);
4523
4658
  const [response, setResponse] = React.useState();
4524
4659
  React.useEffect(() => {
4525
- medplum.requestSchema('Questionnaire').then(setSchema);
4660
+ medplum.requestSchema('Questionnaire').then(setSchema).catch(console.log);
4526
4661
  }, [medplum]);
4527
4662
  React.useEffect(() => {
4528
4663
  setResponse(questionnaire ? buildInitialResponse(questionnaire) : undefined);
@@ -4565,6 +4700,7 @@
4565
4700
  return (React__default["default"].createElement(CheckboxFormSection, { key: item.linkId, title: item.text, htmlFor: item.linkId },
4566
4701
  React__default["default"].createElement(Checkbox, { name: item.linkId, defaultValue: initial === null || initial === void 0 ? void 0 : initial.valueBoolean, onChange: (newValue) => setResponseItem(index, {
4567
4702
  linkId: item.linkId,
4703
+ text: item.text,
4568
4704
  answer: [{ valueBoolean: newValue }],
4569
4705
  }) })));
4570
4706
  }
@@ -4586,12 +4722,14 @@
4586
4722
  function onChangeItem(newResponseItems) {
4587
4723
  props.onChange({
4588
4724
  linkId: item.linkId,
4725
+ text: item.text,
4589
4726
  item: newResponseItems,
4590
4727
  });
4591
4728
  }
4592
4729
  function onChangeAnswer(newResponseAnswer) {
4593
4730
  props.onChange({
4594
4731
  linkId: item.linkId,
4732
+ text: item.text,
4595
4733
  answer: [newResponseAnswer],
4596
4734
  });
4597
4735
  }
@@ -4692,6 +4830,7 @@
4692
4830
  var _a, _b;
4693
4831
  return {
4694
4832
  linkId: item.linkId,
4833
+ text: item.text,
4695
4834
  item: buildInitialResponseItems(item.item),
4696
4835
  answer: (_b = (_a = item.initial) === null || _a === void 0 ? void 0 : _a.map(buildInitialResponseAnswer)) !== null && _b !== void 0 ? _b : [],
4697
4836
  };
@@ -4724,7 +4863,7 @@
4724
4863
  setSelectedKey(undefined);
4725
4864
  }
4726
4865
  React.useEffect(() => {
4727
- medplum.requestSchema('Questionnaire').then(setSchema);
4866
+ medplum.requestSchema('Questionnaire').then(setSchema).catch(console.log);
4728
4867
  }, [medplum]);
4729
4868
  React.useEffect(() => {
4730
4869
  setValue(ensureQuestionnaireKeys(defaultValue !== null && defaultValue !== void 0 ? defaultValue : { resourceType: 'Questionnaire' }));
@@ -4958,9 +5097,9 @@
4958
5097
  return clientId;
4959
5098
  }
4960
5099
  const origin = window.location.protocol + '//' + window.location.host;
4961
- const authorizedOrigins = (_b = (_a = "undefined") === null || _a === void 0 ? void 0 : _a.split(',')) !== null && _b !== void 0 ? _b : [];
5100
+ const authorizedOrigins = (_b = (_a = "http://localhost:3000,http://127.0.0.1:3000,http://localhost:6006,http://127.0.0.1:6006,https://app.medplum.com,https://docs.medplum.com") === null || _a === void 0 ? void 0 : _a.split(',')) !== null && _b !== void 0 ? _b : [];
4962
5101
  if (authorizedOrigins.includes(origin)) {
4963
- return "undefined";
5102
+ return "921088377005-3j1sa10vr6hj86jgmdfh2l53v3mp7lfi.apps.googleusercontent.com";
4964
5103
  }
4965
5104
  return undefined;
4966
5105
  }
@@ -4981,10 +5120,15 @@
4981
5120
  * @returns Promise to a recaptcha token for the current user.
4982
5121
  */
4983
5122
  function getRecaptcha(siteKey) {
4984
- return new Promise((resolve) => {
4985
- grecaptcha.ready(() => {
4986
- grecaptcha.execute(siteKey, { action: 'submit' }).then(resolve);
4987
- });
5123
+ return new Promise((resolve, reject) => {
5124
+ grecaptcha.ready(() => __awaiter(this, void 0, void 0, function* () {
5125
+ try {
5126
+ resolve(yield grecaptcha.execute(siteKey, { action: 'submit' }));
5127
+ }
5128
+ catch (err) {
5129
+ reject(err);
5130
+ }
5131
+ }));
4988
5132
  });
4989
5133
  }
4990
5134
 
@@ -5029,7 +5173,7 @@
5029
5173
  recaptchaToken,
5030
5174
  };
5031
5175
  const userLogin = yield medplum.startNewUser(registerRequest);
5032
- handleAuthResponse(registerRequest, userLogin);
5176
+ yield handleAuthResponse(registerRequest, userLogin);
5033
5177
  }
5034
5178
  catch (err) {
5035
5179
  setOutcome(err);
@@ -5056,7 +5200,7 @@
5056
5200
  lastName: googleClaims.family_name,
5057
5201
  email: googleClaims.email,
5058
5202
  };
5059
- handleAuthResponse(registerRequest, userLogin);
5203
+ yield handleAuthResponse(registerRequest, userLogin);
5060
5204
  }
5061
5205
  catch (err) {
5062
5206
  setOutcome(err);
@@ -5106,7 +5250,7 @@
5106
5250
  const [responseBundle, setResponseBundle] = React.useState();
5107
5251
  React.useEffect(() => {
5108
5252
  if (requestGroup && !startedLoading) {
5109
- medplum.executeBatch(buildBatchRequest(requestGroup)).then(setResponseBundle);
5253
+ medplum.executeBatch(buildBatchRequest(requestGroup)).then(setResponseBundle).catch(console.log);
5110
5254
  setStartedLoading(true);
5111
5255
  }
5112
5256
  }, [medplum, requestGroup, startedLoading]);
@@ -5126,7 +5270,7 @@
5126
5270
  "Last edited by\u00A0",
5127
5271
  React__default["default"].createElement(ResourceName, { value: (_e = task === null || task === void 0 ? void 0 : task.meta) === null || _e === void 0 ? void 0 : _e.author }),
5128
5272
  "\u00A0on\u00A0",
5129
- React__default["default"].createElement(DateTimeDisplay, { value: (_f = task === null || task === void 0 ? void 0 : task.meta) === null || _f === void 0 ? void 0 : _f.lastUpdated })),
5273
+ core.formatDateTime((_f = task === null || task === void 0 ? void 0 : task.meta) === null || _f === void 0 ? void 0 : _f.lastUpdated)),
5130
5274
  React__default["default"].createElement("div", null,
5131
5275
  "Status: ",
5132
5276
  React__default["default"].createElement(StatusBadge, { status: (task === null || task === void 0 ? void 0 : task.status) || 'unknown' }))),
@@ -5351,7 +5495,7 @@
5351
5495
  const [value, setValue] = React.useState(props.history);
5352
5496
  React.useEffect(() => {
5353
5497
  if (!props.history && props.resourceType && props.id) {
5354
- medplum.readHistory(props.resourceType, props.id).then((result) => setValue(result));
5498
+ medplum.readHistory(props.resourceType, props.id).then(setValue).catch(console.log);
5355
5499
  }
5356
5500
  }, [medplum, props.history, props.resourceType, props.id]);
5357
5501
  if (!value) {
@@ -5429,7 +5573,10 @@
5429
5573
  const [value, setValue] = React.useState(props.history);
5430
5574
  React.useEffect(() => {
5431
5575
  if (!props.history && props.resourceType && props.id) {
5432
- medplum.readHistory(props.resourceType, props.id).then((result) => setValue(result));
5576
+ medplum
5577
+ .readHistory(props.resourceType, props.id)
5578
+ .then(setValue)
5579
+ .catch(console.log);
5433
5580
  }
5434
5581
  }, [medplum, props.history, props.resourceType, props.id]);
5435
5582
  if (!value) {
@@ -5451,8 +5598,7 @@
5451
5598
  return (React__default["default"].createElement("tr", null,
5452
5599
  React__default["default"].createElement("td", null,
5453
5600
  React__default["default"].createElement(ResourceBadge, { value: (_a = props.version.meta) === null || _a === void 0 ? void 0 : _a.author, link: true })),
5454
- React__default["default"].createElement("td", null,
5455
- React__default["default"].createElement(DateTimeDisplay, { value: (_b = props.version.meta) === null || _b === void 0 ? void 0 : _b.lastUpdated })),
5601
+ React__default["default"].createElement("td", null, core.formatDateTime((_b = props.version.meta) === null || _b === void 0 ? void 0 : _b.lastUpdated)),
5456
5602
  React__default["default"].createElement("td", null,
5457
5603
  React__default["default"].createElement(MedplumLink, { to: getVersionUrl(props.version) }, (_c = props.version.meta) === null || _c === void 0 ? void 0 : _c.versionId))));
5458
5604
  }
@@ -5470,12 +5616,14 @@
5470
5616
  return date.toLocaleString('default', { month: 'long' }) + ' ' + date.getFullYear();
5471
5617
  }
5472
5618
  function CalendarInput(props) {
5619
+ const { onChangeMonth, onClick } = props;
5473
5620
  const [month, setMonth] = React.useState(getStartMonth);
5474
5621
  function moveMonth(delta) {
5475
5622
  setMonth((currMonth) => {
5476
- const prevMonth = new Date(currMonth.getTime());
5477
- prevMonth.setMonth(currMonth.getMonth() + delta);
5478
- return prevMonth;
5623
+ const newMonth = new Date(currMonth.getTime());
5624
+ newMonth.setMonth(currMonth.getMonth() + delta);
5625
+ onChangeMonth(newMonth);
5626
+ return newMonth;
5479
5627
  });
5480
5628
  }
5481
5629
  const grid = React.useMemo(() => buildGrid(month, props.slots), [month, props.slots]);
@@ -5495,7 +5643,7 @@
5495
5643
  React__default["default"].createElement("th", null, "THU"),
5496
5644
  React__default["default"].createElement("th", null, "FRI"),
5497
5645
  React__default["default"].createElement("th", null, "SAT"))),
5498
- React__default["default"].createElement("tbody", null, grid.map((week, weekIndex) => (React__default["default"].createElement("tr", { key: 'week-' + weekIndex }, week.map((day, dayIndex) => (React__default["default"].createElement("td", { key: 'day-' + dayIndex }, day && (React__default["default"].createElement("button", { disabled: !day.available, onClick: () => props.onClick(day.date) }, day.date.getDate()))))))))))));
5646
+ React__default["default"].createElement("tbody", null, grid.map((week, weekIndex) => (React__default["default"].createElement("tr", { key: 'week-' + weekIndex }, week.map((day, dayIndex) => (React__default["default"].createElement("td", { key: 'day-' + dayIndex }, day && (React__default["default"].createElement("button", { disabled: !day.available, onClick: () => onClick(day.date) }, day.date.getDate()))))))))))));
5499
5647
  }
5500
5648
  function getStartMonth() {
5501
5649
  const result = new Date();
@@ -5514,7 +5662,6 @@
5514
5662
  while (d.getMonth() === startDate.getMonth()) {
5515
5663
  row.push({
5516
5664
  date: new Date(d.getTime()),
5517
- // available: isAvailable(d),
5518
5665
  available: isDayAvailable(d, slots),
5519
5666
  });
5520
5667
  if (d.getDay() === 6) {
@@ -5558,20 +5705,27 @@
5558
5705
  const [slots, setSlots] = React.useState();
5559
5706
  const slotsRef = React.useRef();
5560
5707
  slotsRef.current = slots;
5708
+ const [month, setMonth] = React.useState(getStartMonth());
5561
5709
  const [date, setDate] = React.useState();
5562
5710
  const [slot, setSlot] = React.useState();
5563
5711
  const [info, setInfo] = React.useState();
5564
5712
  const [form, setForm] = React.useState();
5565
5713
  React.useEffect(() => {
5566
5714
  if (schedule) {
5567
- medplum.search('Slot', 'schedule=' + core.getReferenceString(schedule)).then((bundle) => {
5568
- setSlots(bundle.entry.map((entry) => entry.resource));
5569
- });
5715
+ setSlots([]);
5716
+ medplum
5717
+ .searchResources('Slot', new URLSearchParams([
5718
+ ['schedule', core.getReferenceString(schedule)],
5719
+ ['start', 'gt' + month.toISOString()],
5720
+ ['start', 'lt' + new Date(month.getTime() + 31 * 24 * 60 * 60 * 1000).toISOString()],
5721
+ ]))
5722
+ .then(setSlots)
5723
+ .catch(console.log);
5570
5724
  }
5571
5725
  else {
5572
5726
  setSlots(undefined);
5573
5727
  }
5574
- }, [medplum, schedule]);
5728
+ }, [medplum, schedule, month]);
5575
5729
  if (!schedule || !slots) {
5576
5730
  return null;
5577
5731
  }
@@ -5587,7 +5741,7 @@
5587
5741
  React__default["default"].createElement("div", { className: "medplum-calendar-selection-pane" },
5588
5742
  !date && (React__default["default"].createElement("div", null,
5589
5743
  React__default["default"].createElement("h3", null, "Select date"),
5590
- React__default["default"].createElement(CalendarInput, { slots: slots, onClick: setDate }))),
5744
+ React__default["default"].createElement(CalendarInput, { slots: slots, onChangeMonth: setMonth, onClick: setDate }))),
5591
5745
  date && !slot && (React__default["default"].createElement("div", null,
5592
5746
  React__default["default"].createElement("h3", null, "Select time"),
5593
5747
  slots.map((s) => {
@@ -5696,11 +5850,14 @@
5696
5850
  }
5697
5851
  return (React__default["default"].createElement(Document, { width: 450 }, (() => {
5698
5852
  if (!login) {
5699
- return (React__default["default"].createElement(AuthenticationForm, { clientId: props.clientId, scope: props.scope, nonce: props.nonce, googleClientId: props.googleClientId, onForgotPassword: props.onForgotPassword, onRegister: props.onRegister, handleAuthResponse: handleAuthResponse }, props.children));
5853
+ return (React__default["default"].createElement(AuthenticationForm, { projectId: props.projectId, clientId: props.clientId, scope: props.scope, nonce: props.nonce, googleClientId: props.googleClientId, onForgotPassword: props.onForgotPassword, onRegister: props.onRegister, handleAuthResponse: handleAuthResponse }, props.children));
5700
5854
  }
5701
5855
  else if (memberships) {
5702
5856
  return React__default["default"].createElement(ProfileForm, { login: login, memberships: memberships, handleAuthResponse: handleAuthResponse });
5703
5857
  }
5858
+ else if (props.projectId === 'new') {
5859
+ return React__default["default"].createElement(NewProjectForm, { login: login, handleAuthResponse: handleAuthResponse });
5860
+ }
5704
5861
  else {
5705
5862
  return React__default["default"].createElement("div", null, "Success");
5706
5863
  }
@@ -5714,6 +5871,7 @@
5714
5871
  return (React__default["default"].createElement(Form, { style: { maxWidth: 400 }, onSubmit: (formData) => {
5715
5872
  medplum
5716
5873
  .startLogin({
5874
+ projectId: props.projectId,
5717
5875
  clientId: props.clientId,
5718
5876
  scope: props.scope,
5719
5877
  nonce: props.nonce,
@@ -5734,6 +5892,7 @@
5734
5892
  React__default["default"].createElement(GoogleButton, { googleClientId: googleClientId, handleGoogleCredential: (response) => {
5735
5893
  medplum
5736
5894
  .startGoogleLogin({
5895
+ projectId: props.projectId,
5737
5896
  clientId: props.clientId,
5738
5897
  scope: props.scope,
5739
5898
  nonce: props.nonce,
@@ -5772,7 +5931,8 @@
5772
5931
  login: props.login,
5773
5932
  profile: membership.id,
5774
5933
  })
5775
- .then(props.handleAuthResponse);
5934
+ .then(props.handleAuthResponse)
5935
+ .catch(console.log);
5776
5936
  } },
5777
5937
  React__default["default"].createElement("div", { className: "medplum-nav-menu-profile-icon" },
5778
5938
  React__default["default"].createElement(Avatar, { alt: (_a = membership.profile) === null || _a === void 0 ? void 0 : _a.display })),
@@ -5781,6 +5941,36 @@
5781
5941
  React__default["default"].createElement("div", { className: "medplum-nav-menu-profile-help-text" }, (_c = membership.project) === null || _c === void 0 ? void 0 : _c.display))));
5782
5942
  })));
5783
5943
  }
5944
+ function NewProjectForm(props) {
5945
+ const medplum = useMedplum();
5946
+ const [outcome, setOutcome] = React.useState();
5947
+ return (React__default["default"].createElement(Form, { style: { maxWidth: 400 }, onSubmit: (formData) => __awaiter(this, void 0, void 0, function* () {
5948
+ try {
5949
+ const registerRequest = { projectName: formData.projectName };
5950
+ const partialLogin = { login: props.login };
5951
+ const login = yield medplum.startNewProject(registerRequest, partialLogin);
5952
+ props.handleAuthResponse(login);
5953
+ }
5954
+ catch (err) {
5955
+ setOutcome(err);
5956
+ }
5957
+ }) },
5958
+ React__default["default"].createElement("div", { className: "medplum-center" },
5959
+ React__default["default"].createElement(Logo, { size: 32 }),
5960
+ React__default["default"].createElement("h1", null, "Create project")),
5961
+ React__default["default"].createElement(FormSection, { title: "Project Name", htmlFor: "projectName", outcome: outcome },
5962
+ React__default["default"].createElement(Input, { name: "projectName", type: "text", testid: "projectName", placeholder: "My Project", required: true, outcome: outcome })),
5963
+ React__default["default"].createElement("p", { style: { fontSize: '12px', color: '#888' } },
5964
+ "By clicking submit you agree to the Medplum ",
5965
+ React__default["default"].createElement("a", { href: "https://www.medplum.com/privacy" }, "Privacy\u00A0Policy"),
5966
+ ' and ',
5967
+ React__default["default"].createElement("a", { href: "https://www.medplum.com/terms" }, "Terms\u00A0of\u00A0Service"),
5968
+ "."),
5969
+ React__default["default"].createElement("div", { className: "medplum-signin-buttons" },
5970
+ React__default["default"].createElement("div", null),
5971
+ React__default["default"].createElement("div", null,
5972
+ React__default["default"].createElement(Button, { type: "submit", testid: "submit" }, "Create project")))));
5973
+ }
5784
5974
 
5785
5975
  function Tab(props) {
5786
5976
  let className = 'medplum-tab';
@@ -5846,9 +6036,10 @@
5846
6036
  exports.ContactDetailInput = ContactDetailInput;
5847
6037
  exports.ContactPointDisplay = ContactPointDisplay;
5848
6038
  exports.ContactPointInput = ContactPointInput;
5849
- exports.DateTimeDisplay = DateTimeDisplay;
5850
6039
  exports.DateTimeInput = DateTimeInput;
5851
6040
  exports.DefaultResourceTimeline = DefaultResourceTimeline;
6041
+ exports.DescriptionList = DescriptionList;
6042
+ exports.DescriptionListEntry = DescriptionListEntry;
5852
6043
  exports.DiagnosticReportDisplay = DiagnosticReportDisplay;
5853
6044
  exports.Document = Document;
5854
6045
  exports.ElementDefinitionInputSelector = ElementDefinitionInputSelector;