UNPKG

react-availability-calendar

Version:

A customizable React component for displaying booking availabilities on a calendar.

1,207 lines (1,074 loc) 36.9 kB
import React, { useMemo, useContext, useState, useEffect, useRef } from 'react'; function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } function createUtils(moment) { function intervalLengthMs(interval) { return interval.endDate.getTime() - interval.startDate.getTime(); } function chunkify(intervals, chunkLenMs, stepLenMs // shouldMerge = false ) { // const merged = shouldMerge ? mergeIntervals(intervals) : intervals; var res = []; for (var _iterator = intervals, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { var _ref; if (_isArray) { if (_i >= _iterator.length) break; _ref = _iterator[_i++]; } else { _i = _iterator.next(); if (_i.done) break; _ref = _i.value; } var interval = _ref; var endMs = interval.endDate.getTime(); for (var ms = interval.startDate.getTime(); ms < endMs; ms += stepLenMs) { // const msRounded = Math.floor(ms / (msInHour / 2.0)) * (msInHour / 2.0); var msRounded = ms; var chunk = { startDate: new Date(msRounded), endDate: new Date(Math.min(endMs, msRounded + chunkLenMs)) }; if (intervalLengthMs(chunk) >= chunkLenMs) { res.push(chunk); } } // if (res.length > 0 && intervalLengthMs(res[res.length - 1]) < chunkLenMs) { // const last = res.pop(); // if (res.length > 0) { // // append the too-short last chunk to previous chunk if it's there // res[res.length - 1].endDate = (last as Interval).endDate; // } // } } return res; } var msInDay = 24 * 60 * 60 * 1000; var msInHour = 1 * 60 * 60 * 1000; function rotateMs(ms, msOffset) { msOffset = msOffset > 0 ? Math.min(msInDay, msOffset) : Math.max(-msInDay, msOffset); ms = Math.min(msInDay, Math.max(0, ms)); var rotated = ms - msOffset; return rotated < 0 ? rotated + msInDay : rotated; } function rotateRangesByms(ranges, msOffset) { // make sure ranges are not overlapping var shifted = ranges.map(function (r) { return [rotateMs(r[0], msOffset) % msInDay, rotateMs(r[1], msOffset) % msInDay]; }); // if the new "midnight" happens in the middle of a range, break it into 2 var foldedRangeIndices = shifted.map(function (range, i) { return range[1] < range[0] ? i : -1; }).filter(function (i) { return i >= 0; }); for (var _iterator2 = foldedRangeIndices, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) { var _ref2; if (_isArray2) { if (_i2 >= _iterator2.length) break; _ref2 = _iterator2[_i2++]; } else { _i2 = _iterator2.next(); if (_i2.done) break; _ref2 = _i2.value; } var foldedRangeIndex = _ref2; var foldedRange = shifted[foldedRangeIndex]; shifted[foldedRangeIndex] = [-1, -1]; // mark for deletion (do not disturb indices) shifted.push([foldedRange[0], msInDay]); //start till midnight shifted.push([0, foldedRange[1]]); // beginning-of-day till end } var filtered = shifted.filter(function (r) { return r[0] >= 0; }); filtered.sort(function (a, b) { return a[0] - b[0]; }); return filtered; } function calcOffsetFromProviderTimeZoneMs(localMs, providerTimeZone) { if (!providerTimeZone) return 0; var localDate = new Date(localMs); var localDateInProviderTz = new Date(localDate.toLocaleString('en-US', { timeZone: providerTimeZone })); var offsetRoundedToNearestHour = Math.floor((localDateInProviderTz.getTime() - localDate.getTime()) / msInHour + 0.5) * msInHour; return offsetRoundedToNearestHour; } var ms_in_hour = 60 * 60 * 1000; function roundToHour(ms) { return Math.floor(ms / msInHour) * msInHour; } function formatAsDate(date) { return moment(date).format('ddd, MMM Do YYYY'); } function formatAsDateWithTime(date) { return moment(date).format('ddd, MMM Do h:mma'); } function formatAsDateJustTime(date) { return moment(date).format('h:mma'); } function formatAsMonth(date) { return moment(date).format('MMM YYYY'); } function isWeekend(date) { return [0, 6].indexOf(date.getDay()) >= 0; } function shouldIncludeDate(d, excludeWeekends, excludeFn) { return (!excludeWeekends || !isWeekend(d)) && (!excludeFn || !excludeFn(d)); } function availByIndex(days, avails, excludeWeekends, excludeFn) { return (days || []).map(function (d) { return { hasAvail: shouldIncludeDate(d, excludeWeekends, excludeFn) && avails.some(function (a) { return datesEqual(a.startDate, d); }) }; }); } function sameWeek(d1, d2) { return datesEqual(moment(d1).startOf('week').toDate(), moment(d2).startOf('week').toDate()); } function sameMonth(d1, d2) { return datesEqual(moment(d1).startOf('month').toDate(), moment(d2).startOf('month').toDate()); } function datesEqual(d1, d2) { return d1 && d2 && d1.getFullYear() === d2.getFullYear() && d1.getMonth() === d2.getMonth() && d1.getDate() === d2.getDate(); } function monthDaysForDate(date) { var startOfMonth = moment(date).startOf('month'); var endOfMonth = moment(date).endOf('month'); var startOfWeek = startOfMonth.startOf('week'); var endOfWeek = endOfMonth.endOf('week'); var numDays = endOfWeek.diff(startOfWeek, 'days') + 1; var weeks = []; var days = []; var d = startOfWeek; var numWeeks = Math.floor(numDays / 7); for (var i = 0; i < numWeeks; ++i) { var w = []; weeks.push(w); for (var j = 0; j < 7; ++j) { w.push(d.toDate()); days.push(d.toDate()); d.add(1, 'day'); } } return { weeks: weeks, days: days }; } function shouldHideWeek(selectedDate, week, viewingDayAvailabilities) { return selectedDate && !sameWeek(selectedDate, week[0]) && viewingDayAvailabilities.length > 0; } function addBlockOutBookings(blockOutPeriods, providerTimeZone, bookings, localStart, //client local start, might not be midnight localEnd //client local end midnight ) { var res = [].concat(bookings); var periodStartRoundedToDayMs = new Date(localStart.getFullYear(), localStart.getMonth(), localStart.getDate()).getTime(); var periodEndRoundedToDayMs = new Date(localEnd.getFullYear(), localEnd.getMonth(), localEnd.getDate()).getTime(); for (var i = periodStartRoundedToDayMs; i <= periodEndRoundedToDayMs; i = i + msInDay) { var tzOffsetMs = calcOffsetFromProviderTimeZoneMs(i, providerTimeZone); var blockOutPeriodsTz = rotateRangesByms(blockOutPeriods, tzOffsetMs); for (var _iterator3 = blockOutPeriodsTz, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) { var _ref3; if (_isArray3) { if (_i3 >= _iterator3.length) break; _ref3 = _iterator3[_i3++]; } else { _i3 = _iterator3.next(); if (_i3.done) break; _ref3 = _i3.value; } var period = _ref3; res.push({ startDate: new Date(i + period[0]), endDate: new Date(i + period[1]) }); } // Ensure each availability is broken up at local EOD and doesn't span days res.push({ startDate: new Date(i + msInDay - 1), endDate: new Date(i + msInDay) }); } return res; } function availabilitiesFromBookings(blockOutPeriods, providerTimeZone, bookings, now, periodStartArg, periodEnd) { var periodStartMs = Math.max(roundToHour(now.getTime()) + ms_in_hour, periodStartArg.getTime()); var periodStart = new Date(periodStartMs); if (periodEnd.getTime() <= periodStart.getTime()) { return []; } var withBlockouts = addBlockOutBookings(blockOutPeriods, providerTimeZone, bookings, periodStart, periodEnd); var sorted = withBlockouts.sort(function (a, b) { return a.startDate.getTime() - b.startDate.getTime(); }); // Mark the whole period available to start var res = [{ startDate: periodStart, endDate: periodEnd }]; for (var _iterator4 = sorted, _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) { var _ref4; if (_isArray4) { if (_i4 >= _iterator4.length) break; _ref4 = _iterator4[_i4++]; } else { _i4 = _iterator4.next(); if (_i4.done) break; _ref4 = _i4.value; } var booking = _ref4; var lastAvailability = res[res.length - 1]; var bookingStartMs = booking.startDate.getTime(); var bookingEndMs = booking.endDate.getTime(); if (!booking.startDate || !booking.endDate || bookingStartMs >= bookingEndMs) { continue; } if (bookingStartMs < lastAvailability.startDate.getTime()) { // move lastAvailability start date to be past booking end lastAvailability.startDate = new Date(Math.max(lastAvailability.startDate.getTime(), bookingEndMs)); } else if (bookingStartMs < lastAvailability.endDate.getTime()) { var saveEndDate = lastAvailability.endDate; // cut off lastAvailability before booking start lastAvailability.endDate = new Date(bookingStartMs); if (bookingEndMs < saveEndDate.getTime()) { //create new availability after booking end res.push({ startDate: new Date(bookingEndMs), endDate: saveEndDate }); } } } return res; } function toStartAndEnd(range) { var res = { startDate: range.start || range[0], endDate: range.end || range[range.length - 1] }; if (res.startDate.getTime() === res.endDate.getTime()) { res.endDate = new Date(res.endDate.getTime() + msInDay); } return res; } function monthRangeForDate(d) { return { start: moment(d).startOf('month').toDate(), end: moment(d).endOf('month').toDate() }; } return { msInHour: msInHour, datesEqual: datesEqual, formatAsMonth: formatAsMonth, sameMonth: sameMonth, formatAsDateWithTime: formatAsDateWithTime, formatAsDateJustTime: formatAsDateJustTime, formatAsDate: formatAsDate, shouldHideWeek: shouldHideWeek, availByIndex: availByIndex, addBlockOutBookings: addBlockOutBookings, availabilitiesFromBookings: availabilitiesFromBookings, toStartAndEnd: toStartAndEnd, monthRangeForDate: monthRangeForDate, monthDaysForDate: monthDaysForDate, shouldIncludeDate: shouldIncludeDate, chunkify: chunkify }; } var defaultTheme = { dayClassBase: 'rounded-circle', dayClassSelected: 'border-primary', dayClassHasAvailability: 'border-info', dayClassDefault: 'border border-default', slotsContainerStyleShow: { transition: 'transform 300ms', transform: 'scale(1)' }, slotsContainerStyleHide: { transition: 'transform 300ms', transform: 'scale(0)' }, slotContainerCloseClass: 'close', slotButtonClass: 'btn btn-primary', toolBarStyle: { flexWrap: 'nowrap', width: '100%', minHeight: 50 }, toolBarButtonsContainerClass: 'border btn-group w-100', toolBarButtonClass: 'btn', toolBarLabelClass: 'btn btn-link', requestAppointmentLabel: 'Request Appointment' }; var momentSubsetStub = { format: function format(_format) { throw new Error('not implemented'); }, startOf: function startOf(_unitOfTime) { throw new Error('not implemented'); }, endOf: function endOf(_unitOfTime) { throw new Error('not implemented'); }, add: function add(_amount, _unit) { throw new Error('not implemented'); }, diff: function diff(_b, _unitOfTime, _precise) { throw new Error('not implemented'); }, toDate: function toDate() { throw new Error('not implemented'); } }; var CalendarContext = /*#__PURE__*/ React.createContext({ moment: function moment() { return momentSubsetStub; }, utils: /*#__PURE__*/ createUtils(function () { return momentSubsetStub; }), theme: defaultTheme }); var useCalendarContext = function useCalendarContext() { return useContext(CalendarContext); }; var CalendarContextProvider = function CalendarContextProvider(_ref) { var moment = _ref.moment, theme = _ref.theme, children = _ref.children; var utils = useMemo(function () { return createUtils(moment); }, [moment]); return React.createElement(CalendarContext.Provider, { value: { moment: moment, utils: utils, theme: theme } }, children); }; function resolveStyle(style, styleProps) { if (typeof style === 'function') { return styleProps ? style(styleProps) : style({}); } return style; } function resolveClassName(className, styleProps) { if (typeof className === 'function') { return styleProps ? className(styleProps) : className({}); } return className; } function getOverride(o, defaultSpec, styleProps, _t, _u, _k) { if (o === undefined) { return { Root: defaultSpec.Root, className: resolveClassName(defaultSpec.className, styleProps), style: _extends({}, resolveStyle(defaultSpec.style, styleProps)), internalProps: defaultSpec.internalProps }; } return { Root: o.Root || defaultSpec.Root, className: resolveClassName(o.className, styleProps) || resolveClassName(defaultSpec.className, styleProps), style: _extends({}, resolveStyle(defaultSpec.style, styleProps), {}, resolveStyle(o.style, styleProps)), internalProps: _extends({}, defaultSpec.internalProps, {}, o.internalProps) }; } var DefaultToolBar = {}; var DefaultToolBarButton = {}; var DefaultWeekdays = {}; var DefaultWeekday = {}; var DefaultDayCells = {}; var DefaultDayCell = {}; var DefaultAvailabiliies = {}; var DefaultAvailSlot = {}; var defaultComponents = { ToolBar: DefaultToolBar, ToolBarButton: DefaultToolBarButton, Weekdays: DefaultWeekdays, Weekday: DefaultWeekday, DayCells: DefaultDayCells, DayCell: DefaultDayCell, Availabilities: DefaultAvailabiliies, AvailSlot: DefaultAvailSlot }; // export function getOverride<Key extends keyof Overrides>( // key: Key, // overrides: Overrides | undefined, // props?: ExtractInternalProps<Overrides[Key]>, // style?: CSSProperties // ): OverridableComponentProps< // ExtractComponentProps<Overrides[Key]>, // ExtractInternalProps<Overrides[Key]> // > { // if (overrides === undefined) { // return { Component: undefined, style, props }; // } // const o = overrides[key]; // if (o === undefined) { // return { Component: undefined, style, props }; // } // if (o.Component !== undefined) { // const Component = o.Component; // return { Component }; // } // const oStyle = o.style; // if (oStyle !== undefined) { // const o2Style = oStyle; // if (typeof o2Style === 'function') { // const o3Style = o2Style; // //TODO // } else { // return { // Component: undefined, // style: { ...style, ...o2Style }, // props: { ...props, ...o.props }, // }; // } // } // return { Component: undefined, style, props }; // } // export function getOverride<Key extends keyof Overrides>( // key: Key, // overrides: Overrides | undefined, // defaultSpec: OverridableComponentProps< // ExtractComponentProps<Overrides[Key]>, // ExtractInternalProps<Overrides[Key]>, // ExtractStyleProps<Overrides[Key]> // > // ): OverridableComponentProps< // ExtractComponentProps<Overrides[Key]>, // ExtractInternalProps<Overrides[Key]>, // ExtractStyleProps<Overrides[Key]> // > { // type ComponentProps = ExtractComponentProps<Overrides[Key]>; // if (overrides === undefined || overrides[key] === undefined) { // return { // Component: undefined, // style: defaultSpec.style, // internalProps: defaultSpec.internalProps, // }; // } // const o = overrides[key]; // if (o.Component !== undefined) { // return { Component: o.Component }; // } // return { // Component: undefined, // style: { ...defaultSpec.style, ...o.style }, // internalProps: { ...defaultSpec.internalProps, ...o.internalProps }, // }; // } function getToolBarOverride(overrides, defaultSpec) { var o = overrides ? overrides.ToolBar : undefined; return getOverride(o, defaultSpec, {}); } function getToolBarButtonOverride(overrides, defaultSpec) { var o = overrides ? overrides.ToolBarButton : undefined; return getOverride(o, defaultSpec, {}); } function getWeekdaysOverride(overrides, defaultSpec) { var o = overrides ? overrides.Weekdays : undefined; return getOverride(o, defaultSpec, {}); } function getWeekdayOverride(overrides, defaultSpec) { var o = overrides ? overrides.Weekday : undefined; return getOverride(o, defaultSpec, {}); } function getDayCellsOverride(overrides, defaultSpec) { var o = overrides ? overrides.DayCells : undefined; return getOverride(o, defaultSpec, {}); } function getDayCellOverride(overrides, defaultSpec, styleProps) { var o = overrides ? overrides.DayCell : undefined; return getOverride(o, defaultSpec, styleProps); } function getAvailsOverride(overrides, defaultSpec) { var o = overrides ? overrides.Availabilities : undefined; return getOverride(o, defaultSpec, {}); } function getAvailOverride(overrides, defaultSpec, styleProps) { var o = overrides ? overrides.AvailSlot : undefined; return getOverride(o, defaultSpec, styleProps); } var navigate = { PREVIOUS: 'PREV', NEXT: 'NEXT', TODAY: 'TODAY', DATE: 'DATE' }; var Toolbar = function Toolbar(_ref) { var messages = _ref.localizer.messages, label = _ref.label, onNavigate = _ref.onNavigate, overrides = _ref.overrides; var _useCalendarContext = useCalendarContext(), theme = _useCalendarContext.theme; var _getToolBarOverride = getToolBarOverride(overrides, { style: theme.toolBarStyle, className: theme.toolBarButtonsContainerClass }), Root = _getToolBarOverride.Root, style = _getToolBarOverride.style, className = _getToolBarOverride.className; if (Root) { return React.createElement(Root, Object.assign({}, { localizer: { messages: messages }, label: label, onNavigate: onNavigate })); } return React.createElement("div", { style: style, className: className, role: "group" }, React.createElement(ToolbarButton, { theme: theme, overrides: overrides, onClick: function onClick() { return onNavigate(navigate.TODAY); }, message: messages.today }), React.createElement(ToolbarButton, { theme: theme, overrides: overrides, onClick: function onClick() { return onNavigate(navigate.PREVIOUS); }, message: messages.previous }), React.createElement(ToolbarButton, { theme: theme, overrides: overrides, onClick: function onClick() { return onNavigate(navigate.NEXT); }, message: messages.next }), React.createElement("button", { disabled: true, className: theme.toolBarLabelClass, style: { width: 110 } }, React.createElement("span", null, label))); }; function ToolbarButton(_ref2) { var message = _ref2.message, onClick = _ref2.onClick, overrides = _ref2.overrides, theme = _ref2.theme; var _getToolBarButtonOver = getToolBarButtonOverride(overrides, { className: theme.toolBarButtonClass }), Root = _getToolBarButtonOver.Root, style = _getToolBarButtonOver.style, internalProps = _getToolBarButtonOver.internalProps, className = _getToolBarButtonOver.className; if (Root !== undefined) { return React.createElement(Root, { message: message, onClicked: onClick }); } return React.createElement("button", Object.assign({ className: className, onClick: onClick, style: style }, internalProps), message); } var weekdays = ['S', 'M', 'T', 'W', 'Th', 'F', 'Sa']; var Weekdays = function Weekdays(_ref) { var overrides = _ref.overrides; var _getWeekdaysOverride = getWeekdaysOverride(overrides, { style: { display: 'flex', justifyContent: 'flex-start', flexWrap: 'nowrap', flexDirection: 'row' } }), Root = _getWeekdaysOverride.Root, style = _getWeekdaysOverride.style; if (Root) { return React.createElement(Root, null); } var _getWeekdayOverride = getWeekdayOverride(overrides, { className: 'border border-default', style: { width: 50, height: 50, marginBottom: 10, display: 'flex', justifyContent: 'center', alignItems: 'center' } }), RootWeekday = _getWeekdayOverride.Root, classNameWeekday = _getWeekdayOverride.className, styleWeekday = _getWeekdayOverride.style; return React.createElement("div", { style: style }, weekdays.map(function (weekday) { return RootWeekday ? React.createElement(RootWeekday, { weekday: weekday }) : React.createElement("div", { className: classNameWeekday, key: weekday, style: styleWeekday }, weekday); })); }; function AvailSlot(_ref) { var theme = _ref.theme, onAvailabilitySelected = _ref.onAvailabilitySelected, s = _ref.s, formatAsDateJustTime = _ref.formatAsDateJustTime, overrides = _ref.overrides; var _getAvailOverride = getAvailOverride(overrides, { className: theme.slotButtonClass, style: { minWidth: 200 } }, { date: s.startDate }), Root = _getAvailOverride.Root, className = _getAvailOverride.className, style = _getAvailOverride.style; if (Root) { return React.createElement(Root, Object.assign({}, { theme: theme, onAvailabilitySelected: onAvailabilitySelected, s: s, formatAsDateJustTime: formatAsDateJustTime })); } return React.createElement("div", { style: { marginBottom: 10 } }, React.createElement("button", { className: className, disabled: false, // variant="contained" style: style, onClick: function onClick() { return onAvailabilitySelected({ startDate: new Date(s.startDate), endDate: new Date(s.endDate) }); } }, formatAsDateJustTime(new Date(s.startDate)))); } var AvailSlots = function AvailSlots(_ref) { var viewingDayAvailabilities = _ref.viewingDayAvailabilities, handleUnselect = _ref.handleUnselect, onAvailabilitySelected = _ref.onAvailabilitySelected, show = _ref.show, slotStepMs = _ref.slotStepMs, slotLengthMs = _ref.slotLengthMs, utils = _ref.utils, theme = _ref.theme, overrides = _ref.overrides; var _getAvailsOverride = getAvailsOverride(overrides, { style: show ? theme.slotsContainerStyleShow : theme.slotsContainerStyleHide }), Root = _getAvailsOverride.Root, style = _getAvailsOverride.style; if (Root) { return React.createElement(Root, Object.assign({}, { viewingDayAvailabilities: viewingDayAvailabilities, handleUnselect: handleUnselect, onAvailabilitySelected: onAvailabilitySelected, show: show, slotStepMs: slotStepMs, slotLengthMs: slotLengthMs, utils: utils, theme: theme })); } return React.createElement("div", { style: style }, show && React.createElement("div", { className: "mt-2 mr-1" }, React.createElement("button", { type: "button", className: theme.slotContainerCloseClass, "aria-label": "Close", style: { outline: 'none' }, onClick: handleUnselect }, React.createElement("span", { "aria-hidden": "true" }, "\xD7")), React.createElement(AddBookingFromAvailabilitySlots, { theme: theme, durationMinutes: 60, avails: viewingDayAvailabilities, onAvailabilitySelected: onAvailabilitySelected, slotLengthMs: slotLengthMs, slotStepMs: slotStepMs, utils: utils, overrides: overrides }), viewingDayAvailabilities.length > 7 && React.createElement("button", { type: "button", className: theme.slotContainerCloseClass, "aria-label": "Close", style: { outline: 'none' }, onClick: handleUnselect }, React.createElement("span", { "aria-hidden": "true" }, "\xD7")))); }; var AddBookingFromAvailabilitySlots = function AddBookingFromAvailabilitySlots(_ref2) { var avails = _ref2.avails, slotLengthMs = _ref2.slotLengthMs, slotStepMs = _ref2.slotStepMs, onAvailabilitySelected = _ref2.onAvailabilitySelected, theme = _ref2.theme, utils = _ref2.utils, overrides = _ref2.overrides; var chunkify = utils.chunkify, msInHour = utils.msInHour, formatAsDate = utils.formatAsDate, formatAsDateJustTime = utils.formatAsDateJustTime; var slots = useMemo(function () { return chunkify(avails.map(function (a) { return { startDate: a.startDate, endDate: a.endDate }; }), slotLengthMs || 1 * msInHour, slotStepMs || 0.5 * msInHour); }, [avails, msInHour, chunkify, slotLengthMs, slotStepMs]); return React.createElement("div", null, React.createElement("h4", null, theme.requestAppointmentLabel), React.createElement("h5", null, avails && avails.length > 0 ? formatAsDate(avails[0].startDate) : ''), slots.map(function (s, i) { return React.createElement(AvailSlot, Object.assign({ key: 'b_' + i }, { theme: theme, onAvailabilitySelected: onAvailabilitySelected, s: s, formatAsDateJustTime: formatAsDateJustTime, overrides: overrides })); })); }; var DayCell = function DayCell(_ref) { var date = _ref.date, shouldDisplay = _ref.shouldDisplay, dayIndexInWeek = _ref.dayIndexInWeek, weekIndexInCalRange = _ref.weekIndexInCalRange, availsByIndex = _ref.availsByIndex, selectedDate = _ref.selectedDate, handleSelected = _ref.handleSelected, moment = _ref.moment, utils = _ref.utils, theme = _ref.theme, overrides = _ref.overrides; var dayIndexInCalRange = weekIndexInCalRange * 7 + dayIndexInWeek; var isSelected = !!selectedDate && utils.datesEqual(date, selectedDate); var hasAvail = availsByIndex[dayIndexInCalRange].hasAvail; var _getDayCellOverride = getDayCellOverride(overrides, { className: theme.dayClassBase + ' ' + (selectedDate && utils.datesEqual(date, selectedDate) ? theme.dayClassSelected : availsByIndex[dayIndexInCalRange].hasAvail ? theme.dayClassHasAvailability : theme.dayClassDefault), style: { cursor: 'pointer', border: selectedDate && utils.datesEqual(date, selectedDate) ? '4px solid' : availsByIndex[dayIndexInCalRange].hasAvail ? '3px solid' : '', height: 50, width: 50, display: 'flex', justifyContent: 'center', alignItems: 'center' } }, { date: date, isSelected: isSelected, hasAvail: hasAvail }), Root = _getDayCellOverride.Root, style = _getDayCellOverride.style, className = _getDayCellOverride.className; if (Root) { return React.createElement(Root, Object.assign({}, { shouldDisplay: shouldDisplay, date: date, dayIndexInWeek: dayIndexInWeek, weekIndexInCalRange: weekIndexInCalRange, availsByIndex: availsByIndex, selectedDate: selectedDate, handleSelected: handleSelected, moment: moment, utils: utils, theme: theme })); } var styleWithHiden = shouldDisplay ? style : _extends({}, style, { visibility: 'hidden' }); return React.createElement("div", { className: className, style: styleWithHiden, onClick: function onClick() { return handleSelected(date); } }, moment(date).format('D')); }; function DayCells(_ref) { var week = _ref.week, date = _ref.date, selectedDate = _ref.selectedDate, weekIndexInCalRange = _ref.weekIndexInCalRange, handleSelected = _ref.handleSelected, availsByIndex = _ref.availsByIndex, moment = _ref.moment, utils = _ref.utils, theme = _ref.theme, overrides = _ref.overrides; var _getDayCellsOverride = getDayCellsOverride(overrides, { style: { display: 'flex', justifyContent: 'flex-start', flexWrap: 'nowrap', flexDirection: 'row' } }), Root = _getDayCellsOverride.Root, style = _getDayCellsOverride.style; if (Root) { return React.createElement(Root, Object.assign({}, { date: date, week: week, selectedDate: selectedDate, weekIndexInCalRange: weekIndexInCalRange, handleSelected: handleSelected, availsByIndex: availsByIndex, moment: moment, utils: utils, theme: theme })); } return React.createElement("div", { style: style }, week.map(function (d, j) { return React.createElement(DayCell, Object.assign({ key: 'd_' + j }, { shouldDisplay: utils.sameMonth(d, date), date: d, selectedDate: selectedDate, weekIndexInCalRange: weekIndexInCalRange, dayIndexInWeek: j, handleSelected: handleSelected, availsByIndex: availsByIndex, moment: moment, utils: utils, theme: theme, overrides: overrides })); })); } var MonthlyAvailabilityCalendar = function MonthlyAvailabilityCalendar(_ref) { var availabilities = _ref.availabilities, excludeWeekends = _ref.excludeWeekends, excludeFn = _ref.excludeFn, onAvailabilitySelected = _ref.onAvailabilitySelected, onDaySelected = _ref.onDaySelected, slotLengthMs = _ref.slotLengthMs, slotStepMs = _ref.slotStepMs, date = _ref.date, style = _ref.style, overrides = _ref.overrides; var _useCalendarContext = useCalendarContext(), moment = _useCalendarContext.moment, theme = _useCalendarContext.theme, utils = _useCalendarContext.utils; var _useState = useState(null), selectedDate = _useState[0], setSelectedDate = _useState[1]; useEffect(function () { setSelectedDate(null); onDaySelected && onDaySelected(null); }, [date]); var handleSelected = function handleSelected(date) { if (selectedDate && utils.datesEqual(date, selectedDate)) { setSelectedDate(null); onDaySelected && onDaySelected(null); } else { setSelectedDate(date); onDaySelected && onDaySelected(date); } }; var handleUnselect = function handleUnselect() { onDaySelected && onDaySelected(null); setSelectedDate(null); }; var _useMemo = useMemo(function () { return utils.monthDaysForDate(date); }, [date, utils]), days = _useMemo.days, weeks = _useMemo.weeks; var availsByIndex = useMemo(function () { return utils.availByIndex(days, availabilities, excludeWeekends || false, excludeFn); }, [days, availabilities, utils]); var viewingDayAvailabilities = useMemo(function () { if (selectedDate !== null) { if (!utils.shouldIncludeDate(selectedDate, excludeWeekends || false, excludeFn)) { return []; } return (availabilities || []).filter(function (_ref2) { var startDate = _ref2.startDate; return utils.datesEqual(startDate, selectedDate); }); } else { return []; } }, [selectedDate, availabilities, utils]); return React.createElement("div", { style: _extends({ minHeight: 368 }, style) }, React.createElement(Weekdays, { overrides: overrides }), weeks.map(function (w, i) { var hideWeek = utils.shouldHideWeek(selectedDate, w, viewingDayAvailabilities); return hideWeek ? null : React.createElement(React.Fragment, { key: 'w_' + i }, React.createElement(DayCells, Object.assign({}, { date: date, week: w, selectedDate: selectedDate, weekIndexInCalRange: i, handleSelected: handleSelected, availsByIndex: availsByIndex, moment: moment, utils: utils, theme: theme, overrides: overrides }))); }), React.createElement(AvailSlots, Object.assign({}, { show: !!selectedDate && viewingDayAvailabilities.length > 0, onAvailabilitySelected: onAvailabilitySelected, viewingDayAvailabilities: viewingDayAvailabilities, handleUnselect: handleUnselect, slotLengthMs: slotLengthMs, slotStepMs: slotStepMs, utils: utils, theme: theme, overrides: overrides }))); }; var AvailabilityCalendarComp = function AvailabilityCalendarComp(_ref) { var initialDate = _ref.initialDate, onAvailabilitySelected = _ref.onAvailabilitySelected, onDaySelected = _ref.onDaySelected, blockOutPeriods = _ref.blockOutPeriods, providerTimeZone = _ref.providerTimeZone, bookings = _ref.bookings, avails = _ref.avails, onCalRangeChange = _ref.onCalRangeChange, excludeFn = _ref.excludeFn, excludeWeekends = _ref.excludeWeekends, slotLengthMs = _ref.slotLengthMs, slotStepMs = _ref.slotStepMs, overrides = _ref.overrides; var _useCalendarContext = useCalendarContext(), moment = _useCalendarContext.moment, utils = _useCalendarContext.utils; var _useState = useState(initialDate || new Date()), now = _useState[0]; var _useState2 = useState(utils.monthRangeForDate(now)), calRange = _useState2[0], setCalRange = _useState2[1]; var _useState3 = useState(now), date = _useState3[0], setDate = _useState3[1]; var lastCalRange = useRef(null); useEffect(function () { if (lastCalRange.current !== calRange) { onCalRangeChange && onCalRangeChange(calRange); lastCalRange.current = calRange; } }, [calRange, onCalRangeChange]); var availabilities = useMemo(function () { if (avails) return avails; var startAndEnd = utils.toStartAndEnd(calRange); return utils.availabilitiesFromBookings(blockOutPeriods || [], providerTimeZone, bookings, new Date() /*now*/ , startAndEnd.startDate, startAndEnd.endDate); }, [avails, bookings, providerTimeZone, calRange, now, blockOutPeriods, utils]); var handleOnNavigate = function handleOnNavigate(navigate) { if (navigate === 'TODAY') { var today = new Date(); setDate(today); setCalRange(utils.monthRangeForDate(today)); return; } if (navigate !== 'NEXT' && navigate !== 'PREV') { return; } var newDate = moment(date).add(navigate === 'NEXT' ? 1 : -1, 'month').toDate(); setDate(newDate); setCalRange(utils.monthRangeForDate(newDate)); }; return React.createElement("div", null, React.createElement(Toolbar, { onNavigate: handleOnNavigate, label: utils.formatAsMonth(date), localizer: { messages: { today: 'Today', previous: 'Previous', next: 'Next' } }, overrides: overrides }), React.createElement(MonthlyAvailabilityCalendar, { availabilities: availabilities, excludeFn: excludeFn, excludeWeekends: excludeWeekends, date: date, onAvailabilitySelected: onAvailabilitySelected, onDaySelected: onDaySelected, slotLengthMs: slotLengthMs, slotStepMs: slotStepMs, overrides: overrides })); }; var AvailabilityCalendar = function AvailabilityCalendar(_ref2) { var moment = _ref2.moment, theme = _ref2.theme, props = _objectWithoutPropertiesLoose(_ref2, ["moment", "theme"]); return React.createElement(CalendarContextProvider, { moment: moment, theme: theme ? _extends({}, defaultTheme, {}, theme) : defaultTheme }, React.createElement(AvailabilityCalendarComp, Object.assign({}, props))); }; export { AvailSlot, AvailSlots, AvailabilityCalendar, createUtils, defaultComponents, defaultTheme, getAvailOverride, getAvailsOverride, getDayCellOverride, getDayCellsOverride, getToolBarButtonOverride, getToolBarOverride, getWeekdayOverride, getWeekdaysOverride }; //# sourceMappingURL=react-availability-calendar.esm.js.map