react-availability-calendar
Version:
A customizable React component for displaying booking availabilities on a calendar.
1,207 lines (1,074 loc) • 36.9 kB
JavaScript
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