@medplum/react 0.9.21 → 0.9.24

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/esm/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { formatAddress, getDisplayString, getImageSrc, capitalize, globalSchema, getPropertyDisplayName, formatHumanName, stringify, buildTypeName, PropertyType, getTypedPropertyValue, createReference, toTypedValue, getReferenceString, evalFhirPath, getSearchParameterDetails, Operator, evalFhirPathTyped, SearchParameterType, formatSearchQuery, parseSearchDefinition, DEFAULT_SEARCH_COUNT, isUUID } from '@medplum/core';
2
- import React, { useState, useRef, createContext, useEffect, useContext, useCallback } from 'react';
1
+ import { formatAddress, getDisplayString, getImageSrc, capitalize, globalSchema, getPropertyDisplayName, formatHumanName, stringify, buildTypeName, PropertyType, getTypedPropertyValue, createReference, toTypedValue, getReferenceString, evalFhirPath, getSearchParameterDetails, Operator, evalFhirPathTyped, SearchParameterType, formatSearchQuery, parseSearchDefinition, DEFAULT_SEARCH_COUNT, isUUID, parseJWTPayload } from '@medplum/core';
2
+ import React, { useState, useRef, createContext, useEffect, useContext, useCallback, useMemo } from 'react';
3
3
  import { useNavigate, useLocation } from 'react-router-dom';
4
4
 
5
5
  function AddressDisplay(props) {
@@ -1770,18 +1770,24 @@ function ResourceBadge(props) {
1770
1770
  }
1771
1771
 
1772
1772
  function DiagnosticReportDisplay(props) {
1773
- var _a;
1773
+ var _a, _b;
1774
1774
  const diagnosticReport = useResource(props.value);
1775
+ const specimen = useResource((_a = diagnosticReport === null || diagnosticReport === void 0 ? void 0 : diagnosticReport.specimen) === null || _a === void 0 ? void 0 : _a[0]);
1775
1776
  if (!diagnosticReport) {
1776
1777
  return null;
1777
1778
  }
1778
- let textContent = undefined;
1779
+ let textContent = '';
1779
1780
  if (diagnosticReport.presentedForm && diagnosticReport.presentedForm.length > 0) {
1780
1781
  const pf = diagnosticReport.presentedForm[0];
1781
- if (((_a = pf.contentType) === null || _a === void 0 ? void 0 : _a.startsWith('text/plain')) && pf.data) {
1782
+ if (((_b = pf.contentType) === null || _b === void 0 ? void 0 : _b.startsWith('text/plain')) && pf.data) {
1782
1783
  textContent = window.atob(pf.data);
1783
1784
  }
1784
1785
  }
1786
+ if (specimen === null || specimen === void 0 ? void 0 : specimen.note) {
1787
+ for (const note of specimen.note) {
1788
+ textContent += note.text + '\n\n';
1789
+ }
1790
+ }
1785
1791
  return (React.createElement("div", { className: "medplum-diagnostic-report" },
1786
1792
  React.createElement("h1", null, "Diagnostic Report"),
1787
1793
  React.createElement("div", { className: "medplum-diagnostic-report-header" },
@@ -1801,8 +1807,8 @@ function DiagnosticReportDisplay(props) {
1801
1807
  diagnosticReport.status && (React.createElement("dl", null,
1802
1808
  React.createElement("dt", null, "Status"),
1803
1809
  React.createElement("dd", null, capitalize(diagnosticReport.status))))),
1804
- textContent && React.createElement("pre", null, textContent),
1805
- diagnosticReport.result && React.createElement(ObservationTable, { value: diagnosticReport.result })));
1810
+ diagnosticReport.result && React.createElement(ObservationTable, { value: diagnosticReport.result }),
1811
+ textContent && React.createElement("pre", null, textContent.trim())));
1806
1812
  }
1807
1813
  function ObservationTable(props) {
1808
1814
  var _a;
@@ -4898,6 +4904,176 @@ function ensureQuestionnaireOptionKeys(options) {
4898
4904
  return options.map((option) => (Object.assign(Object.assign({}, option), { id: option.id || generateId() })));
4899
4905
  }
4900
4906
 
4907
+ /**
4908
+ * Dynamically creates a script tag for the specified JavaScript file.
4909
+ * @param src The JavaScript file URL.
4910
+ */
4911
+ function createScriptTag(src, onload) {
4912
+ const head = document.getElementsByTagName('head')[0];
4913
+ const script = document.createElement('script');
4914
+ script.async = true;
4915
+ script.src = src;
4916
+ script.onload = onload || null;
4917
+ head.appendChild(script);
4918
+ }
4919
+
4920
+ function GoogleButton(props) {
4921
+ const medplum = useMedplum();
4922
+ const { googleClientId, handleGoogleCredential } = props;
4923
+ const parentRef = useRef(null);
4924
+ const [scriptLoaded, setScriptLoaded] = useState(typeof google !== 'undefined');
4925
+ const [initialized, setInitialized] = useState(false);
4926
+ const [buttonRendered, setButtonRendered] = useState(false);
4927
+ useEffect(() => {
4928
+ if (typeof google === 'undefined') {
4929
+ createScriptTag('https://accounts.google.com/gsi/client', () => setScriptLoaded(true));
4930
+ return;
4931
+ }
4932
+ if (!initialized) {
4933
+ google.accounts.id.initialize({
4934
+ client_id: googleClientId,
4935
+ callback: handleGoogleCredential,
4936
+ });
4937
+ setInitialized(true);
4938
+ }
4939
+ if (parentRef.current && !buttonRendered) {
4940
+ google.accounts.id.renderButton(parentRef.current, {});
4941
+ setButtonRendered(true);
4942
+ }
4943
+ }, [medplum, googleClientId, initialized, scriptLoaded, parentRef, buttonRendered, handleGoogleCredential]);
4944
+ if (!googleClientId) {
4945
+ return null;
4946
+ }
4947
+ return React.createElement("div", { ref: parentRef });
4948
+ }
4949
+ function getGoogleClientId(clientId) {
4950
+ var _a, _b;
4951
+ if (clientId) {
4952
+ return clientId;
4953
+ }
4954
+ const origin = window.location.protocol + '//' + window.location.host;
4955
+ 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 : [];
4956
+ if (authorizedOrigins.includes(origin)) {
4957
+ return "921088377005-3j1sa10vr6hj86jgmdfh2l53v3mp7lfi.apps.googleusercontent.com";
4958
+ }
4959
+ return undefined;
4960
+ }
4961
+
4962
+ /**
4963
+ * Dynamically loads the recaptcha script.
4964
+ * We do not want to load the script on page load unless the user needs it.
4965
+ */
4966
+ function initRecaptcha() {
4967
+ if (typeof grecaptcha === 'undefined') {
4968
+ createScriptTag('https://www.google.com/recaptcha/api.js?render=' + process.env.RECAPTCHA_SITE_KEY);
4969
+ }
4970
+ }
4971
+ /**
4972
+ * Starts a request to generate a recapcha token.
4973
+ * @returns Promise to a recaptcha token for the current user.
4974
+ */
4975
+ function getRecaptcha() {
4976
+ return new Promise((resolve) => {
4977
+ grecaptcha.ready(() => {
4978
+ grecaptcha.execute(process.env.RECAPTCHA_SITE_KEY, { action: 'submit' }).then(resolve);
4979
+ });
4980
+ });
4981
+ }
4982
+
4983
+ function RegisterForm(props) {
4984
+ const medplum = useMedplum();
4985
+ const googleClientId = getGoogleClientId(props.googleClientId);
4986
+ const [outcome, setOutcome] = useState();
4987
+ const issues = getIssuesForExpression(outcome, undefined);
4988
+ useEffect(initRecaptcha, []);
4989
+ function handleAuthResponse(registerRequest, partialLogin) {
4990
+ return __awaiter(this, void 0, void 0, function* () {
4991
+ try {
4992
+ let login;
4993
+ if (props.type === 'patient') {
4994
+ login = yield medplum.startNewPatient(registerRequest, partialLogin);
4995
+ }
4996
+ else {
4997
+ login = yield medplum.startNewProject(registerRequest, partialLogin);
4998
+ }
4999
+ yield medplum.processCode(login.code);
5000
+ props.onSuccess();
5001
+ }
5002
+ catch (err) {
5003
+ setOutcome(err);
5004
+ }
5005
+ });
5006
+ }
5007
+ return (React.createElement(Document, { width: 450 },
5008
+ React.createElement(Form, { style: { maxWidth: 400 }, onSubmit: (formData) => __awaiter(this, void 0, void 0, function* () {
5009
+ try {
5010
+ const recaptchaToken = yield getRecaptcha();
5011
+ const registerRequest = Object.assign(Object.assign({}, formData), { recaptchaToken });
5012
+ const userLogin = yield medplum.startNewUser(registerRequest);
5013
+ handleAuthResponse(registerRequest, userLogin);
5014
+ }
5015
+ catch (err) {
5016
+ setOutcome(err);
5017
+ }
5018
+ }) },
5019
+ React.createElement("div", { className: "medplum-center" }, props.children),
5020
+ issues && (React.createElement("div", { className: "medplum-input-error" }, issues.map((issue) => {
5021
+ var _a, _b;
5022
+ return (React.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));
5023
+ }))),
5024
+ googleClientId && (React.createElement(React.Fragment, null,
5025
+ React.createElement("div", { className: "medplum-signin-google-container" },
5026
+ React.createElement(GoogleButton, { googleClientId: googleClientId, handleGoogleCredential: (response) => __awaiter(this, void 0, void 0, function* () {
5027
+ try {
5028
+ const loginRequest = {
5029
+ googleClientId: response.clientId,
5030
+ googleCredential: response.credential,
5031
+ };
5032
+ const userLogin = yield medplum.startGoogleLogin(loginRequest);
5033
+ const googleClaims = parseJWTPayload(loginRequest.googleCredential);
5034
+ const registerRequest = {
5035
+ firstName: googleClaims.given_name,
5036
+ lastName: googleClaims.family_name,
5037
+ email: googleClaims.email,
5038
+ };
5039
+ handleAuthResponse(registerRequest, userLogin);
5040
+ }
5041
+ catch (err) {
5042
+ setOutcome(err);
5043
+ }
5044
+ }) })),
5045
+ React.createElement("div", { className: "medplum-signin-separator" }, "or"))),
5046
+ React.createElement(FormSection, { title: "First Name", htmlFor: "firstName", outcome: outcome },
5047
+ React.createElement(Input, { name: "firstName", type: "text", testid: "firstName", placeholder: "First name", required: true, autoFocus: true, outcome: outcome })),
5048
+ React.createElement(FormSection, { title: "Last Name", htmlFor: "lastName", outcome: outcome },
5049
+ React.createElement(Input, { name: "lastName", type: "text", testid: "lastName", placeholder: "Last name", required: true, outcome: outcome })),
5050
+ props.type === 'project' && (React.createElement(FormSection, { title: "Project Name", htmlFor: "projectName", outcome: outcome },
5051
+ React.createElement(Input, { name: "projectName", type: "text", testid: "projectName", placeholder: "My Project", required: true, outcome: outcome }))),
5052
+ React.createElement(FormSection, { title: "Email", htmlFor: "email", outcome: outcome },
5053
+ React.createElement(Input, { name: "email", type: "email", testid: "email", placeholder: "name@domain.com", required: true, outcome: outcome })),
5054
+ React.createElement(FormSection, { title: "Password", htmlFor: "password", outcome: outcome },
5055
+ React.createElement(Input, { name: "password", type: "password", testid: "password", autoComplete: "off", required: true, outcome: outcome })),
5056
+ React.createElement("p", { style: { fontSize: '12px', color: '#888' } },
5057
+ "By clicking submit you agree to the Medplum ",
5058
+ React.createElement("a", { href: "https://www.medplum.com/privacy" }, "Privacy\u00A0Policy"),
5059
+ ' and ',
5060
+ React.createElement("a", { href: "https://www.medplum.com/terms" }, "Terms\u00A0of\u00A0Service"),
5061
+ "."),
5062
+ React.createElement("p", { style: { fontSize: '12px', color: '#888' } },
5063
+ "This site is protected by reCAPTCHA and the Google",
5064
+ ' ',
5065
+ React.createElement("a", { href: "https://policies.google.com/privacy" }, "Privacy\u00A0Policy"),
5066
+ ' and ',
5067
+ React.createElement("a", { href: "https://policies.google.com/terms" }, "Terms\u00A0of\u00A0Service"),
5068
+ " apply."),
5069
+ React.createElement("div", { className: "medplum-signin-buttons" },
5070
+ React.createElement("div", null,
5071
+ React.createElement("input", { type: "checkbox", id: "remember", name: "remember", value: "true" }),
5072
+ React.createElement("label", { htmlFor: "remember" }, "Remember me")),
5073
+ React.createElement("div", null,
5074
+ React.createElement(Button, { type: "submit", testid: "submit" }, "Create account"))))));
5075
+ }
5076
+
4901
5077
  function StatusBadge(props) {
4902
5078
  return React.createElement("span", { className: `medplum-status medplum-status-${props.status}` }, props.status);
4903
5079
  }
@@ -5265,6 +5441,165 @@ function getVersionUrl(resource) {
5265
5441
  return `/${resource.resourceType}/${resource.id}/_history/${(_a = resource.meta) === null || _a === void 0 ? void 0 : _a.versionId}`;
5266
5442
  }
5267
5443
 
5444
+ /**
5445
+ * Returns a month display string (e.g. "January 2020").
5446
+ * @param date Any date within the month.
5447
+ * @returns The month display string (e.g. "January 2020")
5448
+ */
5449
+ function getMonthString(date) {
5450
+ return date.toLocaleString('default', { month: 'long' }) + ' ' + date.getFullYear();
5451
+ }
5452
+ function CalendarInput(props) {
5453
+ const [month, setMonth] = useState(getStartMonth);
5454
+ function moveMonth(delta) {
5455
+ setMonth((currMonth) => {
5456
+ const prevMonth = new Date(currMonth.getTime());
5457
+ prevMonth.setMonth(currMonth.getMonth() + delta);
5458
+ return prevMonth;
5459
+ });
5460
+ }
5461
+ const grid = useMemo(() => buildGrid(month, props.slots), [month, props.slots]);
5462
+ return (React.createElement("div", null,
5463
+ React.createElement(InputRow, null,
5464
+ React.createElement("p", { style: { flex: 1 } }, getMonthString(month)),
5465
+ React.createElement("p", null,
5466
+ React.createElement(Button, { label: "Previous month", onClick: () => moveMonth(-1) }, "<"),
5467
+ React.createElement(Button, { label: "Next month", onClick: () => moveMonth(1) }, ">"))),
5468
+ React.createElement("table", { className: "medplum-calendar-table" },
5469
+ React.createElement("thead", null,
5470
+ React.createElement("tr", null,
5471
+ React.createElement("th", null, "SUN"),
5472
+ React.createElement("th", null, "MON"),
5473
+ React.createElement("th", null, "TUE"),
5474
+ React.createElement("th", null, "WED"),
5475
+ React.createElement("th", null, "THU"),
5476
+ React.createElement("th", null, "FRI"),
5477
+ React.createElement("th", null, "SAT"))),
5478
+ React.createElement("tbody", null, grid.map((week, weekIndex) => (React.createElement("tr", { key: 'week-' + weekIndex }, week.map((day, dayIndex) => (React.createElement("td", { key: 'day-' + dayIndex }, day && (React.createElement("button", { disabled: !day.available, onClick: () => props.onClick(day.date) }, day.date.getDate()))))))))))));
5479
+ }
5480
+ function getStartMonth() {
5481
+ const result = new Date();
5482
+ result.setDate(1);
5483
+ result.setHours(0, 0, 0, 0);
5484
+ return result;
5485
+ }
5486
+ function buildGrid(startDate, slots) {
5487
+ const d = new Date(startDate.getFullYear(), startDate.getMonth());
5488
+ const grid = [];
5489
+ let row = [];
5490
+ // Fill leading empty days
5491
+ for (let i = 0; i < d.getDay(); i++) {
5492
+ row.push(undefined);
5493
+ }
5494
+ while (d.getMonth() === startDate.getMonth()) {
5495
+ row.push({
5496
+ date: new Date(d.getTime()),
5497
+ // available: isAvailable(d),
5498
+ available: isDayAvailable(d, slots),
5499
+ });
5500
+ if (d.getDay() === 6) {
5501
+ grid.push(row);
5502
+ row = [];
5503
+ }
5504
+ d.setDate(d.getDate() + 1);
5505
+ }
5506
+ // Fill trailing empty days
5507
+ if (d.getDay() !== 0) {
5508
+ for (let i = d.getDay(); i < 7; i++) {
5509
+ row.push(undefined);
5510
+ }
5511
+ grid.push(row);
5512
+ }
5513
+ return grid;
5514
+ }
5515
+ /**
5516
+ * Returns true if the given date is available for booking.
5517
+ * @param day The day to check.
5518
+ * @param slots The list of available slots.
5519
+ * @returns True if there are any available slots for the day.
5520
+ */
5521
+ function isDayAvailable(day, slots) {
5522
+ // Note that slot start and end time may or may not be in UTC.
5523
+ for (const slot of slots) {
5524
+ const slotStart = new Date(slot.start);
5525
+ if (slotStart.getFullYear() === day.getFullYear() &&
5526
+ slotStart.getMonth() === day.getMonth() &&
5527
+ slotStart.getDate() === day.getDate()) {
5528
+ return true;
5529
+ }
5530
+ }
5531
+ return false;
5532
+ }
5533
+
5534
+ function Scheduler(props) {
5535
+ var _a;
5536
+ const medplum = useMedplum();
5537
+ const schedule = useResource(props.schedule);
5538
+ const [slots, setSlots] = useState();
5539
+ const slotsRef = useRef();
5540
+ slotsRef.current = slots;
5541
+ const [date, setDate] = useState();
5542
+ const [slot, setSlot] = useState();
5543
+ const [info, setInfo] = useState();
5544
+ const [form, setForm] = useState();
5545
+ useEffect(() => {
5546
+ if (schedule) {
5547
+ medplum.search('Slot', 'schedule=' + getReferenceString(schedule)).then((bundle) => {
5548
+ setSlots(bundle.entry.map((entry) => entry.resource));
5549
+ });
5550
+ }
5551
+ else {
5552
+ setSlots(undefined);
5553
+ }
5554
+ }, [medplum, schedule]);
5555
+ if (!schedule || !slots) {
5556
+ return null;
5557
+ }
5558
+ const actor = (_a = schedule.actor) === null || _a === void 0 ? void 0 : _a[0];
5559
+ return (React.createElement("div", { className: "medplum-calendar-container", "data-testid": "scheduler" },
5560
+ React.createElement("div", { className: "medplum-calendar-info-pane" },
5561
+ actor && React.createElement(Avatar, { value: actor, size: "large" }),
5562
+ actor && (React.createElement("h1", null,
5563
+ React.createElement(ResourceName, { value: actor }))),
5564
+ React.createElement("p", null, "1 hour"),
5565
+ date && React.createElement("p", null, date.toLocaleDateString()),
5566
+ slot && React.createElement("p", null, formatTime(new Date(slot.start)))),
5567
+ React.createElement("div", { className: "medplum-calendar-selection-pane" },
5568
+ !date && (React.createElement("div", null,
5569
+ React.createElement("h3", null, "Select date"),
5570
+ React.createElement(CalendarInput, { slots: slots, onClick: setDate }))),
5571
+ date && !slot && (React.createElement("div", null,
5572
+ React.createElement("h3", null, "Select time"),
5573
+ slots.map((s) => {
5574
+ const slotStart = new Date(s.start);
5575
+ return (slotStart.getTime() > date.getTime() &&
5576
+ slotStart.getTime() < date.getTime() + 24 * 3600 * 1000 && (React.createElement("div", { key: s.id },
5577
+ React.createElement(Button, { style: { width: 150 }, onClick: () => setSlot(s) }, formatTime(slotStart)))));
5578
+ }))),
5579
+ date && slot && !info && (React.createElement("div", null,
5580
+ React.createElement("h3", null, "Enter your info"),
5581
+ React.createElement(FormSection, { title: "Name", htmlFor: "name" },
5582
+ React.createElement(Input, { name: "name" })),
5583
+ React.createElement(FormSection, { title: "Email", htmlFor: "email" },
5584
+ React.createElement(Input, { name: "email" })),
5585
+ React.createElement(Button, { primary: true, onClick: () => setInfo('info') }, "Next"))),
5586
+ date && slot && info && !form && (React.createElement("div", null,
5587
+ React.createElement("h3", null, "Custom questions"),
5588
+ React.createElement(FormSection, { title: "Question 1", htmlFor: "q1" },
5589
+ React.createElement(Input, { name: "q1" })),
5590
+ React.createElement(FormSection, { title: "Question 2", htmlFor: "q2" },
5591
+ React.createElement(Input, { name: "email" })),
5592
+ React.createElement(FormSection, { title: "Question 3", htmlFor: "q3" },
5593
+ React.createElement(Input, { name: "email" })),
5594
+ React.createElement(Button, { primary: true, onClick: () => setForm('form') }, "Next"))),
5595
+ date && slot && info && form && (React.createElement("div", null,
5596
+ React.createElement("h3", null, "You're all set!"),
5597
+ React.createElement("p", null, "Check your email for a calendar invite."))))));
5598
+ }
5599
+ function formatTime(date) {
5600
+ return date.toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' });
5601
+ }
5602
+
5268
5603
  function ServiceRequestTimeline(props) {
5269
5604
  return (React.createElement(ResourceTimeline, { value: props.serviceRequest, buildSearchRequests: (resource) => ({
5270
5605
  resourceType: 'Bundle',
@@ -5312,62 +5647,6 @@ function ServiceRequestTimeline(props) {
5312
5647
  }) }));
5313
5648
  }
5314
5649
 
5315
- /**
5316
- * Dynamically creates a script tag for the specified JavaScript file.
5317
- * @param src The JavaScript file URL.
5318
- */
5319
- function createScriptTag(src, onload) {
5320
- const head = document.getElementsByTagName('head')[0];
5321
- const script = document.createElement('script');
5322
- script.async = true;
5323
- script.src = src;
5324
- script.onload = onload || null;
5325
- head.appendChild(script);
5326
- }
5327
-
5328
- function GoogleButton(props) {
5329
- const medplum = useMedplum();
5330
- const { handleGoogleCredential } = props;
5331
- const googleClientId = getGoogleClientId(props.googleClientId);
5332
- const parentRef = useRef(null);
5333
- const [scriptLoaded, setScriptLoaded] = useState(typeof google !== 'undefined');
5334
- const [initialized, setInitialized] = useState(false);
5335
- const [buttonRendered, setButtonRendered] = useState(false);
5336
- useEffect(() => {
5337
- if (typeof google === 'undefined') {
5338
- createScriptTag('https://accounts.google.com/gsi/client', () => setScriptLoaded(true));
5339
- return;
5340
- }
5341
- if (!initialized) {
5342
- google.accounts.id.initialize({
5343
- client_id: googleClientId,
5344
- callback: handleGoogleCredential,
5345
- });
5346
- setInitialized(true);
5347
- }
5348
- if (parentRef.current && !buttonRendered) {
5349
- google.accounts.id.renderButton(parentRef.current, {});
5350
- setButtonRendered(true);
5351
- }
5352
- }, [medplum, googleClientId, initialized, scriptLoaded, parentRef, buttonRendered, handleGoogleCredential]);
5353
- if (!googleClientId) {
5354
- return null;
5355
- }
5356
- return React.createElement("div", { ref: parentRef });
5357
- }
5358
- function getGoogleClientId(clientId) {
5359
- var _a, _b;
5360
- if (clientId) {
5361
- return clientId;
5362
- }
5363
- const origin = window.location.protocol + '//' + window.location.host;
5364
- 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 : [];
5365
- if (authorizedOrigins.includes(origin)) {
5366
- return "921088377005-3j1sa10vr6hj86jgmdfh2l53v3mp7lfi.apps.googleusercontent.com";
5367
- }
5368
- return undefined;
5369
- }
5370
-
5371
5650
  function SignInForm(props) {
5372
5651
  const medplum = useMedplum();
5373
5652
  const [login, setLogin] = useState(undefined);
@@ -5409,6 +5688,7 @@ function SignInForm(props) {
5409
5688
  }
5410
5689
  function AuthenticationForm(props) {
5411
5690
  const medplum = useMedplum();
5691
+ const googleClientId = getGoogleClientId(props.googleClientId);
5412
5692
  const [outcome, setOutcome] = useState();
5413
5693
  const issues = getIssuesForExpression(outcome, undefined);
5414
5694
  return (React.createElement(Form, { style: { maxWidth: 400 }, onSubmit: (formData) => {
@@ -5429,6 +5709,21 @@ function AuthenticationForm(props) {
5429
5709
  var _a, _b;
5430
5710
  return (React.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));
5431
5711
  }))),
5712
+ googleClientId && (React.createElement(React.Fragment, null,
5713
+ React.createElement("div", { className: "medplum-signin-google-container" },
5714
+ React.createElement(GoogleButton, { googleClientId: googleClientId, handleGoogleCredential: (response) => {
5715
+ medplum
5716
+ .startGoogleLogin({
5717
+ clientId: props.clientId,
5718
+ scope: props.scope,
5719
+ nonce: props.nonce,
5720
+ googleClientId: response.clientId,
5721
+ googleCredential: response.credential,
5722
+ })
5723
+ .then(props.handleAuthResponse)
5724
+ .catch(setOutcome);
5725
+ } })),
5726
+ React.createElement("div", { className: "medplum-signin-separator" }, "or"))),
5432
5727
  React.createElement(FormSection, { title: "Email", htmlFor: "email", outcome: outcome },
5433
5728
  React.createElement(Input, { name: "email", type: "email", testid: "email", required: true, autoFocus: true, outcome: outcome })),
5434
5729
  React.createElement(FormSection, { title: "Password", htmlFor: "password", outcome: outcome },
@@ -5441,20 +5736,7 @@ function AuthenticationForm(props) {
5441
5736
  React.createElement("input", { type: "checkbox", id: "remember", name: "remember", value: "true" }),
5442
5737
  React.createElement("label", { htmlFor: "remember" }, "Remember me")),
5443
5738
  React.createElement("div", null,
5444
- React.createElement(Button, { type: "submit", testid: "submit" }, "Sign in"))),
5445
- React.createElement("div", { className: "medplum-signin-google-container" },
5446
- React.createElement(GoogleButton, { googleClientId: props.googleClientId, handleGoogleCredential: (response) => {
5447
- medplum
5448
- .startGoogleLogin({
5449
- clientId: props.clientId,
5450
- scope: props.scope,
5451
- nonce: props.nonce,
5452
- googleClientId: response.clientId,
5453
- googleCredential: response.credential,
5454
- })
5455
- .then(props.handleAuthResponse)
5456
- .catch(setOutcome);
5457
- } }))));
5739
+ React.createElement(Button, { type: "submit", testid: "submit" }, "Sign in")))));
5458
5740
  }
5459
5741
  function ProfileForm(props) {
5460
5742
  const medplum = useMedplum();
@@ -5526,5 +5808,5 @@ function TabSwitch(props) {
5526
5808
  })));
5527
5809
  }
5528
5810
 
5529
- export { AddressDisplay, AddressInput, AttachmentArrayDisplay, AttachmentArrayInput, AttachmentInput, Autocomplete, Avatar, BackboneElementInput, Button, Checkbox, CheckboxFormSection, CodeInput, CodeableConceptDisplay, CodeableConceptInput, ContactDetailDisplay, ContactDetailInput, ContactPointDisplay, ContactPointInput, DateTimeDisplay, DateTimeInput, DefaultResourceTimeline, DiagnosticReportDisplay, Document, ElementDefinitionInputSelector, ElementDefinitionTypeInput, EncounterTimeline, ErrorBoundary, FhirPathTable, FooterLinks, Form, FormSection, Header, HumanNameDisplay, HumanNameInput, IdentifierInput, Input, Loading, Logo, MedplumLink, MedplumProvider, MemoizedFhirPathTable, MemoizedSearchControl, MenuItem, ObservationTable, PatientTimeline, PlanDefinitionBuilder, Popup, QuestionnaireBuilder, QuestionnaireForm, QuestionnaireFormItem, QuestionnaireItemType, RangeDisplay, RangeInput, ReferenceInput, RequestGroupDisplay, ResourceArrayDisplay, ResourceArrayInput, ResourceBadge, ResourceBlame, ResourceDiff, ResourceForm, ResourceHistoryTable, ResourceInput, ResourceName, ResourcePropertyDisplay, ResourcePropertyInput, ResourceTable, ResourceTimeline, Scrollable, SearchChangeEvent, SearchClickEvent, SearchControl, SearchFieldEditor, SearchFilterEditor, SearchLoadEvent, Select, ServiceRequestTimeline, SignInForm, StatusBadge, Tab, TabList, TabPanel, TabSwitch, TextArea, Timeline, TimelineItem, TitleBar, UploadButton, addDateEqualsFilter, addDateFilter, addDateFilterBetween, addField, addFilter, addLastMonthFilter, addMissingFilter, addNextMonthFilter, addQuestionnaireInitialValues, addThisMonthFilter, addTodayFilter, addTomorrowFilter, addYearToDateFilter, addYesterdayFilter, buildFieldNameString, clearFilters, clearFiltersOnField, convertIsoToLocal, convertLocalToIso, createScriptTag, deleteFilter, formatRangeString, getOpString, getSearchOperators, getSortField, getTimeString, getValueAndType, hasFilterOnField, isChoiceQuestion, isSortDescending, movePage, parseForm, renderValue, setFilters, setOffset, setPropertyValue, setSort, sortByDateAndPriority, toggleSort, useMedplum, useMedplumContext, useMedplumProfile, useResource };
5811
+ export { AddressDisplay, AddressInput, AttachmentArrayDisplay, AttachmentArrayInput, AttachmentInput, Autocomplete, Avatar, BackboneElementInput, Button, Checkbox, CheckboxFormSection, CodeInput, CodeableConceptDisplay, CodeableConceptInput, ContactDetailDisplay, ContactDetailInput, ContactPointDisplay, ContactPointInput, DateTimeDisplay, DateTimeInput, DefaultResourceTimeline, DiagnosticReportDisplay, Document, ElementDefinitionInputSelector, ElementDefinitionTypeInput, EncounterTimeline, ErrorBoundary, FhirPathTable, FooterLinks, Form, FormSection, Header, HumanNameDisplay, HumanNameInput, IdentifierInput, Input, Loading, Logo, MedplumLink, MedplumProvider, MemoizedFhirPathTable, MemoizedSearchControl, MenuItem, ObservationTable, PatientTimeline, PlanDefinitionBuilder, Popup, QuestionnaireBuilder, QuestionnaireForm, QuestionnaireFormItem, QuestionnaireItemType, RangeDisplay, RangeInput, ReferenceInput, RegisterForm, RequestGroupDisplay, ResourceArrayDisplay, ResourceArrayInput, ResourceBadge, ResourceBlame, ResourceDiff, ResourceForm, ResourceHistoryTable, ResourceInput, ResourceName, ResourcePropertyDisplay, ResourcePropertyInput, ResourceTable, ResourceTimeline, Scheduler, Scrollable, SearchChangeEvent, SearchClickEvent, SearchControl, SearchFieldEditor, SearchFilterEditor, SearchLoadEvent, Select, ServiceRequestTimeline, SignInForm, StatusBadge, Tab, TabList, TabPanel, TabSwitch, TextArea, Timeline, TimelineItem, TitleBar, UploadButton, addDateEqualsFilter, addDateFilter, addDateFilterBetween, addField, addFilter, addLastMonthFilter, addMissingFilter, addNextMonthFilter, addQuestionnaireInitialValues, addThisMonthFilter, addTodayFilter, addTomorrowFilter, addYearToDateFilter, addYesterdayFilter, buildFieldNameString, clearFilters, clearFiltersOnField, convertIsoToLocal, convertLocalToIso, createScriptTag, deleteFilter, formatRangeString, getOpString, getRecaptcha, getSearchOperators, getSortField, getTimeString, getValueAndType, hasFilterOnField, initRecaptcha, isChoiceQuestion, isSortDescending, movePage, parseForm, renderValue, setFilters, setOffset, setPropertyValue, setSort, sortByDateAndPriority, toggleSort, useMedplum, useMedplumContext, useMedplumProfile, useResource };
5530
5812
  //# sourceMappingURL=index.js.map