@medplum/react 0.9.18 → 0.9.21

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
@@ -22,10 +22,10 @@
22
22
  }
23
23
 
24
24
  function Input(props) {
25
- const className = 'medplum-input'; // + (props.size ? ' ' + props.size : '');
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
  }
@@ -287,7 +287,7 @@
287
287
  props.onChange(newValues);
288
288
  }
289
289
  }
290
- return (React__default["default"].createElement("table", null,
290
+ return (React__default["default"].createElement("table", { style: { width: '100%' } },
291
291
  React__default["default"].createElement("colgroup", null,
292
292
  React__default["default"].createElement("col", { width: "90%" }),
293
293
  React__default["default"].createElement("col", { width: "10%" })),
@@ -713,6 +713,14 @@
713
713
  .join('');
714
714
  }
715
715
 
716
+ function CheckboxFormSection(props) {
717
+ return (React__default["default"].createElement("div", { className: "medplum-checkbox-form-section" },
718
+ React__default["default"].createElement("div", { className: "medplum-checkbox-form-section-checkbox-container" }, props.children),
719
+ React__default["default"].createElement("div", { className: "medplum-checkbox-form-section-details-container" },
720
+ React__default["default"].createElement("label", { htmlFor: props.htmlFor }, props.title),
721
+ React__default["default"].createElement("p", null, props.description))));
722
+ }
723
+
716
724
  const DEFAULT_IGNORED_PROPERTIES = [
717
725
  'meta',
718
726
  'implicitRules',
@@ -726,9 +734,9 @@
726
734
  function FormSection(props) {
727
735
  const issues = getIssuesForExpression(props.outcome, props.htmlFor);
728
736
  const invalid = issues && issues.length > 0;
729
- return (React__default["default"].createElement("fieldset", null,
737
+ return (React__default["default"].createElement("fieldset", { className: "medplum-form-section" },
730
738
  props.title && React__default["default"].createElement("label", { htmlFor: props.htmlFor }, props.title),
731
- props.description && React__default["default"].createElement("small", null, props.description),
739
+ props.description && React__default["default"].createElement("p", null, props.description),
732
740
  props.children,
733
741
  invalid && (React__default["default"].createElement("div", { id: props.htmlFor + '-errors', className: "medplum-input-error" }, issues === null || issues === void 0 ? void 0 : issues.map((issue) => {
734
742
  var _a, _b;
@@ -736,6 +744,50 @@
736
744
  })))));
737
745
  }
738
746
 
747
+ function ResourceForm(props) {
748
+ const medplum = useMedplum();
749
+ const defaultValue = useResource(props.defaultValue);
750
+ const [schema, setSchema] = React.useState();
751
+ const [value, setValue] = React.useState();
752
+ React.useEffect(() => {
753
+ if (defaultValue) {
754
+ setValue(JSON.parse(JSON.stringify(defaultValue)));
755
+ medplum.requestSchema(defaultValue.resourceType).then(setSchema);
756
+ }
757
+ }, [medplum, defaultValue]);
758
+ if (!schema || !value) {
759
+ return React__default["default"].createElement("div", null, "Loading...");
760
+ }
761
+ return (React__default["default"].createElement("form", { noValidate: true, autoComplete: "off", onSubmit: (e) => {
762
+ e.preventDefault();
763
+ if (props.onSubmit) {
764
+ props.onSubmit(value);
765
+ }
766
+ } },
767
+ React__default["default"].createElement(FormSection, { title: "Resource Type" },
768
+ React__default["default"].createElement(Input, { name: "resourceType", defaultValue: value.resourceType, disabled: true })),
769
+ React__default["default"].createElement(FormSection, { title: "ID" },
770
+ React__default["default"].createElement(Input, { name: "id", defaultValue: value.id, disabled: true })),
771
+ React__default["default"].createElement(BackboneElementInput, { typeName: value.resourceType, defaultValue: value, outcome: props.outcome, onChange: setValue }),
772
+ React__default["default"].createElement(Button, { type: "submit", size: "large" }, "OK"),
773
+ props.onDelete && (React__default["default"].createElement(Button, { type: "button", size: "large", onClick: () => {
774
+ props.onDelete(value);
775
+ } }, "Delete"))));
776
+ }
777
+ function setPropertyValue(obj, key, propName, elementDefinition, value) {
778
+ const types = elementDefinition.type;
779
+ if (types.length > 1) {
780
+ for (const type of types) {
781
+ const compoundKey = key.replace('[x]', core.capitalize(type.code));
782
+ if (compoundKey in obj) {
783
+ delete obj[compoundKey];
784
+ }
785
+ }
786
+ }
787
+ obj[propName] = value;
788
+ return obj;
789
+ }
790
+
739
791
  function DescriptionList(props) {
740
792
  return React__default["default"].createElement("dl", { className: 'medplum-description-list' + (props.compact ? ' compact' : '') }, props.children);
741
793
  }
@@ -824,6 +876,18 @@
824
876
  return React__default["default"].createElement(React__default["default"].Fragment, null, builder.join('').trim());
825
877
  }
826
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
+
827
891
  function DateTimeDisplay(props) {
828
892
  if (!props.value) {
829
893
  return null;
@@ -972,6 +1036,8 @@
972
1036
  return React__default["default"].createElement(CodeableConceptDisplay, { value: value });
973
1037
  case core.PropertyType.Coding:
974
1038
  return React__default["default"].createElement(CodingDisplay, { value: value });
1039
+ case core.PropertyType.ContactDetail:
1040
+ return React__default["default"].createElement(ContactDetailDisplay, { value: value });
975
1041
  case core.PropertyType.ContactPoint:
976
1042
  return React__default["default"].createElement(ContactPointDisplay, { value: value });
977
1043
  case core.PropertyType.HumanName:
@@ -1037,6 +1103,15 @@
1037
1103
  return (React__default["default"].createElement(Input, { name: props.name, type: "text", placeholder: "Annotation text", defaultValue: value.text, onChange: setText }));
1038
1104
  }
1039
1105
 
1106
+ function Checkbox(props) {
1107
+ const className = 'medplum-checkbox';
1108
+ return (React__default["default"].createElement("input", { id: props.name, name: props.name, className: className, type: "checkbox", value: "true", defaultChecked: !!props.defaultValue, required: props.required, ref: props.inputRef, "data-testid": props.testid, disabled: props.disabled, onChange: (e) => {
1109
+ if (props.onChange) {
1110
+ props.onChange(e.currentTarget.checked);
1111
+ }
1112
+ } }));
1113
+ }
1114
+
1040
1115
  function CodeableConceptInput(props) {
1041
1116
  const medplum = useMedplum();
1042
1117
  let defaultValue = undefined;
@@ -1132,19 +1207,34 @@
1132
1207
  const ref = React.useRef();
1133
1208
  ref.current = contactPoint;
1134
1209
  function setContactPointWrapper(newValue) {
1210
+ if (newValue && Object.keys(newValue).length === 0) {
1211
+ newValue = undefined;
1212
+ }
1135
1213
  setContactPoint(newValue);
1136
1214
  if (props.onChange) {
1137
1215
  props.onChange(newValue);
1138
1216
  }
1139
1217
  }
1140
1218
  function setSystem(system) {
1141
- 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);
1142
1224
  }
1143
1225
  function setUse(use) {
1144
- 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);
1145
1231
  }
1146
1232
  function setValue(value) {
1147
- 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);
1148
1238
  }
1149
1239
  return (React__default["default"].createElement(InputRow, null,
1150
1240
  React__default["default"].createElement(Select, { defaultValue: contactPoint === null || contactPoint === void 0 ? void 0 : contactPoint.system, onChange: setSystem, testid: "system" },
@@ -1165,6 +1255,36 @@
1165
1255
  React__default["default"].createElement(Input, { placeholder: "Value", defaultValue: contactPoint === null || contactPoint === void 0 ? void 0 : contactPoint.value, onChange: setValue })));
1166
1256
  }
1167
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
+
1168
1288
  /**
1169
1289
  * The DateTimeInput component is a wrapper around the HTML5 input type="datetime-local".
1170
1290
  * The main purpose is to reconcile time zones.
@@ -1223,7 +1343,7 @@
1223
1343
  }
1224
1344
 
1225
1345
  function TextArea(props) {
1226
- const className = 'medplum-textarea';
1346
+ const className = 'medplum-textarea' + (props.monospace ? ' monospace' : '');
1227
1347
  const issues = getIssuesForExpression(props.outcome, props.name);
1228
1348
  const invalid = issues && issues.length > 0;
1229
1349
  return (React__default["default"].createElement("textarea", { id: props.name, name: props.name, className: className, defaultValue: props.defaultValue || '', required: props.required, 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, style: props.style, onChange: (e) => {
@@ -1234,7 +1354,7 @@
1234
1354
  }
1235
1355
 
1236
1356
  function ExtensionInput(props) {
1237
- return (React__default["default"].createElement(TextArea, { testid: "extension-input", name: props.name, defaultValue: core.stringify(props.defaultValue), onChange: (newValue) => {
1357
+ return (React__default["default"].createElement(TextArea, { testid: "extension-input", name: props.name, defaultValue: core.stringify(props.defaultValue), monospace: true, onChange: (newValue) => {
1238
1358
  if (props.onChange) {
1239
1359
  props.onChange(JSON.parse(newValue));
1240
1360
  }
@@ -1457,35 +1577,34 @@
1457
1577
  props.onChange(newValues);
1458
1578
  }
1459
1579
  }
1460
- return (React__default["default"].createElement("div", null,
1461
- React__default["default"].createElement("table", { style: { width: '100%' } },
1462
- React__default["default"].createElement("colgroup", null,
1463
- React__default["default"].createElement("col", { width: "90%" }),
1464
- React__default["default"].createElement("col", { width: "10%" })),
1465
- React__default["default"].createElement("tbody", null,
1466
- values.map((v, index) => (React__default["default"].createElement("tr", { key: `${index}-${values.length}` },
1467
- React__default["default"].createElement("td", null,
1468
- React__default["default"].createElement(ResourcePropertyInput, { arrayElement: true, property: props.property, name: props.name + '.' + index, defaultValue: v, onChange: (newValue) => {
1469
- const copy = [...valuesRef.current];
1470
- copy[index] = newValue;
1471
- setValuesWrapper(copy);
1472
- } })),
1473
- React__default["default"].createElement("td", { style: { textAlign: 'right' } },
1474
- React__default["default"].createElement(Button, { onClick: (e) => {
1475
- killEvent(e);
1476
- const copy = [...valuesRef.current];
1477
- copy.splice(index, 1);
1478
- setValuesWrapper(copy);
1479
- } }, "Remove"))))),
1480
- React__default["default"].createElement("tr", null,
1481
- React__default["default"].createElement("td", null),
1482
- React__default["default"].createElement("td", { style: { textAlign: 'right' } },
1483
- React__default["default"].createElement(Button, { onClick: (e) => {
1484
- killEvent(e);
1485
- const copy = [...valuesRef.current];
1486
- copy.push(undefined);
1487
- setValuesWrapper(copy);
1488
- } }, "Add")))))));
1580
+ return (React__default["default"].createElement("table", { style: { width: '100%', borderCollapse: 'collapse' } },
1581
+ React__default["default"].createElement("colgroup", null,
1582
+ React__default["default"].createElement("col", { width: "90%" }),
1583
+ React__default["default"].createElement("col", { width: "10%" })),
1584
+ React__default["default"].createElement("tbody", null,
1585
+ values.map((v, index) => (React__default["default"].createElement("tr", { key: `${index}-${values.length}` },
1586
+ React__default["default"].createElement("td", null,
1587
+ React__default["default"].createElement(ResourcePropertyInput, { arrayElement: true, property: props.property, name: props.name + '.' + index, defaultValue: v, onChange: (newValue) => {
1588
+ const copy = [...valuesRef.current];
1589
+ copy[index] = newValue;
1590
+ setValuesWrapper(copy);
1591
+ } })),
1592
+ React__default["default"].createElement("td", { style: { textAlign: 'right' } },
1593
+ React__default["default"].createElement(Button, { onClick: (e) => {
1594
+ killEvent(e);
1595
+ const copy = [...valuesRef.current];
1596
+ copy.splice(index, 1);
1597
+ setValuesWrapper(copy);
1598
+ } }, "Remove"))))),
1599
+ React__default["default"].createElement("tr", null,
1600
+ React__default["default"].createElement("td", null),
1601
+ React__default["default"].createElement("td", { style: { textAlign: 'right' } },
1602
+ React__default["default"].createElement(Button, { onClick: (e) => {
1603
+ killEvent(e);
1604
+ const copy = [...valuesRef.current];
1605
+ copy.push(undefined);
1606
+ setValuesWrapper(copy);
1607
+ } }, "Add"))))));
1489
1608
  }
1490
1609
 
1491
1610
  function ResourcePropertyInput(props) {
@@ -1529,6 +1648,7 @@
1529
1648
  } }))));
1530
1649
  }
1531
1650
  function ElementDefinitionTypeInput(props) {
1651
+ var _a;
1532
1652
  const property = props.property;
1533
1653
  const propertyType = props.elementDefinitionType.code;
1534
1654
  const name = props.name;
@@ -1560,7 +1680,11 @@
1560
1680
  case core.PropertyType.code:
1561
1681
  return React__default["default"].createElement(CodeInput, { property: property, name: name, defaultValue: value, onChange: props.onChange });
1562
1682
  case core.PropertyType.boolean:
1563
- return (React__default["default"].createElement("input", { type: "checkbox", name: name, "data-testid": name, defaultChecked: !!value, value: "true", onChange: (e) => props.onChange && props.onChange(e.target.value === 'true') }));
1683
+ return (React__default["default"].createElement(Checkbox, { name: name, testid: name, defaultValue: !!value, onChange: (newValue) => {
1684
+ if (props.onChange) {
1685
+ props.onChange(newValue);
1686
+ }
1687
+ } }));
1564
1688
  case core.PropertyType.markdown:
1565
1689
  return React__default["default"].createElement(TextArea, { name: name, testid: name, defaultValue: value, onChange: props.onChange });
1566
1690
  // 2.24.0.2 Complex Types
@@ -1575,6 +1699,8 @@
1575
1699
  return React__default["default"].createElement(CodeableConceptInput, { property: property, name: name, defaultValue: value, onChange: props.onChange });
1576
1700
  case core.PropertyType.Coding:
1577
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 });
1578
1704
  case core.PropertyType.ContactPoint:
1579
1705
  return React__default["default"].createElement(ContactPointInput, { name: name, defaultValue: value, onChange: props.onChange });
1580
1706
  case core.PropertyType.Extension:
@@ -1594,7 +1720,7 @@
1594
1720
  case core.PropertyType.Reference:
1595
1721
  return (React__default["default"].createElement(ReferenceInput, { name: name, defaultValue: value, targetTypes: getTargetTypes(property), onChange: props.onChange }));
1596
1722
  default:
1597
- return (React__default["default"].createElement(BackboneElementInput, { property: property, name: name, defaultValue: value, onChange: props.onChange, outcome: props.outcome }));
1723
+ return (React__default["default"].createElement(BackboneElementInput, { typeName: core.buildTypeName((_a = property.path) === null || _a === void 0 ? void 0 : _a.split('.')), defaultValue: value, onChange: props.onChange, outcome: props.outcome }));
1598
1724
  }
1599
1725
  }
1600
1726
  function getTargetTypes(property) {
@@ -1602,65 +1728,8 @@
1602
1728
  return (_c = (_b = (_a = property === null || property === void 0 ? void 0 : property.type) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.targetProfile) === null || _c === void 0 ? void 0 : _c.map((p) => p.split('/').pop());
1603
1729
  }
1604
1730
 
1605
- function ResourceForm(props) {
1606
- const medplum = useMedplum();
1607
- const defaultValue = useResource(props.defaultValue);
1608
- const [schema, setSchema] = React.useState();
1609
- const [value, setValue] = React.useState();
1610
- React.useEffect(() => {
1611
- if (defaultValue) {
1612
- setValue(JSON.parse(JSON.stringify(defaultValue)));
1613
- medplum.requestSchema(defaultValue.resourceType).then(setSchema);
1614
- }
1615
- }, [medplum, defaultValue]);
1616
- if (!schema || !value) {
1617
- return React__default["default"].createElement("div", null, "Loading...");
1618
- }
1619
- const typeSchema = schema.types[value.resourceType];
1620
- const typedValue = { type: value.resourceType, value };
1621
- return (React__default["default"].createElement("form", { noValidate: true, autoComplete: "off", onSubmit: (e) => {
1622
- e.preventDefault();
1623
- if (props.onSubmit) {
1624
- props.onSubmit(value);
1625
- }
1626
- } },
1627
- React__default["default"].createElement(FormSection, { title: "Resource Type" },
1628
- React__default["default"].createElement(Input, { name: "resourceType", defaultValue: value.resourceType, disabled: true })),
1629
- React__default["default"].createElement(FormSection, { title: "ID" },
1630
- React__default["default"].createElement(Input, { name: "id", defaultValue: value.id, disabled: true })),
1631
- Object.entries(typeSchema.properties).map((entry) => {
1632
- const key = entry[0];
1633
- if (key === 'id' || DEFAULT_IGNORED_PROPERTIES.indexOf(key) >= 0) {
1634
- return null;
1635
- }
1636
- const property = entry[1];
1637
- const [propertyValue, propertyType] = getValueAndType(typedValue, key);
1638
- return (React__default["default"].createElement(FormSection, { key: key, title: core.getPropertyDisplayName(key), description: property.definition, htmlFor: key, outcome: props.outcome },
1639
- React__default["default"].createElement(ResourcePropertyInput, { property: property, name: key, defaultValue: propertyValue, defaultPropertyType: propertyType, outcome: props.outcome, onChange: (newValue, propName) => {
1640
- setValue(setPropertyValue(value, key, propName !== null && propName !== void 0 ? propName : key, entry[1], newValue));
1641
- } })));
1642
- }),
1643
- React__default["default"].createElement(Button, { type: "submit", size: "large" }, "OK"),
1644
- props.onDelete && (React__default["default"].createElement(Button, { type: "button", size: "large", onClick: () => {
1645
- props.onDelete(value);
1646
- } }, "Delete"))));
1647
- }
1648
- function setPropertyValue(obj, key, propName, elementDefinition, value) {
1649
- const types = elementDefinition.type;
1650
- if (types.length > 1) {
1651
- for (const type of types) {
1652
- const compoundKey = key.replace('[x]', core.capitalize(type.code));
1653
- if (compoundKey in obj) {
1654
- delete obj[compoundKey];
1655
- }
1656
- }
1657
- }
1658
- obj[propName] = value;
1659
- return obj;
1660
- }
1661
-
1662
1731
  function BackboneElementInput(props) {
1663
- var _a, _b;
1732
+ var _a;
1664
1733
  const [value, setValue] = React.useState((_a = props.defaultValue) !== null && _a !== void 0 ? _a : {});
1665
1734
  function setValueWrapper(newValue) {
1666
1735
  setValue(newValue);
@@ -1668,13 +1737,14 @@
1668
1737
  props.onChange(newValue);
1669
1738
  }
1670
1739
  }
1671
- const typeName = core.buildTypeName((_b = props.property.path) === null || _b === void 0 ? void 0 : _b.split('.'));
1740
+ const typeName = props.typeName;
1672
1741
  const typeSchema = core.globalSchema.types[typeName];
1673
1742
  if (!typeSchema) {
1674
1743
  return React__default["default"].createElement("div", null,
1675
1744
  typeName,
1676
1745
  "\u00A0not implemented");
1677
1746
  }
1747
+ const typedValue = { type: typeName, value };
1678
1748
  return (React__default["default"].createElement(React__default["default"].Fragment, null, Object.entries(typeSchema.properties).map((entry) => {
1679
1749
  const key = entry[0];
1680
1750
  if (key === 'id' || DEFAULT_IGNORED_PROPERTIES.indexOf(key) >= 0) {
@@ -1684,7 +1754,13 @@
1684
1754
  if (!property.type) {
1685
1755
  return null;
1686
1756
  }
1687
- const [propertyValue, propertyType] = getValueAndType(value, key);
1757
+ const [propertyValue, propertyType] = getValueAndType(typedValue, key);
1758
+ if (property.type.length === 1 && property.type[0].code === 'boolean') {
1759
+ return (React__default["default"].createElement(CheckboxFormSection, { key: key, title: core.getPropertyDisplayName(key), description: property.definition, htmlFor: key },
1760
+ React__default["default"].createElement(ResourcePropertyInput, { property: property, name: key, defaultValue: propertyValue, defaultPropertyType: propertyType, outcome: props.outcome, onChange: (newValue, propName) => {
1761
+ setValueWrapper(setPropertyValue(value, key, propName !== null && propName !== void 0 ? propName : key, entry[1], newValue));
1762
+ } })));
1763
+ }
1688
1764
  return (React__default["default"].createElement(FormSection, { key: key, title: core.getPropertyDisplayName(key), description: property.definition, htmlFor: key, outcome: props.outcome },
1689
1765
  React__default["default"].createElement(ResourcePropertyInput, { property: property, name: key, defaultValue: propertyValue, defaultPropertyType: propertyType, outcome: props.outcome, onChange: (newValue, propName) => {
1690
1766
  setValueWrapper(setPropertyValue(value, key, propName !== null && propName !== void 0 ? propName : key, entry[1], newValue));
@@ -2108,8 +2184,7 @@
2108
2184
  setHistory({});
2109
2185
  return;
2110
2186
  }
2111
- const batchRequest = buildSearchRequests(resource);
2112
- medplum.post('fhir/R4', batchRequest).then(handleBatchResponse);
2187
+ medplum.executeBatch(buildSearchRequests(resource)).then(handleBatchResponse);
2113
2188
  }, [medplum, resource, buildSearchRequests]);
2114
2189
  React.useEffect(() => {
2115
2190
  loadTimeline();
@@ -3202,7 +3277,7 @@
3202
3277
  }
3203
3278
  } }));
3204
3279
  case core.SearchParameterType.BOOLEAN:
3205
- return (React__default["default"].createElement("input", { type: "checkbox", name: name, "data-testid": name, defaultChecked: props.defaultValue === 'true', value: "true", onChange: (e) => props.onChange(e.target.checked ? 'true' : 'false') }));
3280
+ return (React__default["default"].createElement(Checkbox, { name: name, testid: name, defaultValue: props.defaultValue === 'true', onChange: (newValue) => props.onChange(newValue.toString()) }));
3206
3281
  case core.SearchParameterType.DATE:
3207
3282
  return React__default["default"].createElement(Input, { type: "date", testid: name, defaultValue: props.defaultValue, onChange: props.onChange });
3208
3283
  case core.SearchParameterType.DATETIME:
@@ -3898,7 +3973,7 @@
3898
3973
  function HeaderSearchInput(props) {
3899
3974
  const medplum = useMedplum();
3900
3975
  return (React__default["default"].createElement(Autocomplete, { loadOptions: (input, signal) => __awaiter(this, void 0, void 0, function* () {
3901
- return getResourcesFromResponse((yield medplum.graphql(buildGraphQLQuery(input), { signal })), input);
3976
+ return getResourcesFromResponse((yield medplum.graphql(buildGraphQLQuery(input), undefined, undefined, { signal })), input);
3902
3977
  }), getId: (item) => {
3903
3978
  return item.id;
3904
3979
  }, getIcon: (item) => React__default["default"].createElement(Avatar, { value: item }), getDisplay: (item) => React__default["default"].createElement(ResourceName, { value: item }), getHelpText: (item) => {
@@ -4472,8 +4547,24 @@
4472
4547
  setResponseItems(newResponseItems);
4473
4548
  props.onChange(newResponseItems);
4474
4549
  }
4475
- return (React__default["default"].createElement(React__default["default"].Fragment, null, props.items.map((item, index) => item.type === exports.QuestionnaireItemType.group ? (React__default["default"].createElement(QuestionnaireFormItem, { key: item.linkId, item: item, onChange: (newResponseItem) => setResponseItem(index, newResponseItem) })) : (React__default["default"].createElement(FormSection, { key: item.linkId, htmlFor: item.linkId, title: item.text || '' },
4476
- React__default["default"].createElement(QuestionnaireFormItem, { item: item, onChange: (newResponseItem) => setResponseItem(index, newResponseItem) }))))));
4550
+ return (React__default["default"].createElement(React__default["default"].Fragment, null, props.items.map((item, index) => {
4551
+ if (item.type === exports.QuestionnaireItemType.display) {
4552
+ return React__default["default"].createElement("p", { key: item.linkId }, item.text);
4553
+ }
4554
+ if (item.type === exports.QuestionnaireItemType.group) {
4555
+ return (React__default["default"].createElement(QuestionnaireFormItem, { key: item.linkId, item: item, onChange: (newResponseItem) => setResponseItem(index, newResponseItem) }));
4556
+ }
4557
+ if (item.type === exports.QuestionnaireItemType.boolean) {
4558
+ const initial = item.initial && item.initial.length > 0 ? item.initial[0] : undefined;
4559
+ return (React__default["default"].createElement(CheckboxFormSection, { key: item.linkId, title: item.text, htmlFor: item.linkId },
4560
+ React__default["default"].createElement(Checkbox, { name: item.linkId, defaultValue: initial === null || initial === void 0 ? void 0 : initial.valueBoolean, onChange: (newValue) => setResponseItem(index, {
4561
+ linkId: item.linkId,
4562
+ answer: [{ valueBoolean: newValue }],
4563
+ }) })));
4564
+ }
4565
+ return (React__default["default"].createElement(FormSection, { key: item.linkId, htmlFor: item.linkId, title: item.text || '' },
4566
+ React__default["default"].createElement(QuestionnaireFormItem, { item: item, onChange: (newResponseItem) => setResponseItem(index, newResponseItem) })));
4567
+ })));
4477
4568
  }
4478
4569
  function QuestionnaireFormItem(props) {
4479
4570
  const item = props.item;
@@ -4504,7 +4595,7 @@
4504
4595
  React__default["default"].createElement("h3", null, item.text),
4505
4596
  item.item && React__default["default"].createElement(QuestionnaireFormItemArray, { items: item.item, onChange: onChangeItem })));
4506
4597
  case exports.QuestionnaireItemType.boolean:
4507
- return (React__default["default"].createElement("input", { type: "checkbox", id: name, name: name, value: "true", defaultChecked: initial === null || initial === void 0 ? void 0 : initial.valueBoolean, onChange: (e) => onChangeAnswer({ valueBoolean: e.currentTarget.checked }) }));
4598
+ return (React__default["default"].createElement(Checkbox, { name: name, defaultValue: initial === null || initial === void 0 ? void 0 : initial.valueBoolean, onChange: (newValue) => onChangeAnswer({ valueBoolean: newValue }) }));
4508
4599
  case exports.QuestionnaireItemType.decimal:
4509
4600
  return (React__default["default"].createElement(Input, { type: "number", step: "any", name: name, defaultValue: initial === null || initial === void 0 ? void 0 : initial.valueDecimal, onChange: (newValue) => onChangeAnswer({ valueDecimal: parseFloat(newValue) }) }));
4510
4601
  case exports.QuestionnaireItemType.integer:
@@ -4521,31 +4612,64 @@
4521
4612
  return (React__default["default"].createElement(TextArea, { name: name, defaultValue: initial === null || initial === void 0 ? void 0 : initial.valueString, onChange: (newValue) => onChangeAnswer({ valueString: newValue }) }));
4522
4613
  case exports.QuestionnaireItemType.url:
4523
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 }) }));
4524
- case exports.QuestionnaireItemType.choice:
4525
- case exports.QuestionnaireItemType.openChoice:
4526
- return (React__default["default"].createElement("div", null, item.answerOption &&
4527
- item.answerOption.map((option, index) => {
4528
- const valueElementDefinition = core.globalSchema.types['QuestionnaireItemAnswerOption'].properties['value[x]'];
4529
- const optionValue = core.getTypedPropertyValue({ type: 'QuestionnaireItemAnswerOption', value: option }, 'value');
4530
- const initialValue = core.getTypedPropertyValue({ type: 'QuestionnaireItemInitial', value: initial }, 'value');
4531
- const propertyName = 'value' + core.capitalize(optionValue.type);
4532
- const optionName = `${name}-option-${index}`;
4533
- return (React__default["default"].createElement("div", { key: optionName, className: "medplum-questionnaire-option-row" },
4534
- React__default["default"].createElement("div", { className: "medplum-questionnaire-option-checkbox" },
4535
- 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 }) })),
4536
- React__default["default"].createElement("div", null,
4537
- React__default["default"].createElement("label", { htmlFor: optionName },
4538
- React__default["default"].createElement(ResourcePropertyDisplay, { property: valueElementDefinition, propertyType: optionValue.type, value: optionValue.value })))));
4539
- })));
4540
4615
  case exports.QuestionnaireItemType.attachment:
4541
4616
  return (React__default["default"].createElement(AttachmentInput, { name: name, defaultValue: initial === null || initial === void 0 ? void 0 : initial.valueAttachment, onChange: (newValue) => onChangeAnswer({ valueAttachment: newValue }) }));
4542
4617
  case exports.QuestionnaireItemType.reference:
4543
4618
  return (React__default["default"].createElement(ReferenceInput, { name: name, defaultValue: initial === null || initial === void 0 ? void 0 : initial.valueReference, onChange: (newValue) => onChangeAnswer({ valueReference: newValue }) }));
4544
4619
  case exports.QuestionnaireItemType.quantity:
4545
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
+ }
4546
4629
  }
4547
4630
  return null;
4548
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
+ }
4549
4673
  function buildInitialResponse(questionnaire) {
4550
4674
  const response = {
4551
4675
  resourceType: 'QuestionnaireResponse',
@@ -4571,6 +4695,14 @@
4571
4695
  // have the same properties.
4572
4696
  return Object.assign({}, answer);
4573
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
+ }
4574
4706
 
4575
4707
  function QuestionnaireBuilder(props) {
4576
4708
  const medplum = useMedplum();
@@ -4784,7 +4916,7 @@
4784
4916
  const [responseBundle, setResponseBundle] = React.useState();
4785
4917
  React.useEffect(() => {
4786
4918
  if (requestGroup && !startedLoading) {
4787
- medplum.post('fhir/R4', buildBatchRequest(requestGroup)).then(setResponseBundle);
4919
+ medplum.executeBatch(buildBatchRequest(requestGroup)).then(setResponseBundle);
4788
4920
  setStartedLoading(true);
4789
4921
  }
4790
4922
  }, [medplum, requestGroup, startedLoading]);
@@ -5201,7 +5333,7 @@
5201
5333
 
5202
5334
  function GoogleButton(props) {
5203
5335
  const medplum = useMedplum();
5204
- const { handleAuthResponse } = props;
5336
+ const { handleGoogleCredential } = props;
5205
5337
  const googleClientId = getGoogleClientId(props.googleClientId);
5206
5338
  const parentRef = React.useRef(null);
5207
5339
  const [scriptLoaded, setScriptLoaded] = React.useState(typeof google !== 'undefined');
@@ -5215,7 +5347,7 @@
5215
5347
  if (!initialized) {
5216
5348
  google.accounts.id.initialize({
5217
5349
  client_id: googleClientId,
5218
- callback: (response) => medplum.startGoogleLogin(response).then(handleAuthResponse),
5350
+ callback: handleGoogleCredential,
5219
5351
  });
5220
5352
  setInitialized(true);
5221
5353
  }
@@ -5223,7 +5355,7 @@
5223
5355
  google.accounts.id.renderButton(parentRef.current, {});
5224
5356
  setButtonRendered(true);
5225
5357
  }
5226
- }, [medplum, googleClientId, initialized, scriptLoaded, parentRef, buttonRendered, handleAuthResponse]);
5358
+ }, [medplum, googleClientId, initialized, scriptLoaded, parentRef, buttonRendered, handleGoogleCredential]);
5227
5359
  if (!googleClientId) {
5228
5360
  return null;
5229
5361
  }
@@ -5254,19 +5386,24 @@
5254
5386
  setMemberships(response.memberships);
5255
5387
  }
5256
5388
  if (response.code) {
5257
- medplum
5258
- .processCode(response.code)
5259
- .then(() => {
5260
- if (props.onSuccess) {
5261
- props.onSuccess();
5262
- }
5263
- })
5264
- .catch(console.log);
5389
+ if (props.onCode) {
5390
+ props.onCode(response.code);
5391
+ }
5392
+ else {
5393
+ medplum
5394
+ .processCode(response.code)
5395
+ .then(() => {
5396
+ if (props.onSuccess) {
5397
+ props.onSuccess();
5398
+ }
5399
+ })
5400
+ .catch(console.log);
5401
+ }
5265
5402
  }
5266
5403
  }
5267
5404
  return (React__default["default"].createElement(Document, { width: 450 }, (() => {
5268
5405
  if (!login) {
5269
- return (React__default["default"].createElement(AuthenticationForm, { googleClientId: props.googleClientId, onForgotPassword: props.onForgotPassword, onRegister: props.onRegister, handleAuthResponse: handleAuthResponse }, props.children));
5406
+ 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));
5270
5407
  }
5271
5408
  else if (memberships) {
5272
5409
  return React__default["default"].createElement(ProfileForm, { login: login, memberships: memberships, handleAuthResponse: handleAuthResponse });
@@ -5283,6 +5420,9 @@
5283
5420
  return (React__default["default"].createElement(Form, { style: { maxWidth: 400 }, onSubmit: (formData) => {
5284
5421
  medplum
5285
5422
  .startLogin({
5423
+ clientId: props.clientId,
5424
+ scope: props.scope,
5425
+ nonce: props.nonce,
5286
5426
  email: formData.email,
5287
5427
  password: formData.password,
5288
5428
  remember: formData.remember === 'true',
@@ -5309,7 +5449,18 @@
5309
5449
  React__default["default"].createElement("div", null,
5310
5450
  React__default["default"].createElement(Button, { type: "submit", testid: "submit" }, "Sign in"))),
5311
5451
  React__default["default"].createElement("div", { className: "medplum-signin-google-container" },
5312
- React__default["default"].createElement(GoogleButton, { googleClientId: props.googleClientId, handleAuthResponse: props.handleAuthResponse }))));
5452
+ React__default["default"].createElement(GoogleButton, { googleClientId: props.googleClientId, handleGoogleCredential: (response) => {
5453
+ medplum
5454
+ .startGoogleLogin({
5455
+ clientId: props.clientId,
5456
+ scope: props.scope,
5457
+ nonce: props.nonce,
5458
+ googleClientId: response.clientId,
5459
+ googleCredential: response.credential,
5460
+ })
5461
+ .then(props.handleAuthResponse)
5462
+ .catch(setOutcome);
5463
+ } }))));
5313
5464
  }
5314
5465
  function ProfileForm(props) {
5315
5466
  const medplum = useMedplum();
@@ -5390,9 +5541,13 @@
5390
5541
  exports.Avatar = Avatar;
5391
5542
  exports.BackboneElementInput = BackboneElementInput;
5392
5543
  exports.Button = Button;
5544
+ exports.Checkbox = Checkbox;
5545
+ exports.CheckboxFormSection = CheckboxFormSection;
5393
5546
  exports.CodeInput = CodeInput;
5394
5547
  exports.CodeableConceptDisplay = CodeableConceptDisplay;
5395
5548
  exports.CodeableConceptInput = CodeableConceptInput;
5549
+ exports.ContactDetailDisplay = ContactDetailDisplay;
5550
+ exports.ContactDetailInput = ContactDetailInput;
5396
5551
  exports.ContactPointDisplay = ContactPointDisplay;
5397
5552
  exports.ContactPointInput = ContactPointInput;
5398
5553
  exports.DateTimeDisplay = DateTimeDisplay;