@medplum/react 0.9.19 → 0.9.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cjs/index.js CHANGED
@@ -25,7 +25,7 @@
25
25
  const className = 'medplum-input';
26
26
  const issues = getIssuesForExpression(props.outcome, props.name);
27
27
  const invalid = issues && issues.length > 0;
28
- return (React__default["default"].createElement("input", { id: props.name, name: props.name, type: getInputType(props.type), size: props.size, step: props.step, className: className, defaultValue: props.defaultValue || '', required: props.required, autoCapitalize: props.autoCapitalize, autoComplete: props.autoComplete, autoFocus: props.autoFocus, ref: props.inputRef, "aria-invalid": invalid, "aria-describedby": invalid ? props.name + '-errors' : '', placeholder: props.placeholder, "data-testid": props.testid, disabled: props.disabled, onChange: (e) => {
28
+ return (React__default["default"].createElement("input", { id: props.name, name: props.name, type: getInputType(props.type), size: props.size, step: props.step, className: className, style: props.style, defaultValue: props.defaultValue || '', required: props.required, autoCapitalize: props.autoCapitalize, autoComplete: props.autoComplete, autoFocus: props.autoFocus, ref: props.inputRef, "aria-invalid": invalid, "aria-describedby": invalid ? props.name + '-errors' : '', placeholder: props.placeholder, "data-testid": props.testid, disabled: props.disabled, onChange: (e) => {
29
29
  if (props.onChange) {
30
30
  props.onChange(e.currentTarget.value);
31
31
  }
@@ -876,6 +876,18 @@
876
876
  return React__default["default"].createElement(React__default["default"].Fragment, null, builder.join('').trim());
877
877
  }
878
878
 
879
+ function ContactDetailDisplay(props) {
880
+ var _a;
881
+ const contactDetail = props.value;
882
+ if (!contactDetail) {
883
+ return null;
884
+ }
885
+ return (React__default["default"].createElement(React__default["default"].Fragment, null,
886
+ contactDetail.name,
887
+ contactDetail.name && ': ', (_a = contactDetail.telecom) === null || _a === void 0 ? void 0 :
888
+ _a.map((telecom, index) => (React__default["default"].createElement(ContactPointDisplay, { key: 'telecom-' + index, value: telecom })))));
889
+ }
890
+
879
891
  function DateTimeDisplay(props) {
880
892
  if (!props.value) {
881
893
  return null;
@@ -1024,6 +1036,8 @@
1024
1036
  return React__default["default"].createElement(CodeableConceptDisplay, { value: value });
1025
1037
  case core.PropertyType.Coding:
1026
1038
  return React__default["default"].createElement(CodingDisplay, { value: value });
1039
+ case core.PropertyType.ContactDetail:
1040
+ return React__default["default"].createElement(ContactDetailDisplay, { value: value });
1027
1041
  case core.PropertyType.ContactPoint:
1028
1042
  return React__default["default"].createElement(ContactPointDisplay, { value: value });
1029
1043
  case core.PropertyType.HumanName:
@@ -1193,19 +1207,34 @@
1193
1207
  const ref = React.useRef();
1194
1208
  ref.current = contactPoint;
1195
1209
  function setContactPointWrapper(newValue) {
1210
+ if (newValue && Object.keys(newValue).length === 0) {
1211
+ newValue = undefined;
1212
+ }
1196
1213
  setContactPoint(newValue);
1197
1214
  if (props.onChange) {
1198
1215
  props.onChange(newValue);
1199
1216
  }
1200
1217
  }
1201
1218
  function setSystem(system) {
1202
- setContactPointWrapper(Object.assign(Object.assign({}, ref.current), { system: system ? system : undefined }));
1219
+ const newValue = Object.assign(Object.assign({}, ref.current), { system });
1220
+ if (!system) {
1221
+ delete newValue.system;
1222
+ }
1223
+ setContactPointWrapper(newValue);
1203
1224
  }
1204
1225
  function setUse(use) {
1205
- setContactPointWrapper(Object.assign(Object.assign({}, ref.current), { use: use ? use : undefined }));
1226
+ const newValue = Object.assign(Object.assign({}, ref.current), { use });
1227
+ if (!use) {
1228
+ delete newValue.use;
1229
+ }
1230
+ setContactPointWrapper(newValue);
1206
1231
  }
1207
1232
  function setValue(value) {
1208
- setContactPointWrapper(Object.assign(Object.assign({}, ref.current), { value: value ? value : undefined }));
1233
+ const newValue = Object.assign(Object.assign({}, ref.current), { value });
1234
+ if (!value) {
1235
+ delete newValue.value;
1236
+ }
1237
+ setContactPointWrapper(newValue);
1209
1238
  }
1210
1239
  return (React__default["default"].createElement(InputRow, null,
1211
1240
  React__default["default"].createElement(Select, { defaultValue: contactPoint === null || contactPoint === void 0 ? void 0 : contactPoint.system, onChange: setSystem, testid: "system" },
@@ -1226,6 +1255,36 @@
1226
1255
  React__default["default"].createElement(Input, { placeholder: "Value", defaultValue: contactPoint === null || contactPoint === void 0 ? void 0 : contactPoint.value, onChange: setValue })));
1227
1256
  }
1228
1257
 
1258
+ function ContactDetailInput(props) {
1259
+ var _a;
1260
+ const [contactPoint, setContactDetail] = React.useState(props.defaultValue);
1261
+ const ref = React.useRef();
1262
+ ref.current = contactPoint;
1263
+ function setContactDetailWrapper(newValue) {
1264
+ setContactDetail(newValue);
1265
+ if (props.onChange) {
1266
+ props.onChange(newValue);
1267
+ }
1268
+ }
1269
+ function setName(name) {
1270
+ const newValue = Object.assign(Object.assign({}, ref.current), { name });
1271
+ if (!name) {
1272
+ delete newValue.name;
1273
+ }
1274
+ setContactDetailWrapper(newValue);
1275
+ }
1276
+ function setTelecom(telecom) {
1277
+ const newValue = Object.assign(Object.assign({}, ref.current), { telecom: telecom && [telecom] });
1278
+ if (!telecom) {
1279
+ delete newValue.telecom;
1280
+ }
1281
+ setContactDetailWrapper(newValue);
1282
+ }
1283
+ return (React__default["default"].createElement(InputRow, null,
1284
+ React__default["default"].createElement(Input, { name: props.name + '-name', placeholder: "Name", style: { width: 180 }, defaultValue: contactPoint === null || contactPoint === void 0 ? void 0 : contactPoint.name, onChange: setName }),
1285
+ React__default["default"].createElement(ContactPointInput, { name: props.name + '-telecom', defaultValue: (_a = contactPoint === null || contactPoint === void 0 ? void 0 : contactPoint.telecom) === null || _a === void 0 ? void 0 : _a[0], onChange: setTelecom })));
1286
+ }
1287
+
1229
1288
  /**
1230
1289
  * The DateTimeInput component is a wrapper around the HTML5 input type="datetime-local".
1231
1290
  * The main purpose is to reconcile time zones.
@@ -1640,6 +1699,8 @@
1640
1699
  return React__default["default"].createElement(CodeableConceptInput, { property: property, name: name, defaultValue: value, onChange: props.onChange });
1641
1700
  case core.PropertyType.Coding:
1642
1701
  return React__default["default"].createElement(CodingInput, { property: property, name: name, defaultValue: value, onChange: props.onChange });
1702
+ case core.PropertyType.ContactDetail:
1703
+ return React__default["default"].createElement(ContactDetailInput, { name: name, defaultValue: value, onChange: props.onChange });
1643
1704
  case core.PropertyType.ContactPoint:
1644
1705
  return React__default["default"].createElement(ContactPointInput, { name: name, defaultValue: value, onChange: props.onChange });
1645
1706
  case core.PropertyType.Extension:
@@ -2123,8 +2184,7 @@
2123
2184
  setHistory({});
2124
2185
  return;
2125
2186
  }
2126
- const batchRequest = buildSearchRequests(resource);
2127
- medplum.post('fhir/R4', batchRequest).then(handleBatchResponse);
2187
+ medplum.executeBatch(buildSearchRequests(resource)).then(handleBatchResponse);
2128
2188
  }, [medplum, resource, buildSearchRequests]);
2129
2189
  React.useEffect(() => {
2130
2190
  loadTimeline();
@@ -4552,31 +4612,64 @@
4552
4612
  return (React__default["default"].createElement(TextArea, { name: name, defaultValue: initial === null || initial === void 0 ? void 0 : initial.valueString, onChange: (newValue) => onChangeAnswer({ valueString: newValue }) }));
4553
4613
  case exports.QuestionnaireItemType.url:
4554
4614
  return (React__default["default"].createElement(Input, { type: "url", name: name, defaultValue: initial === null || initial === void 0 ? void 0 : initial.valueUri, onChange: (newValue) => onChangeAnswer({ valueUri: newValue }) }));
4555
- case exports.QuestionnaireItemType.choice:
4556
- case exports.QuestionnaireItemType.openChoice:
4557
- return (React__default["default"].createElement("div", null, item.answerOption &&
4558
- item.answerOption.map((option, index) => {
4559
- const valueElementDefinition = core.globalSchema.types['QuestionnaireItemAnswerOption'].properties['value[x]'];
4560
- const optionValue = core.getTypedPropertyValue({ type: 'QuestionnaireItemAnswerOption', value: option }, 'value');
4561
- const initialValue = core.getTypedPropertyValue({ type: 'QuestionnaireItemInitial', value: initial }, 'value');
4562
- const propertyName = 'value' + core.capitalize(optionValue.type);
4563
- const optionName = `${name}-option-${index}`;
4564
- return (React__default["default"].createElement("div", { key: optionName, className: "medplum-questionnaire-option-row" },
4565
- React__default["default"].createElement("div", { className: "medplum-questionnaire-option-checkbox" },
4566
- React__default["default"].createElement("input", { type: "radio", id: optionName, name: name, value: optionValue.value, defaultChecked: initialValue && core.stringify(optionValue) === core.stringify(initialValue), onChange: () => onChangeAnswer({ [propertyName]: optionValue.value }) })),
4567
- React__default["default"].createElement("div", null,
4568
- React__default["default"].createElement("label", { htmlFor: optionName },
4569
- React__default["default"].createElement(ResourcePropertyDisplay, { property: valueElementDefinition, propertyType: optionValue.type, value: optionValue.value })))));
4570
- })));
4571
4615
  case exports.QuestionnaireItemType.attachment:
4572
4616
  return (React__default["default"].createElement(AttachmentInput, { name: name, defaultValue: initial === null || initial === void 0 ? void 0 : initial.valueAttachment, onChange: (newValue) => onChangeAnswer({ valueAttachment: newValue }) }));
4573
4617
  case exports.QuestionnaireItemType.reference:
4574
4618
  return (React__default["default"].createElement(ReferenceInput, { name: name, defaultValue: initial === null || initial === void 0 ? void 0 : initial.valueReference, onChange: (newValue) => onChangeAnswer({ valueReference: newValue }) }));
4575
4619
  case exports.QuestionnaireItemType.quantity:
4576
4620
  return (React__default["default"].createElement(QuantityInput, { name: name, defaultValue: initial === null || initial === void 0 ? void 0 : initial.valueQuantity, onChange: (newValue) => onChangeAnswer({ valueQuantity: newValue }) }));
4621
+ case exports.QuestionnaireItemType.choice:
4622
+ case exports.QuestionnaireItemType.openChoice:
4623
+ if (isDropDownChoice(item)) {
4624
+ return (React__default["default"].createElement(QuestionnaireChoiceDropDownInput, { name: name, item: item, initial: initial, onChangeAnswer: onChangeAnswer }));
4625
+ }
4626
+ else {
4627
+ return (React__default["default"].createElement(QuestionnaireChoiceRadioInput, { name: name, item: item, initial: initial, onChangeAnswer: onChangeAnswer }));
4628
+ }
4577
4629
  }
4578
4630
  return null;
4579
4631
  }
4632
+ function QuestionnaireChoiceDropDownInput(props) {
4633
+ const { name, item, initial } = props;
4634
+ const valueElementDefinition = core.globalSchema.types['QuestionnaireItemAnswerOption'].properties['value[x]'];
4635
+ const initialValue = core.getTypedPropertyValue({ type: 'QuestionnaireItemInitial', value: initial }, 'value');
4636
+ return (React__default["default"].createElement("select", { id: name, name: name, className: "medplum-select", onChange: (e) => {
4637
+ const index = e.currentTarget.selectedIndex;
4638
+ if (index === 0) {
4639
+ props.onChangeAnswer({});
4640
+ return;
4641
+ }
4642
+ const option = item.answerOption[index - 1];
4643
+ const optionValue = core.getTypedPropertyValue({ type: 'QuestionnaireItemAnswerOption', value: option }, 'value');
4644
+ const propertyName = 'value' + core.capitalize(optionValue.type);
4645
+ props.onChangeAnswer({ [propertyName]: optionValue.value });
4646
+ } },
4647
+ React__default["default"].createElement("option", null),
4648
+ item.answerOption &&
4649
+ item.answerOption.map((option, index) => {
4650
+ const optionValue = core.getTypedPropertyValue({ type: 'QuestionnaireItemAnswerOption', value: option }, 'value');
4651
+ const optionName = `${name}-option-${index}`;
4652
+ return (React__default["default"].createElement("option", { key: optionName, value: optionValue.value, selected: initialValue && core.stringify(optionValue) === core.stringify(initialValue) },
4653
+ React__default["default"].createElement(ResourcePropertyDisplay, { property: valueElementDefinition, propertyType: optionValue.type, value: optionValue.value })));
4654
+ })));
4655
+ }
4656
+ function QuestionnaireChoiceRadioInput(props) {
4657
+ const { name, item, initial, onChangeAnswer } = props;
4658
+ const valueElementDefinition = core.globalSchema.types['QuestionnaireItemAnswerOption'].properties['value[x]'];
4659
+ const initialValue = core.getTypedPropertyValue({ type: 'QuestionnaireItemInitial', value: initial }, 'value');
4660
+ return (React__default["default"].createElement(React__default["default"].Fragment, null, item.answerOption &&
4661
+ item.answerOption.map((option, index) => {
4662
+ const optionValue = core.getTypedPropertyValue({ type: 'QuestionnaireItemAnswerOption', value: option }, 'value');
4663
+ const propertyName = 'value' + core.capitalize(optionValue.type);
4664
+ const optionName = `${name}-option-${index}`;
4665
+ return (React__default["default"].createElement("div", { key: optionName, className: "medplum-questionnaire-option-row" },
4666
+ React__default["default"].createElement("div", { className: "medplum-questionnaire-option-checkbox" },
4667
+ React__default["default"].createElement("input", { type: "radio", id: optionName, name: name, value: optionValue.value, defaultChecked: initialValue && core.stringify(optionValue) === core.stringify(initialValue), onChange: () => onChangeAnswer({ [propertyName]: optionValue.value }) })),
4668
+ React__default["default"].createElement("div", null,
4669
+ React__default["default"].createElement("label", { htmlFor: optionName },
4670
+ React__default["default"].createElement(ResourcePropertyDisplay, { property: valueElementDefinition, propertyType: optionValue.type, value: optionValue.value })))));
4671
+ })));
4672
+ }
4580
4673
  function buildInitialResponse(questionnaire) {
4581
4674
  const response = {
4582
4675
  resourceType: 'QuestionnaireResponse',
@@ -4602,6 +4695,14 @@
4602
4695
  // have the same properties.
4603
4696
  return Object.assign({}, answer);
4604
4697
  }
4698
+ function isDropDownChoice(item) {
4699
+ var _a;
4700
+ return !!((_a = item.extension) === null || _a === void 0 ? void 0 : _a.some((e) => {
4701
+ var _a, _b, _c;
4702
+ return e.url === 'http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl' &&
4703
+ ((_c = (_b = (_a = e.valueCodeableConcept) === null || _a === void 0 ? void 0 : _a.coding) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.code) === 'drop-down';
4704
+ }));
4705
+ }
4605
4706
 
4606
4707
  function QuestionnaireBuilder(props) {
4607
4708
  const medplum = useMedplum();
@@ -4815,7 +4916,7 @@
4815
4916
  const [responseBundle, setResponseBundle] = React.useState();
4816
4917
  React.useEffect(() => {
4817
4918
  if (requestGroup && !startedLoading) {
4818
- medplum.post('fhir/R4', buildBatchRequest(requestGroup)).then(setResponseBundle);
4919
+ medplum.executeBatch(buildBatchRequest(requestGroup)).then(setResponseBundle);
4819
4920
  setStartedLoading(true);
4820
4921
  }
4821
4922
  }, [medplum, requestGroup, startedLoading]);
@@ -5170,6 +5271,165 @@
5170
5271
  return `/${resource.resourceType}/${resource.id}/_history/${(_a = resource.meta) === null || _a === void 0 ? void 0 : _a.versionId}`;
5171
5272
  }
5172
5273
 
5274
+ /**
5275
+ * Returns a month display string (e.g. "January 2020").
5276
+ * @param date Any date within the month.
5277
+ * @returns The month display string (e.g. "January 2020")
5278
+ */
5279
+ function getMonthString(date) {
5280
+ return date.toLocaleString('default', { month: 'long' }) + ' ' + date.getFullYear();
5281
+ }
5282
+ function CalendarInput(props) {
5283
+ const [month, setMonth] = React.useState(getStartMonth);
5284
+ function moveMonth(delta) {
5285
+ setMonth((currMonth) => {
5286
+ const prevMonth = new Date(currMonth.getTime());
5287
+ prevMonth.setMonth(currMonth.getMonth() + delta);
5288
+ return prevMonth;
5289
+ });
5290
+ }
5291
+ const grid = React.useMemo(() => buildGrid(month, props.slots), [month, props.slots]);
5292
+ return (React__default["default"].createElement("div", null,
5293
+ React__default["default"].createElement(InputRow, null,
5294
+ React__default["default"].createElement("p", { style: { flex: 1 } }, getMonthString(month)),
5295
+ React__default["default"].createElement("p", null,
5296
+ React__default["default"].createElement(Button, { label: "Previous month", onClick: () => moveMonth(-1) }, "<"),
5297
+ React__default["default"].createElement(Button, { label: "Next month", onClick: () => moveMonth(1) }, ">"))),
5298
+ React__default["default"].createElement("table", { className: "medplum-calendar-table" },
5299
+ React__default["default"].createElement("thead", null,
5300
+ React__default["default"].createElement("tr", null,
5301
+ React__default["default"].createElement("th", null, "SUN"),
5302
+ React__default["default"].createElement("th", null, "MON"),
5303
+ React__default["default"].createElement("th", null, "TUE"),
5304
+ React__default["default"].createElement("th", null, "WED"),
5305
+ React__default["default"].createElement("th", null, "THU"),
5306
+ React__default["default"].createElement("th", null, "FRI"),
5307
+ React__default["default"].createElement("th", null, "SAT"))),
5308
+ 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()))))))))))));
5309
+ }
5310
+ function getStartMonth() {
5311
+ const result = new Date();
5312
+ result.setDate(1);
5313
+ result.setHours(0, 0, 0, 0);
5314
+ return result;
5315
+ }
5316
+ function buildGrid(startDate, slots) {
5317
+ const d = new Date(startDate.getFullYear(), startDate.getMonth());
5318
+ const grid = [];
5319
+ let row = [];
5320
+ // Fill leading empty days
5321
+ for (let i = 0; i < d.getDay(); i++) {
5322
+ row.push(undefined);
5323
+ }
5324
+ while (d.getMonth() === startDate.getMonth()) {
5325
+ row.push({
5326
+ date: new Date(d.getTime()),
5327
+ // available: isAvailable(d),
5328
+ available: isDayAvailable(d, slots),
5329
+ });
5330
+ if (d.getDay() === 6) {
5331
+ grid.push(row);
5332
+ row = [];
5333
+ }
5334
+ d.setDate(d.getDate() + 1);
5335
+ }
5336
+ // Fill trailing empty days
5337
+ if (d.getDay() !== 0) {
5338
+ for (let i = d.getDay(); i < 7; i++) {
5339
+ row.push(undefined);
5340
+ }
5341
+ grid.push(row);
5342
+ }
5343
+ return grid;
5344
+ }
5345
+ /**
5346
+ * Returns true if the given date is available for booking.
5347
+ * @param day The day to check.
5348
+ * @param slots The list of available slots.
5349
+ * @returns True if there are any available slots for the day.
5350
+ */
5351
+ function isDayAvailable(day, slots) {
5352
+ // Note that slot start and end time may or may not be in UTC.
5353
+ for (const slot of slots) {
5354
+ const slotStart = new Date(slot.start);
5355
+ if (slotStart.getFullYear() === day.getFullYear() &&
5356
+ slotStart.getMonth() === day.getMonth() &&
5357
+ slotStart.getDate() === day.getDate()) {
5358
+ return true;
5359
+ }
5360
+ }
5361
+ return false;
5362
+ }
5363
+
5364
+ function Scheduler(props) {
5365
+ var _a;
5366
+ const medplum = useMedplum();
5367
+ const schedule = useResource(props.schedule);
5368
+ const [slots, setSlots] = React.useState();
5369
+ const slotsRef = React.useRef();
5370
+ slotsRef.current = slots;
5371
+ const [date, setDate] = React.useState();
5372
+ const [slot, setSlot] = React.useState();
5373
+ const [info, setInfo] = React.useState();
5374
+ const [form, setForm] = React.useState();
5375
+ React.useEffect(() => {
5376
+ if (schedule) {
5377
+ medplum.search('Slot', 'schedule=' + core.getReferenceString(schedule)).then((bundle) => {
5378
+ setSlots(bundle.entry.map((entry) => entry.resource));
5379
+ });
5380
+ }
5381
+ else {
5382
+ setSlots(undefined);
5383
+ }
5384
+ }, [medplum, schedule]);
5385
+ if (!schedule || !slots) {
5386
+ return null;
5387
+ }
5388
+ const actor = (_a = schedule.actor) === null || _a === void 0 ? void 0 : _a[0];
5389
+ return (React__default["default"].createElement("div", { className: "medplum-calendar-container", "data-testid": "scheduler" },
5390
+ React__default["default"].createElement("div", { className: "medplum-calendar-info-pane" },
5391
+ actor && React__default["default"].createElement(Avatar, { value: actor, size: "large" }),
5392
+ actor && (React__default["default"].createElement("h1", null,
5393
+ React__default["default"].createElement(ResourceName, { value: actor }))),
5394
+ React__default["default"].createElement("p", null, "1 hour"),
5395
+ date && React__default["default"].createElement("p", null, date.toLocaleDateString()),
5396
+ slot && React__default["default"].createElement("p", null, formatTime(new Date(slot.start)))),
5397
+ React__default["default"].createElement("div", { className: "medplum-calendar-selection-pane" },
5398
+ !date && (React__default["default"].createElement("div", null,
5399
+ React__default["default"].createElement("h3", null, "Select date"),
5400
+ React__default["default"].createElement(CalendarInput, { slots: slots, onClick: setDate }))),
5401
+ date && !slot && (React__default["default"].createElement("div", null,
5402
+ React__default["default"].createElement("h3", null, "Select time"),
5403
+ slots.map((s) => {
5404
+ const slotStart = new Date(s.start);
5405
+ return (slotStart.getTime() > date.getTime() &&
5406
+ slotStart.getTime() < date.getTime() + 24 * 3600 * 1000 && (React__default["default"].createElement("div", { key: s.id },
5407
+ React__default["default"].createElement(Button, { style: { width: 150 }, onClick: () => setSlot(s) }, formatTime(slotStart)))));
5408
+ }))),
5409
+ date && slot && !info && (React__default["default"].createElement("div", null,
5410
+ React__default["default"].createElement("h3", null, "Enter your info"),
5411
+ React__default["default"].createElement(FormSection, { title: "Name", htmlFor: "name" },
5412
+ React__default["default"].createElement(Input, { name: "name" })),
5413
+ React__default["default"].createElement(FormSection, { title: "Email", htmlFor: "email" },
5414
+ React__default["default"].createElement(Input, { name: "email" })),
5415
+ React__default["default"].createElement(Button, { primary: true, onClick: () => setInfo('info') }, "Next"))),
5416
+ date && slot && info && !form && (React__default["default"].createElement("div", null,
5417
+ React__default["default"].createElement("h3", null, "Custom questions"),
5418
+ React__default["default"].createElement(FormSection, { title: "Question 1", htmlFor: "q1" },
5419
+ React__default["default"].createElement(Input, { name: "q1" })),
5420
+ React__default["default"].createElement(FormSection, { title: "Question 2", htmlFor: "q2" },
5421
+ React__default["default"].createElement(Input, { name: "email" })),
5422
+ React__default["default"].createElement(FormSection, { title: "Question 3", htmlFor: "q3" },
5423
+ React__default["default"].createElement(Input, { name: "email" })),
5424
+ React__default["default"].createElement(Button, { primary: true, onClick: () => setForm('form') }, "Next"))),
5425
+ date && slot && info && form && (React__default["default"].createElement("div", null,
5426
+ React__default["default"].createElement("h3", null, "You're all set!"),
5427
+ React__default["default"].createElement("p", null, "Check your email for a calendar invite."))))));
5428
+ }
5429
+ function formatTime(date) {
5430
+ return date.toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' });
5431
+ }
5432
+
5173
5433
  function ServiceRequestTimeline(props) {
5174
5434
  return (React__default["default"].createElement(ResourceTimeline, { value: props.serviceRequest, buildSearchRequests: (resource) => ({
5175
5435
  resourceType: 'Bundle',
@@ -5232,7 +5492,7 @@
5232
5492
 
5233
5493
  function GoogleButton(props) {
5234
5494
  const medplum = useMedplum();
5235
- const { handleAuthResponse } = props;
5495
+ const { handleGoogleCredential } = props;
5236
5496
  const googleClientId = getGoogleClientId(props.googleClientId);
5237
5497
  const parentRef = React.useRef(null);
5238
5498
  const [scriptLoaded, setScriptLoaded] = React.useState(typeof google !== 'undefined');
@@ -5246,7 +5506,7 @@
5246
5506
  if (!initialized) {
5247
5507
  google.accounts.id.initialize({
5248
5508
  client_id: googleClientId,
5249
- callback: (response) => medplum.startGoogleLogin(response).then(handleAuthResponse),
5509
+ callback: handleGoogleCredential,
5250
5510
  });
5251
5511
  setInitialized(true);
5252
5512
  }
@@ -5254,7 +5514,7 @@
5254
5514
  google.accounts.id.renderButton(parentRef.current, {});
5255
5515
  setButtonRendered(true);
5256
5516
  }
5257
- }, [medplum, googleClientId, initialized, scriptLoaded, parentRef, buttonRendered, handleAuthResponse]);
5517
+ }, [medplum, googleClientId, initialized, scriptLoaded, parentRef, buttonRendered, handleGoogleCredential]);
5258
5518
  if (!googleClientId) {
5259
5519
  return null;
5260
5520
  }
@@ -5285,19 +5545,24 @@
5285
5545
  setMemberships(response.memberships);
5286
5546
  }
5287
5547
  if (response.code) {
5288
- medplum
5289
- .processCode(response.code)
5290
- .then(() => {
5291
- if (props.onSuccess) {
5292
- props.onSuccess();
5293
- }
5294
- })
5295
- .catch(console.log);
5548
+ if (props.onCode) {
5549
+ props.onCode(response.code);
5550
+ }
5551
+ else {
5552
+ medplum
5553
+ .processCode(response.code)
5554
+ .then(() => {
5555
+ if (props.onSuccess) {
5556
+ props.onSuccess();
5557
+ }
5558
+ })
5559
+ .catch(console.log);
5560
+ }
5296
5561
  }
5297
5562
  }
5298
5563
  return (React__default["default"].createElement(Document, { width: 450 }, (() => {
5299
5564
  if (!login) {
5300
- return (React__default["default"].createElement(AuthenticationForm, { googleClientId: props.googleClientId, onForgotPassword: props.onForgotPassword, onRegister: props.onRegister, handleAuthResponse: handleAuthResponse }, props.children));
5565
+ 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));
5301
5566
  }
5302
5567
  else if (memberships) {
5303
5568
  return React__default["default"].createElement(ProfileForm, { login: login, memberships: memberships, handleAuthResponse: handleAuthResponse });
@@ -5314,6 +5579,9 @@
5314
5579
  return (React__default["default"].createElement(Form, { style: { maxWidth: 400 }, onSubmit: (formData) => {
5315
5580
  medplum
5316
5581
  .startLogin({
5582
+ clientId: props.clientId,
5583
+ scope: props.scope,
5584
+ nonce: props.nonce,
5317
5585
  email: formData.email,
5318
5586
  password: formData.password,
5319
5587
  remember: formData.remember === 'true',
@@ -5340,7 +5608,18 @@
5340
5608
  React__default["default"].createElement("div", null,
5341
5609
  React__default["default"].createElement(Button, { type: "submit", testid: "submit" }, "Sign in"))),
5342
5610
  React__default["default"].createElement("div", { className: "medplum-signin-google-container" },
5343
- React__default["default"].createElement(GoogleButton, { googleClientId: props.googleClientId, handleAuthResponse: props.handleAuthResponse }))));
5611
+ React__default["default"].createElement(GoogleButton, { googleClientId: props.googleClientId, handleGoogleCredential: (response) => {
5612
+ medplum
5613
+ .startGoogleLogin({
5614
+ clientId: props.clientId,
5615
+ scope: props.scope,
5616
+ nonce: props.nonce,
5617
+ googleClientId: response.clientId,
5618
+ googleCredential: response.credential,
5619
+ })
5620
+ .then(props.handleAuthResponse)
5621
+ .catch(setOutcome);
5622
+ } }))));
5344
5623
  }
5345
5624
  function ProfileForm(props) {
5346
5625
  const medplum = useMedplum();
@@ -5426,6 +5705,8 @@
5426
5705
  exports.CodeInput = CodeInput;
5427
5706
  exports.CodeableConceptDisplay = CodeableConceptDisplay;
5428
5707
  exports.CodeableConceptInput = CodeableConceptInput;
5708
+ exports.ContactDetailDisplay = ContactDetailDisplay;
5709
+ exports.ContactDetailInput = ContactDetailInput;
5429
5710
  exports.ContactPointDisplay = ContactPointDisplay;
5430
5711
  exports.ContactPointInput = ContactPointInput;
5431
5712
  exports.DateTimeDisplay = DateTimeDisplay;
@@ -5477,6 +5758,7 @@
5477
5758
  exports.ResourcePropertyInput = ResourcePropertyInput;
5478
5759
  exports.ResourceTable = ResourceTable;
5479
5760
  exports.ResourceTimeline = ResourceTimeline;
5761
+ exports.Scheduler = Scheduler;
5480
5762
  exports.Scrollable = Scrollable;
5481
5763
  exports.SearchChangeEvent = SearchChangeEvent;
5482
5764
  exports.SearchClickEvent = SearchClickEvent;