@medplum/react 0.9.28 → 0.9.31

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 (240) 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/RequestGroupDisplay.d.ts +9 -0
  71. package/dist/cjs/ResourceArrayDisplay.d.ts +11 -0
  72. package/dist/cjs/ResourceArrayInput.d.ts +11 -0
  73. package/dist/cjs/ResourceBadge.d.ts +9 -0
  74. package/dist/cjs/ResourceBlame.d.ts +10 -0
  75. package/dist/cjs/ResourceDiff.d.ts +9 -0
  76. package/dist/cjs/ResourceDiffTable.d.ts +9 -0
  77. package/dist/cjs/ResourceForm.d.ts +10 -0
  78. package/dist/cjs/ResourceHistoryTable.d.ts +9 -0
  79. package/dist/cjs/ResourceInput.d.ts +12 -0
  80. package/dist/cjs/ResourceName.d.ts +7 -0
  81. package/dist/cjs/ResourcePropertyDisplay.d.ts +24 -0
  82. package/dist/cjs/ResourcePropertyInput.d.ts +21 -0
  83. package/dist/cjs/ResourceTable.d.ts +7 -0
  84. package/dist/cjs/ResourceTimeline.d.ts +11 -0
  85. package/dist/cjs/Scheduler.d.ts +7 -0
  86. package/dist/cjs/Scrollable.d.ts +9 -0
  87. package/dist/cjs/SearchControl.d.ts +40 -0
  88. package/dist/cjs/SearchControlField.d.ts +41 -0
  89. package/dist/cjs/SearchFieldEditor.d.ts +11 -0
  90. package/dist/cjs/SearchFilterEditor.d.ts +11 -0
  91. package/dist/cjs/SearchFilterValueDialog.d.ts +15 -0
  92. package/dist/cjs/SearchFilterValueDisplay.d.ts +7 -0
  93. package/dist/cjs/SearchFilterValueInput.d.ts +12 -0
  94. package/dist/cjs/SearchPopupMenu.d.ts +15 -0
  95. package/dist/cjs/SearchUtils.d.ts +174 -0
  96. package/dist/cjs/Select.d.ts +16 -0
  97. package/dist/cjs/ServiceRequestTimeline.d.ts +6 -0
  98. package/dist/cjs/StatusBadge.d.ts +6 -0
  99. package/dist/cjs/SubMenu.d.ts +7 -0
  100. package/dist/cjs/Tab.d.ts +12 -0
  101. package/dist/cjs/TabList.d.ts +10 -0
  102. package/dist/cjs/TabPanel.d.ts +6 -0
  103. package/dist/cjs/TabSwitch.d.ts +6 -0
  104. package/dist/cjs/TextArea.d.ts +18 -0
  105. package/dist/cjs/Timeline.d.ts +17 -0
  106. package/dist/cjs/TimingInput.d.ts +8 -0
  107. package/dist/cjs/TitleBar.d.ts +6 -0
  108. package/dist/cjs/UploadButton.d.ts +7 -0
  109. package/dist/cjs/auth/AuthenticationForm.d.ts +14 -0
  110. package/dist/cjs/auth/ChooseProfileForm.d.ts +8 -0
  111. package/dist/cjs/auth/NewProjectForm.d.ts +7 -0
  112. package/dist/cjs/auth/NewUserForm.d.ts +10 -0
  113. package/dist/cjs/auth/RegisterForm.d.ts +12 -0
  114. package/dist/{esm → cjs/auth}/SignInForm.d.ts +1 -1
  115. package/dist/cjs/constants.d.ts +1 -0
  116. package/dist/cjs/index.d.ts +87 -0
  117. package/dist/cjs/index.js +660 -565
  118. package/dist/cjs/index.js.map +1 -1
  119. package/dist/cjs/index.min.js +1 -1
  120. package/dist/cjs/index.min.js.map +1 -1
  121. package/dist/cjs/stories/AddressInput.stories.d.ts +6 -0
  122. package/dist/cjs/stories/AttachmentArrayInput.stories.d.ts +6 -0
  123. package/dist/cjs/stories/AttachmentInput.stories.d.ts +6 -0
  124. package/dist/cjs/stories/Autocomplete.stories.d.ts +9 -0
  125. package/dist/cjs/stories/Avatar.stories.d.ts +10 -0
  126. package/dist/cjs/stories/Button.stories.d.ts +9 -0
  127. package/dist/cjs/stories/CodeableConceptDisplay.stories.d.ts +8 -0
  128. package/dist/cjs/stories/DiagnosticReportDisplay.stories.d.ts +5 -0
  129. package/dist/cjs/stories/Dialog.stories.d.ts +5 -0
  130. package/dist/cjs/stories/EncounterTimeline.stories.d.ts +5 -0
  131. package/dist/cjs/stories/FhirPathDisplay.stories.d.ts +7 -0
  132. package/dist/cjs/stories/FormSection.stories.d.ts +6 -0
  133. package/dist/cjs/stories/Header.stories.d.ts +8 -0
  134. package/dist/cjs/stories/Input.stories.d.ts +6 -0
  135. package/dist/cjs/stories/Loading.stories.d.ts +5 -0
  136. package/dist/cjs/stories/Logo.stories.d.ts +5 -0
  137. package/dist/cjs/stories/PatientTimeline.stories.d.ts +5 -0
  138. package/dist/cjs/stories/PlanDefinitionBuilder.stories.d.ts +5 -0
  139. package/dist/cjs/stories/QuestionnaireBuilder.stories.d.ts +7 -0
  140. package/dist/cjs/stories/QuestionnaireForm.stories.d.ts +11 -0
  141. package/dist/cjs/stories/ReferenceInput.stories.d.ts +6 -0
  142. package/dist/cjs/stories/RegisterForm.stories.d.ts +7 -0
  143. package/dist/cjs/stories/RequestGroupDisplay.stories.d.ts +5 -0
  144. package/dist/cjs/stories/ResourceBlame.stories.d.ts +5 -0
  145. package/dist/cjs/stories/ResourceForm.stories.d.ts +12 -0
  146. package/dist/cjs/stories/ResourceHistoryTable.stories.d.ts +5 -0
  147. package/dist/cjs/stories/ResourceTable.stories.d.ts +7 -0
  148. package/dist/cjs/stories/Scheduler.stories.d.ts +5 -0
  149. package/dist/cjs/stories/SearchControl.stories.d.ts +13 -0
  150. package/dist/cjs/stories/Select.stories.d.ts +6 -0
  151. package/dist/cjs/stories/SignInForm.stories.d.ts +8 -0
  152. package/dist/cjs/stories/StatusBadge.stories.d.ts +5 -0
  153. package/dist/cjs/stories/Tabs.stories.d.ts +6 -0
  154. package/dist/cjs/stories/Timeline.stories.d.ts +5 -0
  155. package/dist/cjs/stories/TimingInput.stories.d.ts +6 -0
  156. package/dist/cjs/stories/UploadButton.stories.d.ts +6 -0
  157. package/dist/cjs/styles.css +248 -247
  158. package/dist/cjs/test.setup.d.ts +1 -0
  159. package/dist/cjs/useResource.d.ts +8 -0
  160. package/dist/cjs/utils/blame.d.ts +8 -0
  161. package/dist/cjs/utils/date.d.ts +6 -0
  162. package/dist/cjs/utils/diff.d.ts +16 -0
  163. package/dist/cjs/utils/dom.d.ts +15 -0
  164. package/dist/cjs/utils/outcomes.d.ts +2 -0
  165. package/dist/cjs/utils/recaptcha.d.ts +12 -0
  166. package/dist/cjs/utils.d.ts +5 -0
  167. package/dist/esm/Autocomplete.js +1 -0
  168. package/dist/esm/Autocomplete.js.map +1 -1
  169. package/dist/esm/CalendarInput.d.ts +1 -0
  170. package/dist/esm/CalendarInput.js +6 -5
  171. package/dist/esm/CalendarInput.js.map +1 -1
  172. package/dist/esm/CodeInput.js +1 -1
  173. package/dist/esm/CodeInput.js.map +1 -1
  174. package/dist/esm/CodeableConceptInput.js +1 -1
  175. package/dist/esm/CodeableConceptInput.js.map +1 -1
  176. package/dist/esm/CodingInput.js +1 -1
  177. package/dist/esm/CodingInput.js.map +1 -1
  178. package/dist/esm/FhirPathTable.js +5 -2
  179. package/dist/esm/FhirPathTable.js.map +1 -1
  180. package/dist/esm/GoogleButton.js +1 -1
  181. package/dist/esm/GoogleButton.js.map +1 -1
  182. package/dist/esm/Header.js +7 -3
  183. package/dist/esm/Header.js.map +1 -1
  184. package/dist/esm/MedplumLink.js +29 -14
  185. package/dist/esm/MedplumLink.js.map +1 -1
  186. package/dist/esm/PlanDefinitionBuilder.js +1 -1
  187. package/dist/esm/PlanDefinitionBuilder.js.map +1 -1
  188. package/dist/esm/QuestionnaireBuilder.js +1 -1
  189. package/dist/esm/QuestionnaireBuilder.js.map +1 -1
  190. package/dist/esm/QuestionnaireForm.js +2 -1
  191. package/dist/esm/QuestionnaireForm.js.map +1 -1
  192. package/dist/esm/RequestGroupDisplay.js +1 -1
  193. package/dist/esm/RequestGroupDisplay.js.map +1 -1
  194. package/dist/esm/ResourceBlame.js +1 -1
  195. package/dist/esm/ResourceBlame.js.map +1 -1
  196. package/dist/esm/ResourceDiffTable.js +1 -1
  197. package/dist/esm/ResourceDiffTable.js.map +1 -1
  198. package/dist/esm/ResourceForm.js +1 -1
  199. package/dist/esm/ResourceForm.js.map +1 -1
  200. package/dist/esm/ResourceHistoryTable.js +19 -12
  201. package/dist/esm/ResourceHistoryTable.js.map +1 -1
  202. package/dist/esm/ResourceTable.js +1 -1
  203. package/dist/esm/ResourceTable.js.map +1 -1
  204. package/dist/esm/ResourceTimeline.js +16 -8
  205. package/dist/esm/ResourceTimeline.js.map +1 -1
  206. package/dist/esm/Scheduler.js +13 -6
  207. package/dist/esm/Scheduler.js.map +1 -1
  208. package/dist/esm/SearchControl.js +5 -2
  209. package/dist/esm/SearchControl.js.map +1 -1
  210. package/dist/esm/auth/AuthenticationForm.d.ts +14 -0
  211. package/dist/esm/{SignInForm.js → auth/AuthenticationForm.js} +12 -75
  212. package/dist/esm/auth/AuthenticationForm.js.map +1 -0
  213. package/dist/esm/auth/ChooseProfileForm.d.ts +8 -0
  214. package/dist/esm/auth/ChooseProfileForm.js +32 -0
  215. package/dist/esm/auth/ChooseProfileForm.js.map +1 -0
  216. package/dist/esm/auth/NewProjectForm.d.ts +7 -0
  217. package/dist/esm/auth/NewProjectForm.js +42 -0
  218. package/dist/esm/auth/NewProjectForm.js.map +1 -0
  219. package/dist/esm/auth/NewUserForm.d.ts +10 -0
  220. package/dist/esm/auth/NewUserForm.js +87 -0
  221. package/dist/esm/auth/NewUserForm.js.map +1 -0
  222. package/dist/esm/auth/RegisterForm.d.ts +12 -0
  223. package/dist/esm/auth/RegisterForm.js +39 -0
  224. package/dist/esm/auth/RegisterForm.js.map +1 -0
  225. package/dist/esm/auth/SignInForm.d.ts +17 -0
  226. package/dist/esm/auth/SignInForm.js +52 -0
  227. package/dist/esm/auth/SignInForm.js.map +1 -0
  228. package/dist/esm/index.d.ts +3 -2
  229. package/dist/esm/index.js +3 -2
  230. package/dist/esm/index.js.map +1 -1
  231. package/dist/esm/index.min.js +1 -1
  232. package/dist/esm/index.min.js.map +1 -1
  233. package/dist/esm/styles.css +248 -247
  234. package/dist/esm/utils/recaptcha.js +10 -4
  235. package/dist/esm/utils/recaptcha.js.map +1 -1
  236. package/package.json +16 -18
  237. package/dist/esm/RegisterForm.d.ts +0 -18
  238. package/dist/esm/RegisterForm.js +0 -121
  239. package/dist/esm/RegisterForm.js.map +0 -1
  240. package/dist/esm/SignInForm.js.map +0 -1
package/dist/cjs/index.js CHANGED
@@ -329,6 +329,578 @@
329
329
  return React__default["default"].createElement(UploadButton, { onUpload: setValueWrapper });
330
330
  }
331
331
 
332
+ function Document(props) {
333
+ return (React__default["default"].createElement("main", { className: "medplum-document" },
334
+ React__default["default"].createElement("article", { style: { maxWidth: props.width } }, props.children)));
335
+ }
336
+
337
+ /******************************************************************************
338
+ Copyright (c) Microsoft Corporation.
339
+
340
+ Permission to use, copy, modify, and/or distribute this software for any
341
+ purpose with or without fee is hereby granted.
342
+
343
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
344
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
345
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
346
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
347
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
348
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
349
+ PERFORMANCE OF THIS SOFTWARE.
350
+ ***************************************************************************** */
351
+
352
+ function __awaiter(thisArg, _arguments, P, generator) {
353
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
354
+ return new (P || (P = Promise))(function (resolve, reject) {
355
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
356
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
357
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
358
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
359
+ });
360
+ }
361
+
362
+ /**
363
+ * Parses an HTML form and returns the result as a JavaScript object.
364
+ * @param form The HTML form element.
365
+ */
366
+ function parseForm(form) {
367
+ const result = {};
368
+ for (const element of Array.from(form.elements)) {
369
+ if (element instanceof HTMLInputElement) {
370
+ parseInputElement(result, element);
371
+ }
372
+ else if (element instanceof HTMLTextAreaElement) {
373
+ result[element.name] = element.value;
374
+ }
375
+ else if (element instanceof HTMLSelectElement) {
376
+ parseSelectElement(result, element);
377
+ }
378
+ }
379
+ return result;
380
+ }
381
+ /**
382
+ * Parses an HTML input element.
383
+ * Sets the name/value pair in the result,
384
+ * but only if the element is enabled and checked.
385
+ * @param el The input element.
386
+ * @param result The result builder.
387
+ */
388
+ function parseInputElement(result, el) {
389
+ if (el.disabled) {
390
+ // Ignore disabled elements
391
+ return;
392
+ }
393
+ if ((el.type === 'checkbox' || el.type === 'radio') && !el.checked) {
394
+ // Ignore unchecked radio or checkbox elements
395
+ return;
396
+ }
397
+ result[el.name] = el.value;
398
+ }
399
+ /**
400
+ * Parses an HTML select element.
401
+ * Sets the name/value pair if one is selected.
402
+ * @param result The result builder.
403
+ * @param el The select element.
404
+ */
405
+ function parseSelectElement(result, el) {
406
+ result[el.name] = el.value;
407
+ }
408
+
409
+ function Form(props) {
410
+ return (React__default["default"].createElement("form", { style: props.style, "data-testid": props.testid, onSubmit: (e) => {
411
+ e.preventDefault();
412
+ const formData = parseForm(e.target);
413
+ if (props.onSubmit) {
414
+ props.onSubmit(formData);
415
+ }
416
+ } }, props.children));
417
+ }
418
+
419
+ function FormSection(props) {
420
+ const issues = getIssuesForExpression(props.outcome, props.htmlFor);
421
+ const invalid = issues && issues.length > 0;
422
+ return (React__default["default"].createElement("fieldset", { className: "medplum-form-section" },
423
+ props.title && React__default["default"].createElement("label", { htmlFor: props.htmlFor }, props.title),
424
+ props.description && React__default["default"].createElement("p", null, props.description),
425
+ props.children,
426
+ invalid && (React__default["default"].createElement("div", { id: props.htmlFor + '-errors', className: "medplum-input-error" }, issues === null || issues === void 0 ? void 0 : issues.map((issue) => {
427
+ var _a, _b;
428
+ return (React__default["default"].createElement("div", { "data-testid": "text-field-error", key: (_a = issue.details) === null || _a === void 0 ? void 0 : _a.text }, (_b = issue.details) === null || _b === void 0 ? void 0 : _b.text));
429
+ })))));
430
+ }
431
+
432
+ function Logo(props) {
433
+ return (React__default["default"].createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 491 491", style: { width: props.size, height: props.size } },
434
+ React__default["default"].createElement("title", null, "Medplum Logo"),
435
+ React__default["default"].createElement("path", { fill: props.fill || '#ad7136', d: "M282 67c6-16 16-29 29-40L289 0c-22 17-37 41-43 68l17 23 19-24z" }),
436
+ React__default["default"].createElement("path", { fill: props.fill || '#654b87', d: "M311 63c-17 0-33 4-48 11-16-7-32-11-49-11-87 0-158 96-158 214s71 214 158 214c17 0 33-4 49-11 15 7 31 11 48 11 87 0 158-96 158-214S398 63 311 63z" }),
437
+ React__default["default"].createElement("path", { fill: props.fill || '#463068', d: "M231 489l-17 2c-87 0-158-96-158-214S127 63 214 63l17 1c-39 12-70 102-70 213s31 201 70 212z" }),
438
+ React__default["default"].createElement("path", { fill: props.fill || '#70d65b', d: "M207 220a176 176 0 01-177 43A176 176 0 01251 43l1 5c17 59 2 125-45 172z" }),
439
+ React__default["default"].createElement("path", { fill: props.fill || '#58b741', d: "M252 48A421 421 0 0057 270l-27-7A176 176 0 01251 43l1 5z" })));
440
+ }
441
+
442
+ function NewProjectForm(props) {
443
+ const medplum = useMedplum();
444
+ const [outcome, setOutcome] = React.useState();
445
+ return (React__default["default"].createElement(Form, { style: { maxWidth: 400 }, onSubmit: (formData) => __awaiter(this, void 0, void 0, function* () {
446
+ try {
447
+ props.handleAuthResponse(yield medplum.startNewProject({
448
+ login: props.login,
449
+ projectName: formData.projectName,
450
+ }));
451
+ }
452
+ catch (err) {
453
+ setOutcome(err);
454
+ }
455
+ }) },
456
+ React__default["default"].createElement("div", { className: "medplum-center" },
457
+ React__default["default"].createElement(Logo, { size: 32 }),
458
+ React__default["default"].createElement("h1", null, "Create project")),
459
+ React__default["default"].createElement(FormSection, { title: "Project Name", htmlFor: "projectName", outcome: outcome },
460
+ React__default["default"].createElement(Input, { name: "projectName", type: "text", testid: "projectName", placeholder: "My Project", required: true, outcome: outcome })),
461
+ React__default["default"].createElement("p", { style: { fontSize: '12px', color: '#888' } },
462
+ "By clicking submit you agree to the Medplum ",
463
+ React__default["default"].createElement("a", { href: "https://www.medplum.com/privacy" }, "Privacy\u00A0Policy"),
464
+ ' and ',
465
+ React__default["default"].createElement("a", { href: "https://www.medplum.com/terms" }, "Terms\u00A0of\u00A0Service"),
466
+ "."),
467
+ React__default["default"].createElement("div", { className: "medplum-signin-buttons" },
468
+ React__default["default"].createElement("div", null),
469
+ React__default["default"].createElement("div", null,
470
+ React__default["default"].createElement(Button, { type: "submit", testid: "submit" }, "Create project")))));
471
+ }
472
+
473
+ /**
474
+ * Dynamically creates a script tag for the specified JavaScript file.
475
+ * @param src The JavaScript file URL.
476
+ */
477
+ function createScriptTag(src, onload) {
478
+ const head = document.getElementsByTagName('head')[0];
479
+ const script = document.createElement('script');
480
+ script.async = true;
481
+ script.src = src;
482
+ script.onload = onload || null;
483
+ head.appendChild(script);
484
+ }
485
+
486
+ function GoogleButton(props) {
487
+ const medplum = useMedplum();
488
+ const { googleClientId, handleGoogleCredential } = props;
489
+ const parentRef = React.useRef(null);
490
+ const [scriptLoaded, setScriptLoaded] = React.useState(typeof google !== 'undefined');
491
+ const [initialized, setInitialized] = React.useState(false);
492
+ const [buttonRendered, setButtonRendered] = React.useState(false);
493
+ React.useEffect(() => {
494
+ if (typeof google === 'undefined') {
495
+ createScriptTag('https://accounts.google.com/gsi/client', () => setScriptLoaded(true));
496
+ return;
497
+ }
498
+ if (!initialized) {
499
+ google.accounts.id.initialize({
500
+ client_id: googleClientId,
501
+ callback: handleGoogleCredential,
502
+ });
503
+ setInitialized(true);
504
+ }
505
+ if (parentRef.current && !buttonRendered) {
506
+ google.accounts.id.renderButton(parentRef.current, {});
507
+ setButtonRendered(true);
508
+ }
509
+ }, [medplum, googleClientId, initialized, scriptLoaded, parentRef, buttonRendered, handleGoogleCredential]);
510
+ if (!googleClientId) {
511
+ return null;
512
+ }
513
+ return React__default["default"].createElement("div", { ref: parentRef });
514
+ }
515
+ function getGoogleClientId(clientId) {
516
+ var _a, _b;
517
+ if (clientId) {
518
+ return clientId;
519
+ }
520
+ const origin = window.location.protocol + '//' + window.location.host;
521
+ 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 : [];
522
+ if (authorizedOrigins.includes(origin)) {
523
+ return "921088377005-3j1sa10vr6hj86jgmdfh2l53v3mp7lfi.apps.googleusercontent.com";
524
+ }
525
+ return undefined;
526
+ }
527
+
528
+ /**
529
+ * Dynamically loads the recaptcha script.
530
+ * We do not want to load the script on page load unless the user needs it.
531
+ * @param siteKey The reCAPTCHA site key, available from the reCAPTCHA admin page.
532
+ */
533
+ function initRecaptcha(siteKey) {
534
+ if (typeof grecaptcha === 'undefined') {
535
+ createScriptTag('https://www.google.com/recaptcha/api.js?render=' + siteKey);
536
+ }
537
+ }
538
+ /**
539
+ * Starts a request to generate a recapcha token.
540
+ * @param siteKey The reCAPTCHA site key, available from the reCAPTCHA admin page.
541
+ * @returns Promise to a recaptcha token for the current user.
542
+ */
543
+ function getRecaptcha(siteKey) {
544
+ return new Promise((resolve, reject) => {
545
+ grecaptcha.ready(() => __awaiter(this, void 0, void 0, function* () {
546
+ try {
547
+ resolve(yield grecaptcha.execute(siteKey, { action: 'submit' }));
548
+ }
549
+ catch (err) {
550
+ reject(err);
551
+ }
552
+ }));
553
+ });
554
+ }
555
+
556
+ function NewUserForm(props) {
557
+ const googleClientId = getGoogleClientId(props.googleClientId);
558
+ const recaptchaSiteKey = props.recaptchaSiteKey;
559
+ const medplum = useMedplum();
560
+ const [outcome, setOutcome] = React.useState();
561
+ const issues = getIssuesForExpression(outcome, undefined);
562
+ React.useEffect(() => initRecaptcha(recaptchaSiteKey), [recaptchaSiteKey]);
563
+ return (React__default["default"].createElement(Form, { style: { maxWidth: 400 }, onSubmit: (formData) => __awaiter(this, void 0, void 0, function* () {
564
+ try {
565
+ const recaptchaToken = yield getRecaptcha(recaptchaSiteKey);
566
+ props.handleAuthResponse(yield medplum.startNewUser({
567
+ projectId: props.projectId,
568
+ firstName: formData.firstName,
569
+ lastName: formData.lastName,
570
+ email: formData.email,
571
+ password: formData.password,
572
+ remember: formData.remember === 'true',
573
+ recaptchaSiteKey,
574
+ recaptchaToken,
575
+ }));
576
+ }
577
+ catch (err) {
578
+ setOutcome(err);
579
+ }
580
+ }) },
581
+ React__default["default"].createElement("div", { className: "medplum-center" }, props.children),
582
+ issues && (React__default["default"].createElement("div", { className: "medplum-input-error" }, issues.map((issue) => {
583
+ var _a, _b;
584
+ return (React__default["default"].createElement("div", { "data-testid": "text-field-error", key: (_a = issue.details) === null || _a === void 0 ? void 0 : _a.text }, (_b = issue.details) === null || _b === void 0 ? void 0 : _b.text));
585
+ }))),
586
+ googleClientId && (React__default["default"].createElement(React__default["default"].Fragment, null,
587
+ React__default["default"].createElement("div", { className: "medplum-signin-google-container" },
588
+ React__default["default"].createElement(GoogleButton, { googleClientId: googleClientId, handleGoogleCredential: (response) => __awaiter(this, void 0, void 0, function* () {
589
+ try {
590
+ props.handleAuthResponse(yield medplum.startGoogleLogin({
591
+ googleClientId: response.clientId,
592
+ googleCredential: response.credential,
593
+ createUser: true,
594
+ }));
595
+ }
596
+ catch (err) {
597
+ setOutcome(err);
598
+ }
599
+ }) })),
600
+ React__default["default"].createElement("div", { className: "medplum-signin-separator" }, "or"))),
601
+ React__default["default"].createElement(FormSection, { title: "First Name", htmlFor: "firstName", outcome: outcome },
602
+ React__default["default"].createElement(Input, { name: "firstName", type: "text", testid: "firstName", placeholder: "First name", required: true, autoFocus: true, outcome: outcome })),
603
+ React__default["default"].createElement(FormSection, { title: "Last Name", htmlFor: "lastName", outcome: outcome },
604
+ React__default["default"].createElement(Input, { name: "lastName", type: "text", testid: "lastName", placeholder: "Last name", required: true, outcome: outcome })),
605
+ React__default["default"].createElement(FormSection, { title: "Email", htmlFor: "email", outcome: outcome },
606
+ React__default["default"].createElement(Input, { name: "email", type: "email", testid: "email", placeholder: "name@domain.com", required: true, outcome: outcome })),
607
+ React__default["default"].createElement(FormSection, { title: "Password", htmlFor: "password", outcome: outcome },
608
+ React__default["default"].createElement(Input, { name: "password", type: "password", testid: "password", autoComplete: "off", required: true, outcome: outcome })),
609
+ React__default["default"].createElement("p", { style: { fontSize: '12px', color: '#888' } },
610
+ "By clicking submit you agree to the Medplum ",
611
+ React__default["default"].createElement("a", { href: "https://www.medplum.com/privacy" }, "Privacy\u00A0Policy"),
612
+ ' and ',
613
+ React__default["default"].createElement("a", { href: "https://www.medplum.com/terms" }, "Terms\u00A0of\u00A0Service"),
614
+ "."),
615
+ React__default["default"].createElement("p", { style: { fontSize: '12px', color: '#888' } },
616
+ "This site is protected by reCAPTCHA and the Google",
617
+ ' ',
618
+ React__default["default"].createElement("a", { href: "https://policies.google.com/privacy" }, "Privacy\u00A0Policy"),
619
+ ' and ',
620
+ React__default["default"].createElement("a", { href: "https://policies.google.com/terms" }, "Terms\u00A0of\u00A0Service"),
621
+ " apply."),
622
+ React__default["default"].createElement("div", { className: "medplum-signin-buttons" },
623
+ React__default["default"].createElement("div", null,
624
+ React__default["default"].createElement("input", { type: "checkbox", id: "remember", name: "remember", value: "true" }),
625
+ React__default["default"].createElement("label", { htmlFor: "remember" }, "Remember me")),
626
+ React__default["default"].createElement("div", null,
627
+ React__default["default"].createElement(Button, { type: "submit", testid: "submit" }, "Create account")))));
628
+ }
629
+
630
+ function RegisterForm(props) {
631
+ const { type, projectId, googleClientId, recaptchaSiteKey, onSuccess } = props;
632
+ const medplum = useMedplum();
633
+ const [login, setLogin] = React.useState(undefined);
634
+ const [outcome, setOutcome] = React.useState();
635
+ React.useEffect(() => {
636
+ if (type === 'patient' && login) {
637
+ medplum
638
+ .startNewPatient({ login, projectId: projectId })
639
+ .then((response) => medplum.processCode(response.code))
640
+ .then(() => onSuccess())
641
+ .catch((err) => setOutcome(err));
642
+ }
643
+ }, [medplum, type, projectId, login, onSuccess]);
644
+ function handleAuthResponse(response) {
645
+ if (response.code) {
646
+ medplum
647
+ .processCode(response.code)
648
+ .then(() => onSuccess())
649
+ .catch(console.log);
650
+ }
651
+ else if (response.login) {
652
+ setLogin(response.login);
653
+ }
654
+ }
655
+ return (React__default["default"].createElement(Document, { width: 450 },
656
+ outcome && React__default["default"].createElement("pre", null, JSON.stringify(outcome, null, 2)),
657
+ !login && (React__default["default"].createElement(NewUserForm, { projectId: projectId, googleClientId: googleClientId, recaptchaSiteKey: recaptchaSiteKey, handleAuthResponse: handleAuthResponse })),
658
+ login && type === 'project' && React__default["default"].createElement(NewProjectForm, { login: login, handleAuthResponse: handleAuthResponse })));
659
+ }
660
+
661
+ function MedplumLink(props) {
662
+ const navigate = reactRouterDom.useNavigate();
663
+ let href = getHref(props.to);
664
+ if (props.suffix) {
665
+ href += '/' + props.suffix;
666
+ }
667
+ return (React__default["default"].createElement("a", { href: href, id: props.id, "aria-label": props.label, "data-testid": props.testid || 'link', className: props.className, onClick: (e) => {
668
+ killEvent(e);
669
+ if (props.onClick) {
670
+ props.onClick();
671
+ }
672
+ else if (props.to) {
673
+ navigate(href);
674
+ }
675
+ } }, props.children));
676
+ }
677
+ function getHref(to) {
678
+ if (to) {
679
+ if (typeof to === 'string') {
680
+ return getStringHref(to);
681
+ }
682
+ else if ('resourceType' in to) {
683
+ return getResourceHref(to);
684
+ }
685
+ else if ('reference' in to) {
686
+ return getReferenceHref(to);
687
+ }
688
+ }
689
+ return '#';
690
+ }
691
+ function getStringHref(to) {
692
+ if (to.startsWith('http://') || to.startsWith('https://') || to.startsWith('/')) {
693
+ return to;
694
+ }
695
+ return '/' + to;
696
+ }
697
+ function getResourceHref(to) {
698
+ return `/${to.resourceType}/${to.id}`;
699
+ }
700
+ function getReferenceHref(to) {
701
+ return `/${to.reference}`;
702
+ }
703
+
704
+ function AuthenticationForm(props) {
705
+ const medplum = useMedplum();
706
+ const googleClientId = getGoogleClientId(props.googleClientId);
707
+ const [outcome, setOutcome] = React.useState();
708
+ const issues = getIssuesForExpression(outcome, undefined);
709
+ return (React__default["default"].createElement(Form, { style: { maxWidth: 400 }, onSubmit: (formData) => {
710
+ medplum
711
+ .startLogin({
712
+ projectId: props.projectId,
713
+ clientId: props.clientId,
714
+ scope: props.scope,
715
+ nonce: props.nonce,
716
+ email: formData.email,
717
+ password: formData.password,
718
+ remember: formData.remember === 'true',
719
+ })
720
+ .then(props.handleAuthResponse)
721
+ .catch(setOutcome);
722
+ } },
723
+ React__default["default"].createElement("div", { className: "medplum-center" }, props.children),
724
+ issues && (React__default["default"].createElement("div", { className: "medplum-input-error" }, issues.map((issue) => {
725
+ var _a, _b;
726
+ return (React__default["default"].createElement("div", { "data-testid": "text-field-error", key: (_a = issue.details) === null || _a === void 0 ? void 0 : _a.text }, (_b = issue.details) === null || _b === void 0 ? void 0 : _b.text));
727
+ }))),
728
+ googleClientId && (React__default["default"].createElement(React__default["default"].Fragment, null,
729
+ React__default["default"].createElement("div", { className: "medplum-signin-google-container" },
730
+ React__default["default"].createElement(GoogleButton, { googleClientId: googleClientId, handleGoogleCredential: (response) => {
731
+ medplum
732
+ .startGoogleLogin({
733
+ projectId: props.projectId,
734
+ clientId: props.clientId,
735
+ scope: props.scope,
736
+ nonce: props.nonce,
737
+ googleClientId: response.clientId,
738
+ googleCredential: response.credential,
739
+ })
740
+ .then(props.handleAuthResponse)
741
+ .catch(setOutcome);
742
+ } })),
743
+ React__default["default"].createElement("div", { className: "medplum-signin-separator" }, "or"))),
744
+ React__default["default"].createElement(FormSection, { title: "Email", htmlFor: "email", outcome: outcome },
745
+ React__default["default"].createElement(Input, { name: "email", type: "email", testid: "email", required: true, autoFocus: true, outcome: outcome })),
746
+ React__default["default"].createElement(FormSection, { title: "Password", htmlFor: "password", outcome: outcome },
747
+ React__default["default"].createElement(Input, { name: "password", type: "password", testid: "password", autoComplete: "off", required: true, outcome: outcome })),
748
+ React__default["default"].createElement("div", { className: "medplum-signin-buttons" },
749
+ (props.onForgotPassword || props.onRegister) && (React__default["default"].createElement("div", null,
750
+ props.onForgotPassword && (React__default["default"].createElement(MedplumLink, { testid: "forgotpassword", onClick: props.onForgotPassword }, "Forgot password")),
751
+ props.onRegister && (React__default["default"].createElement(MedplumLink, { testid: "register", onClick: props.onRegister }, "Register")))),
752
+ React__default["default"].createElement("div", null,
753
+ React__default["default"].createElement("input", { type: "checkbox", id: "remember", name: "remember", value: "true" }),
754
+ React__default["default"].createElement("label", { htmlFor: "remember" }, "Remember me")),
755
+ React__default["default"].createElement("div", null,
756
+ React__default["default"].createElement(Button, { type: "submit", testid: "submit" }, "Sign in")))));
757
+ }
758
+
759
+ const system = {
760
+ resourceType: 'Device',
761
+ id: 'system',
762
+ deviceName: [
763
+ {
764
+ name: 'System',
765
+ },
766
+ ],
767
+ };
768
+ /**
769
+ * React Hook to use a FHIR reference.
770
+ * Handles the complexity of resolving references and caching resources.
771
+ * @param value The resource or reference to resource.
772
+ * @returns The resolved resource.
773
+ */
774
+ function useResource(value) {
775
+ const medplum = useMedplum();
776
+ const [resource, setResource] = React.useState(getInitialResource(medplum, value));
777
+ React.useEffect(() => {
778
+ let subscribed = true;
779
+ if (!resource && value && 'reference' in value && value.reference) {
780
+ medplum
781
+ .readReference(value)
782
+ .then((r) => {
783
+ if (subscribed) {
784
+ setResource(r);
785
+ }
786
+ })
787
+ .catch(() => setResource(undefined));
788
+ }
789
+ return (() => (subscribed = false));
790
+ }, [medplum, resource, value]);
791
+ return resource;
792
+ }
793
+ /**
794
+ * Returns the initial resource value based on the input value.
795
+ * If the input value is a resource, returns the resource.
796
+ * If the input value is a reference to system, returns the system resource.
797
+ * If the input value is a reference to a resource available in the cache, returns the resource.
798
+ * Otherwise, returns undefined.
799
+ * @param medplum The medplum client.
800
+ * @param value The resource or reference to resource.
801
+ * @returns An initial resource if available; undefined otherwise.
802
+ */
803
+ function getInitialResource(medplum, value) {
804
+ if (!value) {
805
+ return undefined;
806
+ }
807
+ if ('resourceType' in value) {
808
+ return value;
809
+ }
810
+ if ('reference' in value) {
811
+ if (value.reference === 'system') {
812
+ return system;
813
+ }
814
+ return medplum.getCachedReference(value);
815
+ }
816
+ return undefined;
817
+ }
818
+
819
+ function Avatar(props) {
820
+ var _a, _b;
821
+ const resource = useResource(props.value);
822
+ const className = props.size ? 'medplum-avatar ' + props.size : 'medplum-avatar';
823
+ const text = resource ? core.getDisplayString(resource) : (_a = props.alt) !== null && _a !== void 0 ? _a : '';
824
+ const initials = text && getInitials(text);
825
+ const imageUrl = (_b = (resource && core.getImageSrc(resource))) !== null && _b !== void 0 ? _b : props.src;
826
+ const innerContent = imageUrl ? React__default["default"].createElement("img", { src: imageUrl, alt: text }) : initials;
827
+ return (React__default["default"].createElement("div", { className: className, style: { backgroundColor: props.color }, "data-testid": "avatar" }, props.link && resource ? React__default["default"].createElement(MedplumLink, { to: resource }, innerContent) : innerContent));
828
+ }
829
+ function getInitials(text) {
830
+ return text
831
+ .split(' ')
832
+ .map((n) => n[0])
833
+ .join('');
834
+ }
835
+
836
+ function ChooseProfileForm(props) {
837
+ const medplum = useMedplum();
838
+ return (React__default["default"].createElement("div", null,
839
+ React__default["default"].createElement("div", { className: "medplum-center" },
840
+ React__default["default"].createElement(Logo, { size: 32 }),
841
+ React__default["default"].createElement("h1", null, "Choose profile")),
842
+ props.memberships.map((membership) => {
843
+ var _a, _b, _c;
844
+ return (React__default["default"].createElement("div", { className: "medplum-nav-menu-profile", key: membership.id, onClick: () => {
845
+ medplum
846
+ .post('auth/profile', {
847
+ login: props.login,
848
+ profile: membership.id,
849
+ })
850
+ .then(props.handleAuthResponse)
851
+ .catch(console.log);
852
+ } },
853
+ React__default["default"].createElement("div", { className: "medplum-nav-menu-profile-icon" },
854
+ React__default["default"].createElement(Avatar, { alt: (_a = membership.profile) === null || _a === void 0 ? void 0 : _a.display })),
855
+ React__default["default"].createElement("div", { className: "medplum-nav-menu-profile-label" }, (_b = membership.profile) === null || _b === void 0 ? void 0 :
856
+ _b.display,
857
+ React__default["default"].createElement("div", { className: "medplum-nav-menu-profile-help-text" }, (_c = membership.project) === null || _c === void 0 ? void 0 : _c.display))));
858
+ })));
859
+ }
860
+
861
+ function SignInForm(props) {
862
+ const medplum = useMedplum();
863
+ const [login, setLogin] = React.useState(undefined);
864
+ const [memberships, setMemberships] = React.useState(undefined);
865
+ function handleAuthResponse(response) {
866
+ if (response.login) {
867
+ setLogin(response.login);
868
+ }
869
+ if (response.memberships) {
870
+ setMemberships(response.memberships);
871
+ }
872
+ if (response.code) {
873
+ if (props.onCode) {
874
+ props.onCode(response.code);
875
+ }
876
+ else {
877
+ medplum
878
+ .processCode(response.code)
879
+ .then(() => {
880
+ if (props.onSuccess) {
881
+ props.onSuccess();
882
+ }
883
+ })
884
+ .catch(console.log);
885
+ }
886
+ }
887
+ }
888
+ return (React__default["default"].createElement(Document, { width: 450 }, (() => {
889
+ if (!login) {
890
+ 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));
891
+ }
892
+ else if (memberships) {
893
+ return React__default["default"].createElement(ChooseProfileForm, { login: login, memberships: memberships, handleAuthResponse: handleAuthResponse });
894
+ }
895
+ else if (props.projectId === 'new') {
896
+ return React__default["default"].createElement(NewProjectForm, { login: login, handleAuthResponse: handleAuthResponse });
897
+ }
898
+ else {
899
+ return React__default["default"].createElement("div", null, "Success");
900
+ }
901
+ })()));
902
+ }
903
+
332
904
  function Autocomplete(props) {
333
905
  var _a, _b;
334
906
  const inputRef = React.useRef(null);
@@ -392,6 +964,7 @@
392
964
  }
393
965
  }
394
966
  function handleBlur() {
967
+ tryAddOption();
395
968
  setFocused(false);
396
969
  dismissOnDelay();
397
970
  }
@@ -604,111 +1177,6 @@
604
1177
  React__default["default"].createElement("div", { className: "medplum-autocomplete-label" }, "Create new...")))))));
605
1178
  }
606
1179
 
607
- function MedplumLink(props) {
608
- const navigate = reactRouterDom.useNavigate();
609
- let href = '#';
610
- if (props.to) {
611
- if (typeof props.to === 'string') {
612
- href = props.to;
613
- }
614
- else if ('resourceType' in props.to) {
615
- href = `/${props.to.resourceType}/${props.to.id}`;
616
- }
617
- else if ('reference' in props.to) {
618
- href = `/${props.to.reference}`;
619
- }
620
- if (props.suffix) {
621
- href += '/' + props.suffix;
622
- }
623
- }
624
- return (React__default["default"].createElement("a", { href: href, id: props.id, "aria-label": props.label, "data-testid": props.testid || 'link', className: props.className, onClick: (e) => {
625
- killEvent(e);
626
- if (props.onClick) {
627
- props.onClick();
628
- }
629
- else if (props.to) {
630
- navigate(href);
631
- }
632
- } }, props.children));
633
- }
634
-
635
- const system = {
636
- resourceType: 'Device',
637
- id: 'system',
638
- deviceName: [
639
- {
640
- name: 'System',
641
- },
642
- ],
643
- };
644
- /**
645
- * React Hook to use a FHIR reference.
646
- * Handles the complexity of resolving references and caching resources.
647
- * @param value The resource or reference to resource.
648
- * @returns The resolved resource.
649
- */
650
- function useResource(value) {
651
- const medplum = useMedplum();
652
- const [resource, setResource] = React.useState(getInitialResource(medplum, value));
653
- React.useEffect(() => {
654
- let subscribed = true;
655
- if (!resource && value && 'reference' in value && value.reference) {
656
- medplum
657
- .readReference(value)
658
- .then((r) => {
659
- if (subscribed) {
660
- setResource(r);
661
- }
662
- })
663
- .catch(() => setResource(undefined));
664
- }
665
- return (() => (subscribed = false));
666
- }, [medplum, resource, value]);
667
- return resource;
668
- }
669
- /**
670
- * Returns the initial resource value based on the input value.
671
- * If the input value is a resource, returns the resource.
672
- * If the input value is a reference to system, returns the system resource.
673
- * If the input value is a reference to a resource available in the cache, returns the resource.
674
- * Otherwise, returns undefined.
675
- * @param medplum The medplum client.
676
- * @param value The resource or reference to resource.
677
- * @returns An initial resource if available; undefined otherwise.
678
- */
679
- function getInitialResource(medplum, value) {
680
- if (!value) {
681
- return undefined;
682
- }
683
- if ('resourceType' in value) {
684
- return value;
685
- }
686
- if ('reference' in value) {
687
- if (value.reference === 'system') {
688
- return system;
689
- }
690
- return medplum.getCachedReference(value);
691
- }
692
- return undefined;
693
- }
694
-
695
- function Avatar(props) {
696
- var _a, _b;
697
- const resource = useResource(props.value);
698
- const className = props.size ? 'medplum-avatar ' + props.size : 'medplum-avatar';
699
- const text = resource ? core.getDisplayString(resource) : (_a = props.alt) !== null && _a !== void 0 ? _a : '';
700
- const initials = text && getInitials(text);
701
- const imageUrl = (_b = (resource && core.getImageSrc(resource))) !== null && _b !== void 0 ? _b : props.src;
702
- const innerContent = imageUrl ? React__default["default"].createElement("img", { src: imageUrl, alt: text }) : initials;
703
- return (React__default["default"].createElement("div", { className: className, style: { backgroundColor: props.color }, "data-testid": "avatar" }, props.link && resource ? React__default["default"].createElement(MedplumLink, { to: resource }, innerContent) : innerContent));
704
- }
705
- function getInitials(text) {
706
- return text
707
- .split(' ')
708
- .map((n) => n[0])
709
- .join('');
710
- }
711
-
712
1180
  function CheckboxFormSection(props) {
713
1181
  return (React__default["default"].createElement("div", { className: "medplum-checkbox-form-section" },
714
1182
  React__default["default"].createElement("div", { className: "medplum-checkbox-form-section-checkbox-container" }, props.children),
@@ -727,19 +1195,6 @@
727
1195
  'modifierExtension',
728
1196
  ];
729
1197
 
730
- function FormSection(props) {
731
- const issues = getIssuesForExpression(props.outcome, props.htmlFor);
732
- const invalid = issues && issues.length > 0;
733
- return (React__default["default"].createElement("fieldset", { className: "medplum-form-section" },
734
- props.title && React__default["default"].createElement("label", { htmlFor: props.htmlFor }, props.title),
735
- props.description && React__default["default"].createElement("p", null, props.description),
736
- props.children,
737
- invalid && (React__default["default"].createElement("div", { id: props.htmlFor + '-errors', className: "medplum-input-error" }, issues === null || issues === void 0 ? void 0 : issues.map((issue) => {
738
- var _a, _b;
739
- return (React__default["default"].createElement("div", { "data-testid": "text-field-error", key: (_a = issue.details) === null || _a === void 0 ? void 0 : _a.text }, (_b = issue.details) === null || _b === void 0 ? void 0 : _b.text));
740
- })))));
741
- }
742
-
743
1198
  function ResourceForm(props) {
744
1199
  const medplum = useMedplum();
745
1200
  const defaultValue = useResource(props.defaultValue);
@@ -748,7 +1203,7 @@
748
1203
  React.useEffect(() => {
749
1204
  if (defaultValue) {
750
1205
  setValue(JSON.parse(JSON.stringify(defaultValue)));
751
- medplum.requestSchema(defaultValue.resourceType).then(setSchema);
1206
+ medplum.requestSchema(defaultValue.resourceType).then(setSchema).catch(console.log);
752
1207
  }
753
1208
  }, [medplum, defaultValue]);
754
1209
  if (!schema || !value) {
@@ -1106,7 +1561,7 @@
1106
1561
  return medplum.searchValueSet(system, input).then((valueSet) => {
1107
1562
  return valueSet.expansion.contains.map(valueSetElementToCodeableConcept);
1108
1563
  });
1109
- }, buildUnstructured: buildUnstructured, getId: getId, getDisplay: getDisplay, name: props.name, defaultValue: defaultValue, onChange: (values) => {
1564
+ }, buildUnstructured: buildUnstructured, getId: getId, getDisplay: getDisplay, name: props.name, defaultValue: defaultValue, loadOnFocus: true, onChange: (values) => {
1110
1565
  if (props.onChange) {
1111
1566
  props.onChange(values[0]);
1112
1567
  }
@@ -1154,7 +1609,7 @@
1154
1609
  contains.forEach((e) => (cachedDisplayValues[e.code] = e.display));
1155
1610
  return contains.map((e) => e.code);
1156
1611
  });
1157
- }, 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) => {
1612
+ }, 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) => {
1158
1613
  if (props.onChange) {
1159
1614
  props.onChange(values[0]);
1160
1615
  }
@@ -1177,7 +1632,7 @@
1177
1632
  display: e.display,
1178
1633
  }));
1179
1634
  });
1180
- }, buildUnstructured: (str) => ({ code: str }), getId: (item) => item.code, getDisplay: (item) => React__default["default"].createElement(CodingDisplay, { value: item }), name: props.name, defaultValue: defaultValue, onChange: (values) => {
1635
+ }, 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) => {
1181
1636
  if (props.onChange) {
1182
1637
  props.onChange(values[0]);
1183
1638
  }
@@ -1472,31 +1927,6 @@
1472
1927
  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 })) })));
1473
1928
  }
1474
1929
 
1475
- /******************************************************************************
1476
- Copyright (c) Microsoft Corporation.
1477
-
1478
- Permission to use, copy, modify, and/or distribute this software for any
1479
- purpose with or without fee is hereby granted.
1480
-
1481
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
1482
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
1483
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
1484
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
1485
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
1486
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
1487
- PERFORMANCE OF THIS SOFTWARE.
1488
- ***************************************************************************** */
1489
-
1490
- function __awaiter(thisArg, _arguments, P, generator) {
1491
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
1492
- return new (P || (P = Promise))(function (resolve, reject) {
1493
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
1494
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
1495
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
1496
- step((generator = generator.apply(thisArg, _arguments || [])).next());
1497
- });
1498
- }
1499
-
1500
1930
  function ResourceName(props) {
1501
1931
  const resource = useResource(props.value);
1502
1932
  if (!resource) {
@@ -1978,67 +2408,10 @@
1978
2408
  }
1979
2409
  function ReferenceRangeDisplay(props) {
1980
2410
  const range = props.value && props.value.length > 0 && props.value[0];
1981
- if (!range) {
1982
- return null;
1983
- }
1984
- return React__default["default"].createElement(RangeDisplay, { value: range });
1985
- }
1986
-
1987
- /**
1988
- * Parses an HTML form and returns the result as a JavaScript object.
1989
- * @param form The HTML form element.
1990
- */
1991
- function parseForm(form) {
1992
- const result = {};
1993
- for (const element of Array.from(form.elements)) {
1994
- if (element instanceof HTMLInputElement) {
1995
- parseInputElement(result, element);
1996
- }
1997
- else if (element instanceof HTMLTextAreaElement) {
1998
- result[element.name] = element.value;
1999
- }
2000
- else if (element instanceof HTMLSelectElement) {
2001
- parseSelectElement(result, element);
2002
- }
2003
- }
2004
- return result;
2005
- }
2006
- /**
2007
- * Parses an HTML input element.
2008
- * Sets the name/value pair in the result,
2009
- * but only if the element is enabled and checked.
2010
- * @param el The input element.
2011
- * @param result The result builder.
2012
- */
2013
- function parseInputElement(result, el) {
2014
- if (el.disabled) {
2015
- // Ignore disabled elements
2016
- return;
2017
- }
2018
- if ((el.type === 'checkbox' || el.type === 'radio') && !el.checked) {
2019
- // Ignore unchecked radio or checkbox elements
2020
- return;
2021
- }
2022
- result[el.name] = el.value;
2023
- }
2024
- /**
2025
- * Parses an HTML select element.
2026
- * Sets the name/value pair if one is selected.
2027
- * @param result The result builder.
2028
- * @param el The select element.
2029
- */
2030
- function parseSelectElement(result, el) {
2031
- result[el.name] = el.value;
2032
- }
2033
-
2034
- function Form(props) {
2035
- return (React__default["default"].createElement("form", { style: props.style, "data-testid": props.testid, onSubmit: (e) => {
2036
- e.preventDefault();
2037
- const formData = parseForm(e.target);
2038
- if (props.onSubmit) {
2039
- props.onSubmit(formData);
2040
- }
2041
- } }, props.children));
2411
+ if (!range) {
2412
+ return null;
2413
+ }
2414
+ return React__default["default"].createElement(RangeDisplay, { value: range });
2042
2415
  }
2043
2416
 
2044
2417
  function Loading() {
@@ -2056,7 +2429,7 @@
2056
2429
  const medplum = useMedplum();
2057
2430
  const [schema, setSchema] = React.useState();
2058
2431
  React.useEffect(() => {
2059
- medplum.requestSchema(props.original.resourceType).then(setSchema);
2432
+ medplum.requestSchema(props.original.resourceType).then(setSchema).catch(console.log);
2060
2433
  }, [medplum, props.original.resourceType]);
2061
2434
  if (!schema) {
2062
2435
  return null;
@@ -2109,7 +2482,7 @@
2109
2482
  const [schema, setSchema] = React.useState();
2110
2483
  React.useEffect(() => {
2111
2484
  if (value) {
2112
- medplum.requestSchema(value.resourceType).then(setSchema);
2485
+ medplum.requestSchema(value.resourceType).then(setSchema).catch(console.log);
2113
2486
  }
2114
2487
  }, [medplum, value]);
2115
2488
  if (!schema || !value) {
@@ -2307,7 +2680,7 @@
2307
2680
  setHistory({});
2308
2681
  return;
2309
2682
  }
2310
- medplum.executeBatch(buildSearchRequests(resource)).then(handleBatchResponse);
2683
+ medplum.executeBatch(buildSearchRequests(resource)).then(handleBatchResponse).catch(console.log);
2311
2684
  }, [medplum, resource, buildSearchRequests]);
2312
2685
  React.useEffect(() => {
2313
2686
  loadTimeline();
@@ -2330,7 +2703,9 @@
2330
2703
  }
2331
2704
  if (bundle.entry) {
2332
2705
  for (const entry of bundle.entry) {
2333
- newItems.push(entry.resource);
2706
+ if (entry.resource) {
2707
+ newItems.push(entry.resource);
2708
+ }
2334
2709
  }
2335
2710
  }
2336
2711
  }
@@ -2358,9 +2733,12 @@
2358
2733
  // Encounter not loaded yet
2359
2734
  return;
2360
2735
  }
2361
- medplum.createResource(props.createCommunication(resource, sender, contentString)).then((result) => {
2736
+ medplum
2737
+ .createResource(props.createCommunication(resource, sender, contentString))
2738
+ .then((result) => {
2362
2739
  addResources([result]);
2363
- });
2740
+ })
2741
+ .catch(console.log);
2364
2742
  }
2365
2743
  /**
2366
2744
  * Adds a Media resource to the timeline.
@@ -2371,18 +2749,21 @@
2371
2749
  // Encounter not loaded yet
2372
2750
  return;
2373
2751
  }
2374
- medplum.createResource(props.createMedia(resource, sender, attachment)).then((result) => {
2752
+ medplum
2753
+ .createResource(props.createMedia(resource, sender, attachment))
2754
+ .then((result) => {
2375
2755
  addResources([result]);
2376
- });
2756
+ })
2757
+ .catch(console.log);
2377
2758
  }
2378
2759
  function setPriority(communication, priority) {
2379
2760
  return medplum.updateResource(Object.assign(Object.assign({}, communication), { priority }));
2380
2761
  }
2381
2762
  function onPin(communication) {
2382
- setPriority(communication, 'stat').then(loadTimeline);
2763
+ setPriority(communication, 'stat').then(loadTimeline).catch(console.log);
2383
2764
  }
2384
2765
  function onUnpin(communication) {
2385
- setPriority(communication, 'routine').then(loadTimeline);
2766
+ setPriority(communication, 'routine').then(loadTimeline).catch(console.log);
2386
2767
  }
2387
2768
  function onDetails(timelineItem) {
2388
2769
  navigate(`/${timelineItem.resourceType}/${timelineItem.id}`);
@@ -2511,11 +2892,6 @@
2511
2892
  }) }));
2512
2893
  }
2513
2894
 
2514
- function Document(props) {
2515
- return (React__default["default"].createElement("main", { className: "medplum-document" },
2516
- React__default["default"].createElement("article", { style: { maxWidth: props.width } }, props.children)));
2517
- }
2518
-
2519
2895
  function EncounterTimeline(props) {
2520
2896
  return (React__default["default"].createElement(ResourceTimeline, { value: props.encounter, buildSearchRequests: (resource) => ({
2521
2897
  resourceType: 'Bundle',
@@ -3807,11 +4183,14 @@
3807
4183
  }
3808
4184
  }
3809
4185
  React.useEffect(() => {
3810
- medplum.requestSchema(props.search.resourceType).then((newSchema) => {
4186
+ medplum
4187
+ .requestSchema(props.search.resourceType)
4188
+ .then((newSchema) => {
3811
4189
  // The schema could have the same object identity,
3812
4190
  // so need to use the spread operator to kick React re-render.
3813
4191
  setSchema(Object.assign({}, newSchema));
3814
- });
4192
+ })
4193
+ .catch(console.log);
3815
4194
  }, [medplum, props.search.resourceType]);
3816
4195
  const typeSchema = (_a = schema === null || schema === void 0 ? void 0 : schema.types) === null || _a === void 0 ? void 0 : _a[props.search.resourceType];
3817
4196
  if (!typeSchema) {
@@ -3995,11 +4374,14 @@
3995
4374
  }
3996
4375
  }
3997
4376
  React.useEffect(() => {
3998
- medplum.requestSchema(props.resourceType).then((newSchema) => {
4377
+ medplum
4378
+ .requestSchema(props.resourceType)
4379
+ .then((newSchema) => {
3999
4380
  // The schema could have the same object identity,
4000
4381
  // so need to use the spread operator to kick React re-render.
4001
4382
  setSchema(Object.assign({}, newSchema));
4002
- });
4383
+ })
4384
+ .catch(console.log);
4003
4385
  }, [medplum, props.resourceType]);
4004
4386
  const typeSchema = (_a = schema === null || schema === void 0 ? void 0 : schema.types) === null || _a === void 0 ? void 0 : _a[props.resourceType];
4005
4387
  if (!typeSchema) {
@@ -4241,9 +4623,13 @@
4241
4623
  logins.map((login) => {
4242
4624
  var _a, _b, _c, _d;
4243
4625
  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: () => {
4244
- medplum.setActiveLogin(login);
4245
- setUserMenuVisible(false);
4246
- window.location.reload();
4626
+ medplum
4627
+ .setActiveLogin(login)
4628
+ .then(() => {
4629
+ setUserMenuVisible(false);
4630
+ window.location.reload();
4631
+ })
4632
+ .catch(console.log);
4247
4633
  } },
4248
4634
  React__default["default"].createElement("div", { className: "medplum-nav-menu-profile-icon" },
4249
4635
  React__default["default"].createElement(Avatar, null)),
@@ -4284,16 +4670,6 @@
4284
4670
  React__default["default"].createElement(MedplumLink, { to: "/changepassword" }, "Change password"))))));
4285
4671
  }
4286
4672
 
4287
- function Logo(props) {
4288
- return (React__default["default"].createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 491 491", style: { width: props.size, height: props.size } },
4289
- React__default["default"].createElement("title", null, "Medplum Logo"),
4290
- React__default["default"].createElement("path", { fill: props.fill || '#ad7136', d: "M282 67c6-16 16-29 29-40L289 0c-22 17-37 41-43 68l17 23 19-24z" }),
4291
- React__default["default"].createElement("path", { fill: props.fill || '#654b87', d: "M311 63c-17 0-33 4-48 11-16-7-32-11-49-11-87 0-158 96-158 214s71 214 158 214c17 0 33-4 49-11 15 7 31 11 48 11 87 0 158-96 158-214S398 63 311 63z" }),
4292
- React__default["default"].createElement("path", { fill: props.fill || '#463068', d: "M231 489l-17 2c-87 0-158-96-158-214S127 63 214 63l17 1c-39 12-70 102-70 213s31 201 70 212z" }),
4293
- React__default["default"].createElement("path", { fill: props.fill || '#70d65b', d: "M207 220a176 176 0 01-177 43A176 176 0 01251 43l1 5c17 59 2 125-45 172z" }),
4294
- React__default["default"].createElement("path", { fill: props.fill || '#58b741', d: "M252 48A421 421 0 0057 270l-27-7A176 176 0 01251 43l1 5z" })));
4295
- }
4296
-
4297
4673
  const searches = [
4298
4674
  '$/_history',
4299
4675
  'Communication?subject=$',
@@ -4344,7 +4720,7 @@
4344
4720
  const valueRef = React.useRef();
4345
4721
  valueRef.current = value;
4346
4722
  React.useEffect(() => {
4347
- medplum.requestSchema('PlanDefinition').then(setSchema);
4723
+ medplum.requestSchema('PlanDefinition').then(setSchema).catch(console.log);
4348
4724
  }, [medplum]);
4349
4725
  React.useEffect(() => {
4350
4726
  setValue(ensurePlanDefinitionKeys(defaultValue !== null && defaultValue !== void 0 ? defaultValue : { resourceType: 'PlanDefinition' }));
@@ -4640,7 +5016,7 @@
4640
5016
  const questionnaire = useResource(props.questionnaire);
4641
5017
  const [response, setResponse] = React.useState();
4642
5018
  React.useEffect(() => {
4643
- medplum.requestSchema('Questionnaire').then(setSchema);
5019
+ medplum.requestSchema('Questionnaire').then(setSchema).catch(console.log);
4644
5020
  }, [medplum]);
4645
5021
  React.useEffect(() => {
4646
5022
  setResponse(questionnaire ? buildInitialResponse(questionnaire) : undefined);
@@ -4683,6 +5059,7 @@
4683
5059
  return (React__default["default"].createElement(CheckboxFormSection, { key: item.linkId, title: item.text, htmlFor: item.linkId },
4684
5060
  React__default["default"].createElement(Checkbox, { name: item.linkId, defaultValue: initial === null || initial === void 0 ? void 0 : initial.valueBoolean, onChange: (newValue) => setResponseItem(index, {
4685
5061
  linkId: item.linkId,
5062
+ text: item.text,
4686
5063
  answer: [{ valueBoolean: newValue }],
4687
5064
  }) })));
4688
5065
  }
@@ -4845,7 +5222,7 @@
4845
5222
  setSelectedKey(undefined);
4846
5223
  }
4847
5224
  React.useEffect(() => {
4848
- medplum.requestSchema('Questionnaire').then(setSchema);
5225
+ medplum.requestSchema('Questionnaire').then(setSchema).catch(console.log);
4849
5226
  }, [medplum]);
4850
5227
  React.useEffect(() => {
4851
5228
  setValue(ensureQuestionnaireKeys(defaultValue !== null && defaultValue !== void 0 ? defaultValue : { resourceType: 'Questionnaire' }));
@@ -5031,190 +5408,6 @@
5031
5408
  return options.map((option) => (Object.assign(Object.assign({}, option), { id: option.id || generateId() })));
5032
5409
  }
5033
5410
 
5034
- /**
5035
- * Dynamically creates a script tag for the specified JavaScript file.
5036
- * @param src The JavaScript file URL.
5037
- */
5038
- function createScriptTag(src, onload) {
5039
- const head = document.getElementsByTagName('head')[0];
5040
- const script = document.createElement('script');
5041
- script.async = true;
5042
- script.src = src;
5043
- script.onload = onload || null;
5044
- head.appendChild(script);
5045
- }
5046
-
5047
- function GoogleButton(props) {
5048
- const medplum = useMedplum();
5049
- const { googleClientId, handleGoogleCredential } = props;
5050
- const parentRef = React.useRef(null);
5051
- const [scriptLoaded, setScriptLoaded] = React.useState(typeof google !== 'undefined');
5052
- const [initialized, setInitialized] = React.useState(false);
5053
- const [buttonRendered, setButtonRendered] = React.useState(false);
5054
- React.useEffect(() => {
5055
- if (typeof google === 'undefined') {
5056
- createScriptTag('https://accounts.google.com/gsi/client', () => setScriptLoaded(true));
5057
- return;
5058
- }
5059
- if (!initialized) {
5060
- google.accounts.id.initialize({
5061
- client_id: googleClientId,
5062
- callback: handleGoogleCredential,
5063
- });
5064
- setInitialized(true);
5065
- }
5066
- if (parentRef.current && !buttonRendered) {
5067
- google.accounts.id.renderButton(parentRef.current, {});
5068
- setButtonRendered(true);
5069
- }
5070
- }, [medplum, googleClientId, initialized, scriptLoaded, parentRef, buttonRendered, handleGoogleCredential]);
5071
- if (!googleClientId) {
5072
- return null;
5073
- }
5074
- return React__default["default"].createElement("div", { ref: parentRef });
5075
- }
5076
- function getGoogleClientId(clientId) {
5077
- var _a, _b;
5078
- if (clientId) {
5079
- return clientId;
5080
- }
5081
- const origin = window.location.protocol + '//' + window.location.host;
5082
- const authorizedOrigins = (_b = (_a = "http://localhost:3000,http://localhost:6006,https://app.medplum.com,https://docs.medplum.com") === null || _a === void 0 ? void 0 : _a.split(',')) !== null && _b !== void 0 ? _b : [];
5083
- if (authorizedOrigins.includes(origin)) {
5084
- return "921088377005-3j1sa10vr6hj86jgmdfh2l53v3mp7lfi.apps.googleusercontent.com";
5085
- }
5086
- return undefined;
5087
- }
5088
-
5089
- /**
5090
- * Dynamically loads the recaptcha script.
5091
- * We do not want to load the script on page load unless the user needs it.
5092
- * @param siteKey The reCAPTCHA site key, available from the reCAPTCHA admin page.
5093
- */
5094
- function initRecaptcha(siteKey) {
5095
- if (typeof grecaptcha === 'undefined') {
5096
- createScriptTag('https://www.google.com/recaptcha/api.js?render=' + siteKey);
5097
- }
5098
- }
5099
- /**
5100
- * Starts a request to generate a recapcha token.
5101
- * @param siteKey The reCAPTCHA site key, available from the reCAPTCHA admin page.
5102
- * @returns Promise to a recaptcha token for the current user.
5103
- */
5104
- function getRecaptcha(siteKey) {
5105
- return new Promise((resolve) => {
5106
- grecaptcha.ready(() => {
5107
- grecaptcha.execute(siteKey, { action: 'submit' }).then(resolve);
5108
- });
5109
- });
5110
- }
5111
-
5112
- function RegisterForm(props) {
5113
- const medplum = useMedplum();
5114
- const googleClientId = getGoogleClientId(props.googleClientId);
5115
- const recaptchaSiteKey = props.recaptchaSiteKey;
5116
- const [outcome, setOutcome] = React.useState();
5117
- const issues = getIssuesForExpression(outcome, undefined);
5118
- React.useEffect(() => initRecaptcha(recaptchaSiteKey), [recaptchaSiteKey]);
5119
- function handleAuthResponse(registerRequest, partialLogin) {
5120
- return __awaiter(this, void 0, void 0, function* () {
5121
- try {
5122
- let login;
5123
- if (props.type === 'patient') {
5124
- login = yield medplum.startNewPatient(registerRequest, partialLogin);
5125
- }
5126
- else {
5127
- login = yield medplum.startNewProject(registerRequest, partialLogin);
5128
- }
5129
- yield medplum.processCode(login.code);
5130
- props.onSuccess();
5131
- }
5132
- catch (err) {
5133
- setOutcome(err);
5134
- }
5135
- });
5136
- }
5137
- return (React__default["default"].createElement(Document, { width: 450 },
5138
- React__default["default"].createElement(Form, { style: { maxWidth: 400 }, onSubmit: (formData) => __awaiter(this, void 0, void 0, function* () {
5139
- try {
5140
- const recaptchaToken = yield getRecaptcha(recaptchaSiteKey);
5141
- const registerRequest = {
5142
- projectId: props.projectId,
5143
- projectName: formData.projectName,
5144
- firstName: formData.firstName,
5145
- lastName: formData.lastName,
5146
- email: formData.email,
5147
- password: formData.password,
5148
- remember: formData.remember === 'true',
5149
- recaptchaSiteKey,
5150
- recaptchaToken,
5151
- };
5152
- const userLogin = yield medplum.startNewUser(registerRequest);
5153
- handleAuthResponse(registerRequest, userLogin);
5154
- }
5155
- catch (err) {
5156
- setOutcome(err);
5157
- }
5158
- }) },
5159
- React__default["default"].createElement("div", { className: "medplum-center" }, props.children),
5160
- issues && (React__default["default"].createElement("div", { className: "medplum-input-error" }, issues.map((issue) => {
5161
- var _a, _b;
5162
- return (React__default["default"].createElement("div", { "data-testid": "text-field-error", key: (_a = issue.details) === null || _a === void 0 ? void 0 : _a.text }, (_b = issue.details) === null || _b === void 0 ? void 0 : _b.text));
5163
- }))),
5164
- googleClientId && (React__default["default"].createElement(React__default["default"].Fragment, null,
5165
- React__default["default"].createElement("div", { className: "medplum-signin-google-container" },
5166
- React__default["default"].createElement(GoogleButton, { googleClientId: googleClientId, handleGoogleCredential: (response) => __awaiter(this, void 0, void 0, function* () {
5167
- try {
5168
- const loginRequest = {
5169
- googleClientId: response.clientId,
5170
- googleCredential: response.credential,
5171
- };
5172
- const userLogin = yield medplum.startGoogleLogin(loginRequest);
5173
- const googleClaims = core.parseJWTPayload(loginRequest.googleCredential);
5174
- const registerRequest = {
5175
- projectId: props.projectId,
5176
- firstName: googleClaims.given_name,
5177
- lastName: googleClaims.family_name,
5178
- email: googleClaims.email,
5179
- };
5180
- handleAuthResponse(registerRequest, userLogin);
5181
- }
5182
- catch (err) {
5183
- setOutcome(err);
5184
- }
5185
- }) })),
5186
- React__default["default"].createElement("div", { className: "medplum-signin-separator" }, "or"))),
5187
- React__default["default"].createElement(FormSection, { title: "First Name", htmlFor: "firstName", outcome: outcome },
5188
- React__default["default"].createElement(Input, { name: "firstName", type: "text", testid: "firstName", placeholder: "First name", required: true, autoFocus: true, outcome: outcome })),
5189
- React__default["default"].createElement(FormSection, { title: "Last Name", htmlFor: "lastName", outcome: outcome },
5190
- React__default["default"].createElement(Input, { name: "lastName", type: "text", testid: "lastName", placeholder: "Last name", required: true, outcome: outcome })),
5191
- props.type === 'project' && (React__default["default"].createElement(FormSection, { title: "Project Name", htmlFor: "projectName", outcome: outcome },
5192
- React__default["default"].createElement(Input, { name: "projectName", type: "text", testid: "projectName", placeholder: "My Project", required: true, outcome: outcome }))),
5193
- React__default["default"].createElement(FormSection, { title: "Email", htmlFor: "email", outcome: outcome },
5194
- React__default["default"].createElement(Input, { name: "email", type: "email", testid: "email", placeholder: "name@domain.com", required: true, outcome: outcome })),
5195
- React__default["default"].createElement(FormSection, { title: "Password", htmlFor: "password", outcome: outcome },
5196
- React__default["default"].createElement(Input, { name: "password", type: "password", testid: "password", autoComplete: "off", required: true, outcome: outcome })),
5197
- React__default["default"].createElement("p", { style: { fontSize: '12px', color: '#888' } },
5198
- "By clicking submit you agree to the Medplum ",
5199
- React__default["default"].createElement("a", { href: "https://www.medplum.com/privacy" }, "Privacy\u00A0Policy"),
5200
- ' and ',
5201
- React__default["default"].createElement("a", { href: "https://www.medplum.com/terms" }, "Terms\u00A0of\u00A0Service"),
5202
- "."),
5203
- React__default["default"].createElement("p", { style: { fontSize: '12px', color: '#888' } },
5204
- "This site is protected by reCAPTCHA and the Google",
5205
- ' ',
5206
- React__default["default"].createElement("a", { href: "https://policies.google.com/privacy" }, "Privacy\u00A0Policy"),
5207
- ' and ',
5208
- React__default["default"].createElement("a", { href: "https://policies.google.com/terms" }, "Terms\u00A0of\u00A0Service"),
5209
- " apply."),
5210
- React__default["default"].createElement("div", { className: "medplum-signin-buttons" },
5211
- React__default["default"].createElement("div", null,
5212
- React__default["default"].createElement("input", { type: "checkbox", id: "remember", name: "remember", value: "true" }),
5213
- React__default["default"].createElement("label", { htmlFor: "remember" }, "Remember me")),
5214
- React__default["default"].createElement("div", null,
5215
- React__default["default"].createElement(Button, { type: "submit", testid: "submit" }, "Create account"))))));
5216
- }
5217
-
5218
5411
  function StatusBadge(props) {
5219
5412
  return React__default["default"].createElement("span", { className: `medplum-status medplum-status-${props.status}` }, props.status);
5220
5413
  }
@@ -5227,7 +5420,7 @@
5227
5420
  const [responseBundle, setResponseBundle] = React.useState();
5228
5421
  React.useEffect(() => {
5229
5422
  if (requestGroup && !startedLoading) {
5230
- medplum.executeBatch(buildBatchRequest(requestGroup)).then(setResponseBundle);
5423
+ medplum.executeBatch(buildBatchRequest(requestGroup)).then(setResponseBundle).catch(console.log);
5231
5424
  setStartedLoading(true);
5232
5425
  }
5233
5426
  }, [medplum, requestGroup, startedLoading]);
@@ -5472,7 +5665,7 @@
5472
5665
  const [value, setValue] = React.useState(props.history);
5473
5666
  React.useEffect(() => {
5474
5667
  if (!props.history && props.resourceType && props.id) {
5475
- medplum.readHistory(props.resourceType, props.id).then((result) => setValue(result));
5668
+ medplum.readHistory(props.resourceType, props.id).then(setValue).catch(console.log);
5476
5669
  }
5477
5670
  }, [medplum, props.history, props.resourceType, props.id]);
5478
5671
  if (!value) {
@@ -5550,7 +5743,10 @@
5550
5743
  const [value, setValue] = React.useState(props.history);
5551
5744
  React.useEffect(() => {
5552
5745
  if (!props.history && props.resourceType && props.id) {
5553
- medplum.readHistory(props.resourceType, props.id).then((result) => setValue(result));
5746
+ medplum
5747
+ .readHistory(props.resourceType, props.id)
5748
+ .then(setValue)
5749
+ .catch(console.log);
5554
5750
  }
5555
5751
  }, [medplum, props.history, props.resourceType, props.id]);
5556
5752
  if (!value) {
@@ -5562,19 +5758,23 @@
5562
5758
  React__default["default"].createElement("th", null, "Author"),
5563
5759
  React__default["default"].createElement("th", null, "Date"),
5564
5760
  React__default["default"].createElement("th", null, "Version"))),
5565
- React__default["default"].createElement("tbody", null, (_a = value.entry) === null || _a === void 0 ? void 0 : _a.map((entry) => {
5566
- var _a, _b;
5567
- return (React__default["default"].createElement(HistoryRow, { key: (_b = (_a = entry.resource) === null || _a === void 0 ? void 0 : _a.meta) === null || _b === void 0 ? void 0 : _b.versionId, version: entry.resource }));
5568
- }))));
5761
+ React__default["default"].createElement("tbody", null, (_a = value.entry) === null || _a === void 0 ? void 0 : _a.map((entry, index) => (React__default["default"].createElement(HistoryRow, { key: 'entry-' + index, entry: entry }))))));
5569
5762
  }
5570
5763
  function HistoryRow(props) {
5571
5764
  var _a, _b, _c;
5572
- return (React__default["default"].createElement("tr", null,
5573
- React__default["default"].createElement("td", null,
5574
- React__default["default"].createElement(ResourceBadge, { value: (_a = props.version.meta) === null || _a === void 0 ? void 0 : _a.author, link: true })),
5575
- React__default["default"].createElement("td", null, core.formatDateTime((_b = props.version.meta) === null || _b === void 0 ? void 0 : _b.lastUpdated)),
5576
- React__default["default"].createElement("td", null,
5577
- React__default["default"].createElement(MedplumLink, { to: getVersionUrl(props.version) }, (_c = props.version.meta) === null || _c === void 0 ? void 0 : _c.versionId))));
5765
+ const { response, resource } = props.entry;
5766
+ if (resource) {
5767
+ return (React__default["default"].createElement("tr", null,
5768
+ React__default["default"].createElement("td", null,
5769
+ React__default["default"].createElement(ResourceBadge, { value: (_a = resource.meta) === null || _a === void 0 ? void 0 : _a.author, link: true })),
5770
+ React__default["default"].createElement("td", null, core.formatDateTime((_b = resource.meta) === null || _b === void 0 ? void 0 : _b.lastUpdated)),
5771
+ React__default["default"].createElement("td", null,
5772
+ React__default["default"].createElement(MedplumLink, { to: getVersionUrl(resource) }, (_c = resource.meta) === null || _c === void 0 ? void 0 : _c.versionId))));
5773
+ }
5774
+ else {
5775
+ return (React__default["default"].createElement("tr", null,
5776
+ React__default["default"].createElement("td", { colSpan: 3 }, core.normalizeErrorString(response === null || response === void 0 ? void 0 : response.outcome))));
5777
+ }
5578
5778
  }
5579
5779
  function getVersionUrl(resource) {
5580
5780
  var _a;
@@ -5590,12 +5790,14 @@
5590
5790
  return date.toLocaleString('default', { month: 'long' }) + ' ' + date.getFullYear();
5591
5791
  }
5592
5792
  function CalendarInput(props) {
5793
+ const { onChangeMonth, onClick } = props;
5593
5794
  const [month, setMonth] = React.useState(getStartMonth);
5594
5795
  function moveMonth(delta) {
5595
5796
  setMonth((currMonth) => {
5596
- const prevMonth = new Date(currMonth.getTime());
5597
- prevMonth.setMonth(currMonth.getMonth() + delta);
5598
- return prevMonth;
5797
+ const newMonth = new Date(currMonth.getTime());
5798
+ newMonth.setMonth(currMonth.getMonth() + delta);
5799
+ onChangeMonth(newMonth);
5800
+ return newMonth;
5599
5801
  });
5600
5802
  }
5601
5803
  const grid = React.useMemo(() => buildGrid(month, props.slots), [month, props.slots]);
@@ -5615,7 +5817,7 @@
5615
5817
  React__default["default"].createElement("th", null, "THU"),
5616
5818
  React__default["default"].createElement("th", null, "FRI"),
5617
5819
  React__default["default"].createElement("th", null, "SAT"))),
5618
- 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()))))))))))));
5820
+ 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()))))))))))));
5619
5821
  }
5620
5822
  function getStartMonth() {
5621
5823
  const result = new Date();
@@ -5634,7 +5836,6 @@
5634
5836
  while (d.getMonth() === startDate.getMonth()) {
5635
5837
  row.push({
5636
5838
  date: new Date(d.getTime()),
5637
- // available: isAvailable(d),
5638
5839
  available: isDayAvailable(d, slots),
5639
5840
  });
5640
5841
  if (d.getDay() === 6) {
@@ -5678,20 +5879,27 @@
5678
5879
  const [slots, setSlots] = React.useState();
5679
5880
  const slotsRef = React.useRef();
5680
5881
  slotsRef.current = slots;
5882
+ const [month, setMonth] = React.useState(getStartMonth());
5681
5883
  const [date, setDate] = React.useState();
5682
5884
  const [slot, setSlot] = React.useState();
5683
5885
  const [info, setInfo] = React.useState();
5684
5886
  const [form, setForm] = React.useState();
5685
5887
  React.useEffect(() => {
5686
5888
  if (schedule) {
5687
- medplum.search('Slot', 'schedule=' + core.getReferenceString(schedule)).then((bundle) => {
5688
- setSlots(bundle.entry.map((entry) => entry.resource));
5689
- });
5889
+ setSlots([]);
5890
+ medplum
5891
+ .searchResources('Slot', new URLSearchParams([
5892
+ ['schedule', core.getReferenceString(schedule)],
5893
+ ['start', 'gt' + month.toISOString()],
5894
+ ['start', 'lt' + new Date(month.getTime() + 31 * 24 * 60 * 60 * 1000).toISOString()],
5895
+ ]))
5896
+ .then(setSlots)
5897
+ .catch(console.log);
5690
5898
  }
5691
5899
  else {
5692
5900
  setSlots(undefined);
5693
5901
  }
5694
- }, [medplum, schedule]);
5902
+ }, [medplum, schedule, month]);
5695
5903
  if (!schedule || !slots) {
5696
5904
  return null;
5697
5905
  }
@@ -5707,7 +5915,7 @@
5707
5915
  React__default["default"].createElement("div", { className: "medplum-calendar-selection-pane" },
5708
5916
  !date && (React__default["default"].createElement("div", null,
5709
5917
  React__default["default"].createElement("h3", null, "Select date"),
5710
- React__default["default"].createElement(CalendarInput, { slots: slots, onClick: setDate }))),
5918
+ React__default["default"].createElement(CalendarInput, { slots: slots, onChangeMonth: setMonth, onClick: setDate }))),
5711
5919
  date && !slot && (React__default["default"].createElement("div", null,
5712
5920
  React__default["default"].createElement("h3", null, "Select time"),
5713
5921
  slots.map((s) => {
@@ -5787,121 +5995,6 @@
5787
5995
  }) }));
5788
5996
  }
5789
5997
 
5790
- function SignInForm(props) {
5791
- const medplum = useMedplum();
5792
- const [login, setLogin] = React.useState(undefined);
5793
- const [memberships, setMemberships] = React.useState(undefined);
5794
- function handleAuthResponse(response) {
5795
- if (response.login) {
5796
- setLogin(response.login);
5797
- }
5798
- if (response.memberships) {
5799
- setMemberships(response.memberships);
5800
- }
5801
- if (response.code) {
5802
- if (props.onCode) {
5803
- props.onCode(response.code);
5804
- }
5805
- else {
5806
- medplum
5807
- .processCode(response.code)
5808
- .then(() => {
5809
- if (props.onSuccess) {
5810
- props.onSuccess();
5811
- }
5812
- })
5813
- .catch(console.log);
5814
- }
5815
- }
5816
- }
5817
- return (React__default["default"].createElement(Document, { width: 450 }, (() => {
5818
- if (!login) {
5819
- 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));
5820
- }
5821
- else if (memberships) {
5822
- return React__default["default"].createElement(ProfileForm, { login: login, memberships: memberships, handleAuthResponse: handleAuthResponse });
5823
- }
5824
- else {
5825
- return React__default["default"].createElement("div", null, "Success");
5826
- }
5827
- })()));
5828
- }
5829
- function AuthenticationForm(props) {
5830
- const medplum = useMedplum();
5831
- const googleClientId = getGoogleClientId(props.googleClientId);
5832
- const [outcome, setOutcome] = React.useState();
5833
- const issues = getIssuesForExpression(outcome, undefined);
5834
- return (React__default["default"].createElement(Form, { style: { maxWidth: 400 }, onSubmit: (formData) => {
5835
- medplum
5836
- .startLogin({
5837
- clientId: props.clientId,
5838
- scope: props.scope,
5839
- nonce: props.nonce,
5840
- email: formData.email,
5841
- password: formData.password,
5842
- remember: formData.remember === 'true',
5843
- })
5844
- .then(props.handleAuthResponse)
5845
- .catch(setOutcome);
5846
- } },
5847
- React__default["default"].createElement("div", { className: "medplum-center" }, props.children),
5848
- issues && (React__default["default"].createElement("div", { className: "medplum-input-error" }, issues.map((issue) => {
5849
- var _a, _b;
5850
- return (React__default["default"].createElement("div", { "data-testid": "text-field-error", key: (_a = issue.details) === null || _a === void 0 ? void 0 : _a.text }, (_b = issue.details) === null || _b === void 0 ? void 0 : _b.text));
5851
- }))),
5852
- googleClientId && (React__default["default"].createElement(React__default["default"].Fragment, null,
5853
- React__default["default"].createElement("div", { className: "medplum-signin-google-container" },
5854
- React__default["default"].createElement(GoogleButton, { googleClientId: googleClientId, handleGoogleCredential: (response) => {
5855
- medplum
5856
- .startGoogleLogin({
5857
- clientId: props.clientId,
5858
- scope: props.scope,
5859
- nonce: props.nonce,
5860
- googleClientId: response.clientId,
5861
- googleCredential: response.credential,
5862
- })
5863
- .then(props.handleAuthResponse)
5864
- .catch(setOutcome);
5865
- } })),
5866
- React__default["default"].createElement("div", { className: "medplum-signin-separator" }, "or"))),
5867
- React__default["default"].createElement(FormSection, { title: "Email", htmlFor: "email", outcome: outcome },
5868
- React__default["default"].createElement(Input, { name: "email", type: "email", testid: "email", required: true, autoFocus: true, outcome: outcome })),
5869
- React__default["default"].createElement(FormSection, { title: "Password", htmlFor: "password", outcome: outcome },
5870
- React__default["default"].createElement(Input, { name: "password", type: "password", testid: "password", autoComplete: "off", required: true, outcome: outcome })),
5871
- React__default["default"].createElement("div", { className: "medplum-signin-buttons" },
5872
- (props.onForgotPassword || props.onRegister) && (React__default["default"].createElement("div", null,
5873
- props.onForgotPassword && (React__default["default"].createElement(MedplumLink, { testid: "forgotpassword", onClick: props.onForgotPassword }, "Forgot password")),
5874
- props.onRegister && (React__default["default"].createElement(MedplumLink, { testid: "register", onClick: props.onRegister }, "Register")))),
5875
- React__default["default"].createElement("div", null,
5876
- React__default["default"].createElement("input", { type: "checkbox", id: "remember", name: "remember", value: "true" }),
5877
- React__default["default"].createElement("label", { htmlFor: "remember" }, "Remember me")),
5878
- React__default["default"].createElement("div", null,
5879
- React__default["default"].createElement(Button, { type: "submit", testid: "submit" }, "Sign in")))));
5880
- }
5881
- function ProfileForm(props) {
5882
- const medplum = useMedplum();
5883
- return (React__default["default"].createElement("div", null,
5884
- React__default["default"].createElement("div", { className: "medplum-center" },
5885
- React__default["default"].createElement(Logo, { size: 32 }),
5886
- React__default["default"].createElement("h1", null, "Choose profile")),
5887
- props.memberships.map((membership) => {
5888
- var _a, _b, _c;
5889
- return (React__default["default"].createElement("div", { className: "medplum-nav-menu-profile", key: membership.id, onClick: () => {
5890
- medplum
5891
- .post('auth/profile', {
5892
- login: props.login,
5893
- profile: membership.id,
5894
- })
5895
- .then(props.handleAuthResponse);
5896
- } },
5897
- React__default["default"].createElement("div", { className: "medplum-nav-menu-profile-icon" },
5898
- React__default["default"].createElement(Avatar, { alt: (_a = membership.profile) === null || _a === void 0 ? void 0 : _a.display })),
5899
- React__default["default"].createElement("div", { className: "medplum-nav-menu-profile-label" }, (_b = membership.profile) === null || _b === void 0 ? void 0 :
5900
- _b.display,
5901
- React__default["default"].createElement("div", { className: "medplum-nav-menu-profile-help-text" }, (_c = membership.project) === null || _c === void 0 ? void 0 : _c.display))));
5902
- })));
5903
- }
5904
-
5905
5998
  function Tab(props) {
5906
5999
  let className = 'medplum-tab';
5907
6000
  if (props.selected) {
@@ -5968,6 +6061,8 @@
5968
6061
  exports.ContactPointInput = ContactPointInput;
5969
6062
  exports.DateTimeInput = DateTimeInput;
5970
6063
  exports.DefaultResourceTimeline = DefaultResourceTimeline;
6064
+ exports.DescriptionList = DescriptionList;
6065
+ exports.DescriptionListEntry = DescriptionListEntry;
5971
6066
  exports.DiagnosticReportDisplay = DiagnosticReportDisplay;
5972
6067
  exports.Document = Document;
5973
6068
  exports.ElementDefinitionInputSelector = ElementDefinitionInputSelector;