@medplum/react 0.9.21 → 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 +160 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/index.min.js +1 -1
- package/dist/cjs/index.min.js.map +1 -1
- package/dist/cjs/styles.css +58 -0
- package/dist/esm/index.js +161 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/index.min.js +1 -1
- package/dist/esm/index.min.js.map +1 -1
- package/dist/esm/styles.css +58 -0
- package/dist/types/index.d.ts +1 -0
- package/package.json +12 -12
package/dist/cjs/styles.css
CHANGED
|
@@ -1511,6 +1511,64 @@ div.medplum-nav-menu-container {
|
|
|
1511
1511
|
margin: 0;
|
|
1512
1512
|
}
|
|
1513
1513
|
|
|
1514
|
+
.medplum-calendar-table {
|
|
1515
|
+
width: 350px;
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1518
|
+
.medplum-calendar-table th {
|
|
1519
|
+
font-weight: normal;
|
|
1520
|
+
font-size: 11px;
|
|
1521
|
+
padding: 8px;
|
|
1522
|
+
text-align: center;
|
|
1523
|
+
}
|
|
1524
|
+
|
|
1525
|
+
.medplum-calendar-table td {
|
|
1526
|
+
padding: 2px 4px;
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
.medplum-calendar-table button {
|
|
1530
|
+
width: 44px;
|
|
1531
|
+
height: 44px;
|
|
1532
|
+
color: #0060e6;
|
|
1533
|
+
font-size: 16px;
|
|
1534
|
+
font-weight: bold;
|
|
1535
|
+
text-align: center;
|
|
1536
|
+
padding: 0;
|
|
1537
|
+
background-color: #eef5ff;
|
|
1538
|
+
border: 0;
|
|
1539
|
+
border-radius: 50%;
|
|
1540
|
+
cursor: pointer;
|
|
1541
|
+
}
|
|
1542
|
+
|
|
1543
|
+
.medplum-calendar-table button:hover {
|
|
1544
|
+
background-color: #d9e9ff;
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
.medplum-calendar-table button:disabled {
|
|
1548
|
+
background-color: white;
|
|
1549
|
+
cursor: default;
|
|
1550
|
+
color: #666;
|
|
1551
|
+
font-weight: normal;
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1554
|
+
.medplum-calendar-container {
|
|
1555
|
+
display: flex;
|
|
1556
|
+
min-height: 400px;
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1559
|
+
.medplum-calendar-info-pane {
|
|
1560
|
+
min-width: 300px;
|
|
1561
|
+
padding: 20px;
|
|
1562
|
+
border-right: 1px solid #ddd;
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
.medplum-calendar-selection-pane {
|
|
1566
|
+
min-width: 300px;
|
|
1567
|
+
padding: 20px;
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
.grecaptcha-badge { visibility: hidden; }
|
|
1571
|
+
|
|
1514
1572
|
.medplum-signin {
|
|
1515
1573
|
max-width: 400px;
|
|
1516
1574
|
}
|
package/dist/esm/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
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';
|
|
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) {
|
|
@@ -5265,6 +5265,165 @@ function getVersionUrl(resource) {
|
|
|
5265
5265
|
return `/${resource.resourceType}/${resource.id}/_history/${(_a = resource.meta) === null || _a === void 0 ? void 0 : _a.versionId}`;
|
|
5266
5266
|
}
|
|
5267
5267
|
|
|
5268
|
+
/**
|
|
5269
|
+
* Returns a month display string (e.g. "January 2020").
|
|
5270
|
+
* @param date Any date within the month.
|
|
5271
|
+
* @returns The month display string (e.g. "January 2020")
|
|
5272
|
+
*/
|
|
5273
|
+
function getMonthString(date) {
|
|
5274
|
+
return date.toLocaleString('default', { month: 'long' }) + ' ' + date.getFullYear();
|
|
5275
|
+
}
|
|
5276
|
+
function CalendarInput(props) {
|
|
5277
|
+
const [month, setMonth] = useState(getStartMonth);
|
|
5278
|
+
function moveMonth(delta) {
|
|
5279
|
+
setMonth((currMonth) => {
|
|
5280
|
+
const prevMonth = new Date(currMonth.getTime());
|
|
5281
|
+
prevMonth.setMonth(currMonth.getMonth() + delta);
|
|
5282
|
+
return prevMonth;
|
|
5283
|
+
});
|
|
5284
|
+
}
|
|
5285
|
+
const grid = useMemo(() => buildGrid(month, props.slots), [month, props.slots]);
|
|
5286
|
+
return (React.createElement("div", null,
|
|
5287
|
+
React.createElement(InputRow, null,
|
|
5288
|
+
React.createElement("p", { style: { flex: 1 } }, getMonthString(month)),
|
|
5289
|
+
React.createElement("p", null,
|
|
5290
|
+
React.createElement(Button, { label: "Previous month", onClick: () => moveMonth(-1) }, "<"),
|
|
5291
|
+
React.createElement(Button, { label: "Next month", onClick: () => moveMonth(1) }, ">"))),
|
|
5292
|
+
React.createElement("table", { className: "medplum-calendar-table" },
|
|
5293
|
+
React.createElement("thead", null,
|
|
5294
|
+
React.createElement("tr", null,
|
|
5295
|
+
React.createElement("th", null, "SUN"),
|
|
5296
|
+
React.createElement("th", null, "MON"),
|
|
5297
|
+
React.createElement("th", null, "TUE"),
|
|
5298
|
+
React.createElement("th", null, "WED"),
|
|
5299
|
+
React.createElement("th", null, "THU"),
|
|
5300
|
+
React.createElement("th", null, "FRI"),
|
|
5301
|
+
React.createElement("th", null, "SAT"))),
|
|
5302
|
+
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()))))))))))));
|
|
5303
|
+
}
|
|
5304
|
+
function getStartMonth() {
|
|
5305
|
+
const result = new Date();
|
|
5306
|
+
result.setDate(1);
|
|
5307
|
+
result.setHours(0, 0, 0, 0);
|
|
5308
|
+
return result;
|
|
5309
|
+
}
|
|
5310
|
+
function buildGrid(startDate, slots) {
|
|
5311
|
+
const d = new Date(startDate.getFullYear(), startDate.getMonth());
|
|
5312
|
+
const grid = [];
|
|
5313
|
+
let row = [];
|
|
5314
|
+
// Fill leading empty days
|
|
5315
|
+
for (let i = 0; i < d.getDay(); i++) {
|
|
5316
|
+
row.push(undefined);
|
|
5317
|
+
}
|
|
5318
|
+
while (d.getMonth() === startDate.getMonth()) {
|
|
5319
|
+
row.push({
|
|
5320
|
+
date: new Date(d.getTime()),
|
|
5321
|
+
// available: isAvailable(d),
|
|
5322
|
+
available: isDayAvailable(d, slots),
|
|
5323
|
+
});
|
|
5324
|
+
if (d.getDay() === 6) {
|
|
5325
|
+
grid.push(row);
|
|
5326
|
+
row = [];
|
|
5327
|
+
}
|
|
5328
|
+
d.setDate(d.getDate() + 1);
|
|
5329
|
+
}
|
|
5330
|
+
// Fill trailing empty days
|
|
5331
|
+
if (d.getDay() !== 0) {
|
|
5332
|
+
for (let i = d.getDay(); i < 7; i++) {
|
|
5333
|
+
row.push(undefined);
|
|
5334
|
+
}
|
|
5335
|
+
grid.push(row);
|
|
5336
|
+
}
|
|
5337
|
+
return grid;
|
|
5338
|
+
}
|
|
5339
|
+
/**
|
|
5340
|
+
* Returns true if the given date is available for booking.
|
|
5341
|
+
* @param day The day to check.
|
|
5342
|
+
* @param slots The list of available slots.
|
|
5343
|
+
* @returns True if there are any available slots for the day.
|
|
5344
|
+
*/
|
|
5345
|
+
function isDayAvailable(day, slots) {
|
|
5346
|
+
// Note that slot start and end time may or may not be in UTC.
|
|
5347
|
+
for (const slot of slots) {
|
|
5348
|
+
const slotStart = new Date(slot.start);
|
|
5349
|
+
if (slotStart.getFullYear() === day.getFullYear() &&
|
|
5350
|
+
slotStart.getMonth() === day.getMonth() &&
|
|
5351
|
+
slotStart.getDate() === day.getDate()) {
|
|
5352
|
+
return true;
|
|
5353
|
+
}
|
|
5354
|
+
}
|
|
5355
|
+
return false;
|
|
5356
|
+
}
|
|
5357
|
+
|
|
5358
|
+
function Scheduler(props) {
|
|
5359
|
+
var _a;
|
|
5360
|
+
const medplum = useMedplum();
|
|
5361
|
+
const schedule = useResource(props.schedule);
|
|
5362
|
+
const [slots, setSlots] = useState();
|
|
5363
|
+
const slotsRef = useRef();
|
|
5364
|
+
slotsRef.current = slots;
|
|
5365
|
+
const [date, setDate] = useState();
|
|
5366
|
+
const [slot, setSlot] = useState();
|
|
5367
|
+
const [info, setInfo] = useState();
|
|
5368
|
+
const [form, setForm] = useState();
|
|
5369
|
+
useEffect(() => {
|
|
5370
|
+
if (schedule) {
|
|
5371
|
+
medplum.search('Slot', 'schedule=' + getReferenceString(schedule)).then((bundle) => {
|
|
5372
|
+
setSlots(bundle.entry.map((entry) => entry.resource));
|
|
5373
|
+
});
|
|
5374
|
+
}
|
|
5375
|
+
else {
|
|
5376
|
+
setSlots(undefined);
|
|
5377
|
+
}
|
|
5378
|
+
}, [medplum, schedule]);
|
|
5379
|
+
if (!schedule || !slots) {
|
|
5380
|
+
return null;
|
|
5381
|
+
}
|
|
5382
|
+
const actor = (_a = schedule.actor) === null || _a === void 0 ? void 0 : _a[0];
|
|
5383
|
+
return (React.createElement("div", { className: "medplum-calendar-container", "data-testid": "scheduler" },
|
|
5384
|
+
React.createElement("div", { className: "medplum-calendar-info-pane" },
|
|
5385
|
+
actor && React.createElement(Avatar, { value: actor, size: "large" }),
|
|
5386
|
+
actor && (React.createElement("h1", null,
|
|
5387
|
+
React.createElement(ResourceName, { value: actor }))),
|
|
5388
|
+
React.createElement("p", null, "1 hour"),
|
|
5389
|
+
date && React.createElement("p", null, date.toLocaleDateString()),
|
|
5390
|
+
slot && React.createElement("p", null, formatTime(new Date(slot.start)))),
|
|
5391
|
+
React.createElement("div", { className: "medplum-calendar-selection-pane" },
|
|
5392
|
+
!date && (React.createElement("div", null,
|
|
5393
|
+
React.createElement("h3", null, "Select date"),
|
|
5394
|
+
React.createElement(CalendarInput, { slots: slots, onClick: setDate }))),
|
|
5395
|
+
date && !slot && (React.createElement("div", null,
|
|
5396
|
+
React.createElement("h3", null, "Select time"),
|
|
5397
|
+
slots.map((s) => {
|
|
5398
|
+
const slotStart = new Date(s.start);
|
|
5399
|
+
return (slotStart.getTime() > date.getTime() &&
|
|
5400
|
+
slotStart.getTime() < date.getTime() + 24 * 3600 * 1000 && (React.createElement("div", { key: s.id },
|
|
5401
|
+
React.createElement(Button, { style: { width: 150 }, onClick: () => setSlot(s) }, formatTime(slotStart)))));
|
|
5402
|
+
}))),
|
|
5403
|
+
date && slot && !info && (React.createElement("div", null,
|
|
5404
|
+
React.createElement("h3", null, "Enter your info"),
|
|
5405
|
+
React.createElement(FormSection, { title: "Name", htmlFor: "name" },
|
|
5406
|
+
React.createElement(Input, { name: "name" })),
|
|
5407
|
+
React.createElement(FormSection, { title: "Email", htmlFor: "email" },
|
|
5408
|
+
React.createElement(Input, { name: "email" })),
|
|
5409
|
+
React.createElement(Button, { primary: true, onClick: () => setInfo('info') }, "Next"))),
|
|
5410
|
+
date && slot && info && !form && (React.createElement("div", null,
|
|
5411
|
+
React.createElement("h3", null, "Custom questions"),
|
|
5412
|
+
React.createElement(FormSection, { title: "Question 1", htmlFor: "q1" },
|
|
5413
|
+
React.createElement(Input, { name: "q1" })),
|
|
5414
|
+
React.createElement(FormSection, { title: "Question 2", htmlFor: "q2" },
|
|
5415
|
+
React.createElement(Input, { name: "email" })),
|
|
5416
|
+
React.createElement(FormSection, { title: "Question 3", htmlFor: "q3" },
|
|
5417
|
+
React.createElement(Input, { name: "email" })),
|
|
5418
|
+
React.createElement(Button, { primary: true, onClick: () => setForm('form') }, "Next"))),
|
|
5419
|
+
date && slot && info && form && (React.createElement("div", null,
|
|
5420
|
+
React.createElement("h3", null, "You're all set!"),
|
|
5421
|
+
React.createElement("p", null, "Check your email for a calendar invite."))))));
|
|
5422
|
+
}
|
|
5423
|
+
function formatTime(date) {
|
|
5424
|
+
return date.toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' });
|
|
5425
|
+
}
|
|
5426
|
+
|
|
5268
5427
|
function ServiceRequestTimeline(props) {
|
|
5269
5428
|
return (React.createElement(ResourceTimeline, { value: props.serviceRequest, buildSearchRequests: (resource) => ({
|
|
5270
5429
|
resourceType: 'Bundle',
|
|
@@ -5526,5 +5685,5 @@ function TabSwitch(props) {
|
|
|
5526
5685
|
})));
|
|
5527
5686
|
}
|
|
5528
5687
|
|
|
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 };
|
|
5688
|
+
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, 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, getSearchOperators, getSortField, getTimeString, getValueAndType, hasFilterOnField, isChoiceQuestion, isSortDescending, movePage, parseForm, renderValue, setFilters, setOffset, setPropertyValue, setSort, sortByDateAndPriority, toggleSort, useMedplum, useMedplumContext, useMedplumProfile, useResource };
|
|
5530
5689
|
//# sourceMappingURL=index.js.map
|