UNPKG

geecko-react-appointment-picker

Version:

A React component to pick appointments.

448 lines (425 loc) 22.5 kB
'use strict'; function ___$insertStyle(css) { if (!css) { return; } if (typeof window === 'undefined') { return; } var style = document.createElement('style'); style.setAttribute('type', 'text/css'); style.innerHTML = css; document.head.appendChild(style); return css; } Object.defineProperty(exports, '__esModule', { value: true }); function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } var React = require('react'); var React__default = _interopDefault(React); ___$insertStyle(".blank {\n height: 2rem;\n width: 7rem;\n}\n\n.loader {\n position: absolute;\n height: 100%;\n width: 100%;\n display: flex;\n background: rgba(240, 240, 240, 0.9);\n z-index: \"2\";\n justify-content: center;\n align-items: center;\n}\n\n.appointment-content {\n position: relative;\n overflow: hidden;\n margin: 0 auto;\n}\n\n.appointment-picker {\n display: flex;\n flex-direction: row;\n text-align: center;\n justify-content: center;\n align-items: center;\n width: max-content;\n}\n.appointment-picker > *:not(:last-child) {\n margin-right: 0.2rem;\n}\n.appointment-picker__col {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-items: center;\n}\n.appointment-picker__col > *:not(:last-child) {\n margin-bottom: 0.2rem;\n}\n.appointment-picker__col__name {\n font-weight: normal;\n height: 2rem;\n width: 2rem;\n display: flex;\n justify-content: center;\n align-items: center;\n text-align: center;\n color: #9E9E9E;\n}\n.appointment-picker__col--enabled:hover {\n background-color: #F5F5F5;\n}\n.appointment-picker__col--selected {\n background-color: #F5F5F5;\n}\n.appointment-picker__col--enabled:hover > .appointment-picker__col__number {\n font-weight: 600;\n}\n.appointment-picker__col--selected > .appointment-picker__col__number {\n font-weight: 600;\n}\n\n.appointment {\n background-color: #4FC3F7;\n width: 7rem;\n color: #fff;\n display: flex;\n justify-content: center;\n align-items: center;\n border-radius: 0.4rem;\n}\n.appointment__time {\n font-size: 1rem;\n}\n.appointment--enabled {\n cursor: pointer;\n}\n.appointment--enabled:hover {\n background-color: #03A9F4;\n}\n.appointment--selected {\n cursor: pointer;\n background-color: #4CAF50;\n}\n.appointment--reserved {\n cursor: not-allowed;\n background-color: #E0E0E0;\n}"); /*! ***************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ /* global Reflect, Promise */ var extendStatics = function(d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); }; function __extends(d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); } var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; function __values(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); } var DayNumber = /** @class */ (function (_super) { __extends(DayNumber, _super); function DayNumber() { return _super !== null && _super.apply(this, arguments) || this; } DayNumber.prototype.render = function () { return this.props.visible ? (React__default.createElement("div", { className: 'appointment-picker__col__name' }, this.props.dayNumber)) : null; }; return DayNumber; }(React.Component)); var Day = /** @class */ (function (_super) { __extends(Day, _super); function Day() { return _super !== null && _super.apply(this, arguments) || this; } Day.prototype.render = function () { var _a = this.props, visible = _a.visible, dayNumber = _a.dayNumber, isSelected = _a.isSelected; var className = 'appointment-picker__col' + (isSelected ? ' appointment-picker__col--selected' : ' appointment-picker__col--enabled'); return (React__default.createElement("div", { className: className }, React__default.createElement(DayNumber, { dayNumber: dayNumber, visible: visible }), this.props.children)); }; return Day; }(React.Component)); var Appointment = /** @class */ (function (_super) { __extends(Appointment, _super); function Appointment() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.handleClick = function () { !_this.props.isReserved && !_this.props.isOptioned && _this.props.selectAppointment(); }; return _this; } Appointment.prototype.render = function () { var _a = this.props, isSelected = _a.isSelected, isEnabled = _a.isEnabled, isReserved = _a.isReserved, isOptioned = _a.isOptioned, periods = _a.periods; var className = 'appointment' + (isSelected ? ' appointment--selected' : '') + (!isSelected && isEnabled && !isReserved ? ' appointment--enabled' : '') + (isOptioned ? ' appointment--optioned' : '') + (isReserved ? ' appointment--reserved' : ''); var style = { height: "calc(2rem*" + (periods || 1) + " + 0.2rem*(" + (periods || 1) + " - 1))" }; return (React__default.createElement("div", { style: style, className: className, onClick: this.handleClick }, React__default.createElement("span", { className: 'appointment__time' }, this.props.time))); }; Appointment.defaultProps = { isSelected: false }; return Appointment; }(React.Component)); var Blank = /** @class */ (function (_super) { __extends(Blank, _super); function Blank() { return _super !== null && _super.apply(this, arguments) || this; } Blank.prototype.render = function () { return React__default.createElement("div", { className: 'blank' }); }; return Blank; }(React.Component)); var AppointmentPicker = /** @class */ (function (_super) { __extends(AppointmentPicker, _super); function AppointmentPicker(props) { var _this = _super.call(this, props) || this; _this.getAlreadySelectedAppointments = function () { var selectedAppointments = new Map(); var size = 0; var _a = _this.props, maxReservableAppointments = _a.maxReservableAppointments, alpha = _a.alpha, selectedByDefault = _a.selectedByDefault, initialDay = _a.initialDay, unitTime = _a.unitTime, local = _a.local, localeTimeOptions = _a.localeTimeOptions; if (selectedByDefault) { _this.props.days.forEach(function (day, index) { var actualDay = new Date(initialDay.getTime() + 60 * 60 * 24 * 1000 * index); var dayNumber = alpha ? actualDay.toLocaleDateString(local, { weekday: 'long' }) : actualDay.toLocaleDateString(local); var key = 0; day.forEach(function (appointment, _) { if (appointment === null) { key = key + 1; } else if (appointment.isSelected) { var time = new Date(actualDay.getTime() + unitTime * key).toLocaleTimeString(local, localeTimeOptions); var appointmentAlreadySelected = _this.includeAppointment(selectedAppointments, dayNumber, appointment.number); if (size < maxReservableAppointments && !appointmentAlreadySelected) { _this.addAppointment(selectedAppointments, dayNumber, appointment.number, time, appointment.id); size = size + 1; } } }); }); } return { selectedAppointments: selectedAppointments, size: size }; }; _this.includeAppointment = function (selectedAppointments, day, number) { var currentDay = selectedAppointments.get(day); if (currentDay) { return !!currentDay.get(number); } return false; }; _this.addAppointment = function (selectedAppointments, day, number, time, id) { var currentDay = selectedAppointments.get(day); if (currentDay) { var currentAppointment = currentDay.get(number); if (!currentAppointment) { currentDay.set(number, { id: id, time: time }); } } else { selectedAppointments.set(day, new Map([ [ number, { id: id, time: time } ] ])); } }; _this.deleteAppointment = function (day, number) { var selectedAppointments = _this.state.selectedAppointments; var currentDay = selectedAppointments.get(day); if (currentDay) { currentDay["delete"](number); if (!(currentDay.size > 0)) { selectedAppointments["delete"](day); } } }; _this.acceptSelection = function (day, number, time, id) { var _a = _this.state, selectedAppointments = _a.selectedAppointments, size = _a.size; var maxReservableAppointments = _this.props.maxReservableAppointments; if (size < maxReservableAppointments) { _this.addAppointment(selectedAppointments, day, number, time, id); _this.setState({ size: size + 1 }); } }; _this.acceptDeselection = function (day, number) { var size = _this.state.size; _this.deleteAppointment(day, number); _this.setState({ size: size - 1 }); }; _this.selectAppointment = function (day, number, time, id) { var selectedAppointments = _this.state.selectedAppointments; var size = _this.state.size; var _a = _this.props, maxReservableAppointments = _a.maxReservableAppointments, addAppointmentCallback = _a.addAppointmentCallback, removeAppointmentCallback = _a.removeAppointmentCallback, continuous = _a.continuous; var appointmentAlreadySelected = _this.includeAppointment(selectedAppointments, day, number); if (size < maxReservableAppointments) { if (!appointmentAlreadySelected) { addAppointmentCallback({ addedAppointment: { day: day, number: number, time: time, id: id }, addCb: _this.acceptSelection }); } else { removeAppointmentCallback({ day: day, number: number, time: time, id: id }, _this.acceptDeselection); } } else { var currentDay = selectedAppointments.get(day); if (currentDay && appointmentAlreadySelected) { removeAppointmentCallback({ day: day, number: number, time: time, id: id }, _this.acceptDeselection); } else if (continuous) { var auxDay = selectedAppointments.keys().next().value; var auxDayInstance = selectedAppointments.get(auxDay); var auxNumber = auxDayInstance.keys().next().value; var auxNumberInstance = auxDayInstance.get(auxNumber); addAppointmentCallback({ addedAppointment: { day: day, number: number, time: time, id: id }, addCb: _this.acceptSelection, removedAppointment: { day: auxDay, number: auxNumber, time: auxNumberInstance.time, id: auxNumberInstance.id }, removeCb: _this.acceptDeselection }); } } }; var days = props.days; var _a = _this.getAlreadySelectedAppointments(), selectedAppointments = _a.selectedAppointments, size = _a.size; var dayPeriods = days.map(function (day) { var periods = 0; day.forEach(function (obj) { periods = obj ? obj.periods ? periods + obj.periods : periods + 1 : periods + 1; }); return periods; }); _this.state = { selectedAppointments: selectedAppointments, size: size, dayPeriods: dayPeriods, dayLength: Math.max.apply(null, dayPeriods) }; return _this; } AppointmentPicker.getDerivedStateFromProps = function (props, state) { var e_1, _a, e_2, _b; var currentSelectedAppointments = state.selectedAppointments; if (props.maxReservableAppointments < state.size) { var sum = 0; var selectedAppointments = new Map(); try { for (var _c = __values(currentSelectedAppointments.keys()), _d = _c.next(); !_d.done; _d = _c.next()) { var currentDay = _d.value; var day = currentSelectedAppointments.get(currentDay); var lengthByDay = day ? day.size : 0; if (sum + lengthByDay < props.maxReservableAppointments) { selectedAppointments.set(currentDay, day); } else { var dif = props.maxReservableAppointments - sum; var i = 0; if (day) { try { for (var _e = (e_2 = void 0, __values(day.keys())), _f = _e.next(); !_f.done; _f = _e.next()) { var currentNumber = _f.value; if (i < dif) day["delete"](currentNumber); i++; } } catch (e_2_1) { e_2 = { error: e_2_1 }; } finally { try { if (_f && !_f.done && (_b = _e["return"])) _b.call(_e); } finally { if (e_2) throw e_2.error; } } } selectedAppointments.set(currentDay, day); return { selectedAppointments: selectedAppointments, size: props.maxReservableAppointments }; } sum = sum + lengthByDay; } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (_d && !_d.done && (_a = _c["return"])) _a.call(_c); } finally { if (e_1) throw e_1.error; } } } return null; }; AppointmentPicker.prototype.shouldComponentUpdate = function (nextProps, nextState) { return (nextState.selectedAppointments !== this.state.selectedAppointments || this.props.loading !== nextProps.loading); }; AppointmentPicker.prototype.render = function () { return (React__default.createElement("div", { className: 'appointment-content' }, React__default.createElement("div", { className: this.props.loading ? 'loader' : undefined }), React__default.createElement("div", { className: 'appointment-picker' }, this.renderDays()))); }; AppointmentPicker.prototype.renderDays = function () { var _this = this; var _a = this.state, appointments = _a.selectedAppointments, dayPeriods = _a.dayPeriods; var _b = this.props, alpha = _b.alpha, visible = _b.visible, initialDay = _b.initialDay, local = _b.local; return this.props.days.map(function (day, index) { var actualDay = new Date(initialDay.getTime() + 60 * 60 * 24 * 1000 * index); /* const options = { weekday: 'long' year: 'numeric', month: 'long', day: 'numeric' } */ var dayNumber = alpha ? actualDay.toLocaleDateString(local, { weekday: 'long' }) : actualDay.toLocaleDateString(local); var isSelected = !!appointments.get(dayNumber); var props = { visible: visible, dayNumber: dayNumber, isSelected: isSelected, selectedAppointment: null, appointments: day, selectAppointment: _this.selectAppointment }; return (React__default.createElement(Day, __assign({ key: index }, props), _this.renderAppointments(day, dayNumber, isSelected, dayPeriods[index], actualDay))); }); }; AppointmentPicker.prototype.renderAppointments = function (appointments, dayNumber, isDaySelected, periods, actualDay) { var _this = this; var _a = this.state, selectedAppointments = _a.selectedAppointments, size = _a.size, dayLength = _a.dayLength; var _b = this.props, maxReservableAppointments = _b.maxReservableAppointments, unitTime = _b.unitTime, local = _b.local, localeTimeOptions = _b.localeTimeOptions, continuous = _b.continuous; var blanks = new Array(dayLength - periods > 0 ? dayLength - periods : 0).fill(0); var key = 0; var day = appointments.map(function (appointment) { if (appointment === null) { key = key + 1; return React__default.createElement(Blank, { key: key }); } var time = new Date(actualDay.getTime() + unitTime * key).toLocaleTimeString(local, localeTimeOptions); var isSelected = isDaySelected && _this.includeAppointment(selectedAppointments, dayNumber, appointment.number); var props = { isSelected: isSelected, isReserved: appointment.isReserved, isOptioned: appointment.isOptioned, isEnabled: size < maxReservableAppointments || continuous, selectAppointment: _this.selectAppointment.bind(_this, dayNumber, appointment.number, time, appointment.id), appointmentNumber: time, periods: appointment.periods ? appointment.periods : 1, time: time }; key = key + (appointment ? (appointment.periods ? appointment.periods : 1) : 1); return React__default.createElement(Appointment, __assign({ key: key }, props)); }); if (blanks.length > 0) { blanks.forEach(function (_, index) { day.push(React__default.createElement(Blank, { key: (key + index + 1) * 2 })); }); } return day; }; AppointmentPicker.defaultProps = { addAppointmentCallback: function (_a) { var _b = _a.addedAppointment, day = _b.day, number = _b.number, time = _b.time, id = _b.id, addCb = _a.addCb; console.log("Added appointment " + number + ", day " + day + ", time " + time + ", id " + id); addCb(day, number, time, id); }, removeAppointmentCallback: function (_a, removeCb) { var day = _a.day, number = _a.number, time = _a.time, id = _a.id; console.log("Removed appointment " + number + ", day " + day + ", time " + time + ", id " + id); removeCb(day, number); }, maxReservableAppointments: 0, initialDay: new Date(), unitTime: 15 * 60 * 1000, local: 'en-US', localeTimeOptions: {} }; return AppointmentPicker; }(React.Component)); exports.AppointmentPicker = AppointmentPicker; //# sourceMappingURL=index.js.map