react-sprucebot
Version:
React components for your Sprucebot Skill 💪🏼
832 lines (662 loc) • 26.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _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; };
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _moment = require('moment');
var _moment2 = _interopRequireDefault(_moment);
var _propTypes = require('prop-types');
var _propTypes2 = _interopRequireDefault(_propTypes);
var _es6Tween = require('es6-tween');
var _Avatar = require('../Avatar/Avatar');
var _Avatar2 = _interopRequireDefault(_Avatar);
var _Button = require('../Button/Button');
var _Button2 = _interopRequireDefault(_Button);
var _Calendar = require('./Calendar');
var _Calendar2 = _interopRequireDefault(_Calendar);
var _Pager = require('../Pager/Pager');
var _Pager2 = _interopRequireDefault(_Pager);
var _Tabs = require('../Tabs/Tabs');
var _HorizontalWeek = require('./HorizontalWeek');
var _HorizontalWeek2 = _interopRequireDefault(_HorizontalWeek);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
(0, _es6Tween.autoPlay)(true);
var getElementWidth = function getElementWidth(element) {
return element && element.offsetWidth;
};
var getElementHeight = function getElementHeight(element) {
return element && element.offsetHeight;
};
var BigCalendar = function (_Component) {
_inherits(BigCalendar, _Component);
function BigCalendar(props) {
var _this2 = this;
_classCallCheck(this, BigCalendar);
var _this = _possibleConstructorReturn(this, (BigCalendar.__proto__ || Object.getPrototypeOf(BigCalendar)).call(this, props));
_this.componentDidMount = function () {
//give things a sec to settle before recording sizes
_this.refresh();
setTimeout(function () {}, 250);
window.addEventListener('resize', _this.handleWindowResize);
};
_this.componentWillUnmount = function () {
window.removeEventListener('resize', _this.handleWindowResize);
};
_this.setEvents = function (events) {
_this.setState({ events: events });
};
_this.events = function () {
return _this.state.events;
};
_this.generatePagerTitle = function (page) {
var _this$state = _this.state,
view = _this$state.view,
selectedDate = _this$state.selectedDate;
var title = void 0;
if (view === 'month') {
title = (0, _moment2.default)(selectedDate).format('MMM YYYY');
} else if (view === 'week') {
var startOfWeek = (0, _moment2.default)(selectedDate).startOf('week');
var endOfWeek = (0, _moment2.default)(selectedDate).endOf('week');
console.log({ startOfWeek: startOfWeek, endOfWeek: endOfWeek });
if (startOfWeek.isSame(endOfWeek, 'month')) {
title = startOfWeek.format('MMM Do') + ' - ' + endOfWeek.format('Do');
} else {
title = startOfWeek.format('MMM Do') + ' - ' + endOfWeek.format('MMM Do');
}
} else if (view === 'day') {
title = (0, _moment2.default)(selectedDate).format('MMM Do');
}
return title;
};
_this.getDesiredTeammateWrapperWidth = function () {
if (!_this.calendarWrapper) {
return '100%';
}
var _this$state2 = _this.state,
view = _this$state2.view,
mode = _this$state2.mode;
var teamDayViewWidth = _this.props.teamDayViewWidth;
var calendarWrapperWidth = getElementWidth(_this.calendarWrapper);
if (mode === 'team' && view === 'day') {
// make it a little thinner than the screen
return Math.min(calendarWrapperWidth - 20, teamDayViewWidth);
} else if (mode === 'team' && view === 'week') {
return '100%';
} else if (mode === 'team' && view === 'month') {
return '100%';
} else if (mode === 'user') {
return calendarWrapperWidth;
}
return 'auto';
};
_this.getDesiredScrollWidth = function () {
//act like a normal div until loaded
if (!_this.calendarWrapper) {
return '100%';
}
var _this$state3 = _this.state,
view = _this$state3.view,
mode = _this$state3.mode,
teammates = _this$state3.teammates,
transitioning = _this$state3.transitioning;
var calendarWrapperWidth = getElementWidth(_this.calendarWrapper);
var widthOfAllCalendars = 0;
var minWidthOfAllCalendars = _this.getDesiredTeammateWrapperWidth() * teammates.length;
document.querySelectorAll('.teammate_calendar__wrapper').forEach(function (wrapper) {
widthOfAllCalendars += getElementWidth(wrapper);
});
widthOfAllCalendars = Math.max(minWidthOfAllCalendars, widthOfAllCalendars);
if (transitioning && view === 'day') {
return widthOfAllCalendars;
}
if (mode === 'team' && view == 'day') {
return widthOfAllCalendars;
} else if (view === 'week') {
return calendarWrapperWidth;
} else if (view === 'month') {
return calendarWrapperWidth;
} else if (mode === 'user') {
return calendarWrapperWidth;
}
};
_this.getDesiredScrollHeight = function () {
//act like a normal div until loaded
if (!_this.calendarWrapper) {
return 'auto';
}
var _this$state4 = _this.state,
mode = _this$state4.mode,
view = _this$state4.view;
if (mode === 'team' && view === 'week') {
return 'auto';
} else if (view === 'month') {
return 'auto';
}
var firstTeammateWrapper = document.querySelector('.teammate_calendar__wrapper');
if (!firstTeammateWrapper) {
return 'auto';
}
return getElementHeight(firstTeammateWrapper) || 'auto';
};
_this.handleChange = function () {
_this.refresh();
};
_this.refresh = function () {
var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
var triggerOnNavigate = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
var _this$state5, mode, view, teammates, selectedDate, _this$props, auth, onNavigate, fetchEvents, currentView, currentUser, startDate, endDate, options, _ref2, storeSchedule, events;
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
_this$state5 = _this.state, mode = _this$state5.mode, view = _this$state5.view, teammates = _this$state5.teammates, selectedDate = _this$state5.selectedDate;
_this$props = _this.props, auth = _this$props.auth, onNavigate = _this$props.onNavigate, fetchEvents = _this$props.fetchEvents;
currentView = view === 'team_week' ? 'week' : view;
currentUser = teammates.find(function (teammate) {
return teammate.User.id === auth.UserId;
});
startDate = (0, _moment2.default)(selectedDate).startOf(currentView);
endDate = (0, _moment2.default)(selectedDate).endOf(currentView);
options = {
mode: mode,
startDate: startDate,
endDate: endDate,
view: currentView,
teammates: mode === 'user' ? currentUser : teammates
};
triggerOnNavigate && onNavigate && onNavigate(options);
_context.next = 10;
return fetchEvents(options);
case 10:
_ref2 = _context.sent;
storeSchedule = _ref2.storeSchedule;
events = _ref2.events;
_this.setState({ storeSchedule: storeSchedule, events: events });
case 14:
case 'end':
return _context.stop();
}
}
}, _callee, _this2);
}));
return function () {
return _ref.apply(this, arguments);
};
}();
_this.handlePagerChange = function () {
var _ref3 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2(page) {
var view, diff, stepType;
return regeneratorRuntime.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
view = _this.state.view;
diff = view !== 'month' ? page - _this.state.currentPage : 1;
stepType = view !== 'month' ? 'days' : 'months';
_context2.next = 5;
return _this.setState(function (prevState) {
return {
currentPage: page,
selectedDate: prevState.selectedDate.add(diff, stepType)
};
});
case 5:
_this.handleChange();
case 6:
case 'end':
return _context2.stop();
}
}
}, _callee2, _this2);
}));
return function (_x2) {
return _ref3.apply(this, arguments);
};
}();
_this.handleChangeView = function () {
var _ref4 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3(idx) {
var _this$state6, mode, view, newView, movingToWeek;
return regeneratorRuntime.wrap(function _callee3$(_context3) {
while (1) {
switch (_context3.prev = _context3.next) {
case 0:
_this$state6 = _this.state, mode = _this$state6.mode, view = _this$state6.view;
newView = _this.state.views[idx];
movingToWeek = mode === 'user' && view !== 'week' && newView === 'week';
_context3.next = 5;
return _this.setState({
view: newView,
renderFirstCalendar: !movingToWeek
});
case 5:
// because month view does not show all teammates, if we are in team mode jumping OFF month view, lets
// re-show team wrappers
if (mode === 'team' && view === 'month' && newView !== 'month') {
_this.toggleShowOnCalendars();
} else if (mode === 'user' && view !== 'week' && newView === 'week') {
// week view is heavy, give dom a sec to render before rendering calendar
_this.delayedRenderWeekView();
}
_this.handleChange();
//trigger a refresh which causes, sizes to be recalculated. 500 delay for css transitions
setTimeout(function () {
_this.handleWindowResize();
}, 500);
case 8:
case 'end':
return _context3.stop();
}
}
}, _callee3, _this2);
}));
return function (_x3) {
return _ref4.apply(this, arguments);
};
}();
_this.delayedRenderWeekView = function () {
setTimeout(function () {
_this.setState({ renderFirstCalendar: true });
}, 100);
};
_this.timeRange = function () {
var _this$state7 = _this.state,
selectedDate = _this$state7.selectedDate,
storeSchedule = _this$state7.storeSchedule;
var earliest = false;
var latest = false;
if (storeSchedule && storeSchedule.length !== 0) {
storeSchedule.forEach(function (schedule) {
var start = (0, _moment2.default)('2018-04-01 ' + schedule.startTime).subtract(2, 'hour');
var end = (0, _moment2.default)('2018-04-01 ' + schedule.endTime).add(2, 'hour');
if (!earliest || earliest.diff(start) > 0) {
earliest = (0, _moment2.default)(start);
}
if (!latest || latest.diff(end) < 0) {
latest = (0, _moment2.default)(end);
}
});
} else {
earliest = (0, _moment2.default)(selectedDate).hour(7).minutes(0).seconds(0);
latest = (0, _moment2.default)(selectedDate).hour(18).minutes(0).seconds(0);
}
return [earliest, latest];
};
_this.toggleShowOnCalendars = function () {
// show teammates calendars one at a time
var calendars = [].concat(_toConsumableArray(document.querySelectorAll('.teammate_calendar__wrapper')));
if (_this.props.auth) {
calendars.shift();
}
var delay = 100;
var delayBump = 200;
calendars.forEach(function (element) {
setTimeout(function () {
element.classList.toggle('hide');
}, delay);
delay += delayBump;
});
};
_this.jumpToTeamMode = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee4() {
return regeneratorRuntime.wrap(function _callee4$(_context4) {
while (1) {
switch (_context4.prev = _context4.next) {
case 0:
if (!_this.state.transitioning) {
_context4.next = 2;
break;
}
return _context4.abrupt('return');
case 2:
_context4.next = 4;
return _this.setState({
transitioning: true,
mode: 'team',
showAllTeammates: true,
renderAllCalendars: true
});
case 4:
_this.toggleShowOnCalendars();
_this.handleChange();
setTimeout(function () {
_this.setState({
transitioning: false
});
}, 1000);
case 7:
case 'end':
return _context4.stop();
}
}
}, _callee4, _this2);
}));
_this.jumpToUserMode = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee5() {
var view;
return regeneratorRuntime.wrap(function _callee5$(_context5) {
while (1) {
switch (_context5.prev = _context5.next) {
case 0:
if (!_this.state.transitioning) {
_context5.next = 2;
break;
}
return _context5.abrupt('return');
case 2:
//scroll calendar left
new _es6Tween.Tween({
y: _this.calendarWrapper.scrollLeft
}).to({ y: 0 }, 500).on('update', function (_ref7) {
var y = _ref7.y;
_this.calendarWrapper.scrollLeft = y;
}).easing(_es6Tween.Easing.Quadratic.Out).start();
// when jumping to week view in user mode, delay render because it's heavy
view = _this.state.view;
//first give css transitions a sec to adjust the view
_context5.next = 6;
return _this.setState({
transitioning: true,
mode: 'user',
renderFirstCalendar: view !== 'week',
showAllTeammates: view !== 'week'
});
case 6:
if (view === 'week') {
_this.delayedRenderWeekView();
}
// to hard on the client
_this.toggleShowOnCalendars();
_this.handleChange();
setTimeout(function () {
_this.setState({
renderAllCalendars: false,
showAllTeammates: false,
transitioning: false
});
}, 500);
case 10:
case 'end':
return _context5.stop();
}
}
}, _callee5, _this2);
}));
_this.handleToggleMode = function () {
var mode = _this.state.mode;
switch (mode) {
case 'team':
_this.jumpToUserMode();
break;
default:
_this.jumpToTeamMode();
break;
}
};
_this.handleWindowResize = function () {
_this.setState({
resized: _this.state.resized++
});
};
_this.filterEvents = function (events, teammate) {
var _this$state8 = _this.state,
view = _this$state8.view,
mode = _this$state8.mode;
if (mode === 'team' && view === 'month') {
return events;
}
var filteredEvents = events.filter(function (event) {
return event.userId === teammate.User.id || event.type === 'special-event';
});
return filteredEvents;
};
_this.applyClassNames = function (event) {
return { className: '' + (event.className || '') };
};
_this.handleClickEvent = function (event) {
var onClickEvent = _this.props.onClickEvent;
onClickEvent && onClickEvent(event);
};
_this.handleClickOpenSlot = function (start, end, teammate) {
var onClickOpenSlot = _this.props.onClickOpenSlot;
onClickOpenSlot && onClickOpenSlot(start, end, teammate);
};
_this.handleDropEvent = function (_ref8) {
var event = _ref8.event,
start = _ref8.start,
end = _ref8.end;
var onDropEvent = _this.props.onDropEvent;
onDropEvent && onDropEvent(event, start, end);
};
_this.handleResizeEvent = function (resizeType, _ref9) {
var event = _ref9.event,
start = _ref9.start,
end = _ref9.end;
var onResizeEvent = _this.props.onResizeEvent;
onResizeEvent && onResizeEvent(event, start, end);
};
_this.handleCanDrag = function (event) {
var canDrag = _this.props.canDrag;
if (canDrag) {
return canDrag(event);
}
};
_this.handleCanResize = function (event) {
var canResize = _this.props.canResize;
if (canResize) {
return canResize(event);
}
};
_this.state = {
currentPage: 0,
view: props.defaultView,
mode: props.defaultMode,
renderFirstCalendar: true, // the first calendar is always the logged in user
renderFirstEvents: true, // rendering events is slow, so we may defer loading them until later
renderAllCalendars: false,
renderAllEvents: false,
showAllTeammates: props.defaultMode === 'team',
transitioning: false,
selectedDate: (0, _moment2.default)(),
earliestTime: null,
latestTime: null,
teammates: props.teammates ? props.teammates : [],
views: props.supportedViews,
resized: 0,
events: [], // All events for current date range
storeSchedule: [] // Hours store is open for selected date range
// Expected event structure:
// const event = {
// title: 'My favorite event',
// className: 'shift',
// start: new Date(),
// end: new Date(),
// allDay: true,
// userId: id,
// payload: { data preserved in callback }
// }
};return _this;
}
//the earliest and latest time of all schedules
_createClass(BigCalendar, [{
key: 'render',
value: function render() {
var _this3 = this;
var _props = this.props,
auth = _props.auth,
className = _props.className,
supportedViews = _props.supportedViews,
onClickOpenSlot = _props.onClickOpenSlot;
var _state = this.state,
selectedDate = _state.selectedDate,
view = _state.view,
teammates = _state.teammates,
mode = _state.mode,
transitioning = _state.transitioning,
renderAllCalendars = _state.renderAllCalendars,
showAllTeammates = _state.showAllTeammates,
renderFirstCalendar = _state.renderFirstCalendar,
events = _state.events;
// populate views to take into account team week
var selectedView = view;
var views = {};
supportedViews.forEach(function (view) {
views[view] = true;
});
views.team_week = _HorizontalWeek2.default;
if (mode === 'team' && view === 'week') {
selectedView = 'team_week';
}
var teammateWrapperWidth = this.getDesiredTeammateWrapperWidth();
var scrollWidth = this.getDesiredScrollWidth();
var scrollHeight = this.getDesiredScrollHeight();
// format times
var formats = {
// format times in left column
timeGutterFormat: function timeGutterFormat(date) {
return _moment2.default.tz(date, auth.Location.timezone).format('h:mma');
}
// setup start and end times
};
var _timeRange = this.timeRange(),
_timeRange2 = _slicedToArray(_timeRange, 2),
min = _timeRange2[0],
max = _timeRange2[1];
// configure react-sprucebot calendar
var calendarProps = {
view: selectedView,
formats: formats,
toolbar: false,
date: selectedDate.toDate(),
min: min.toDate(),
max: max.toDate(),
selectable: onClickOpenSlot && true
};
var team = showAllTeammates ? teammates : [auth];
var classNames = (className || '') + ' ' + (mode === 'team' ? 'team' : 'user') + ' ' + (transitioning ? 'transitioning' : '') + ' ' + view;
//filter authed user out and prepend
if (view === 'month') {
team = [auth];
} else if (showAllTeammates && auth) {
team = team.filter(function (teammate) {
return teammate.User.id !== auth.User.id;
});
team = [auth].concat(_toConsumableArray(team));
}
return _react2.default.createElement(
'div',
{ className: 'big_calendar ' + classNames },
_react2.default.createElement(
_Tabs.Tabs,
{ onChange: this.handleChangeView },
_react2.default.createElement(_Tabs.TabPane, { title: 'Day' }),
_react2.default.createElement(_Tabs.TabPane, { title: 'Week' }),
_react2.default.createElement(_Tabs.TabPane, { title: 'Month' })
),
_react2.default.createElement(
'div',
{ className: 'calendar__controls' },
_react2.default.createElement(_Pager2.default, {
infinite: true,
onChange: this.handlePagerChange,
titles: this.generatePagerTitle,
jumpAmount: 7,
showStep: selectedView === 'day'
}),
_react2.default.createElement(
_Button2.default,
{ className: 'toggle-mode', onClick: this.handleToggleMode },
mode === 'team' ? 'show just me' : 'show team'
)
),
_react2.default.createElement(
'div',
{
className: 'calendars__wrapper',
ref: function ref(_ref11) {
_this3.calendarWrapper = _ref11;
}
},
_react2.default.createElement(
'div',
{
className: 'calendar__scroll',
style: { width: scrollWidth, height: scrollHeight }
},
team.map(function (teammate, idx) {
return _react2.default.createElement(
'div',
{
key: 'calendar-wrapper-' + teammate.User.id,
className: 'teammate_calendar__wrapper ' + (idx === 0 ? '' : 'hide'),
style: {
width: teammateWrapperWidth
}
},
_react2.default.createElement(
'div',
{ className: 'avatar_wrapper' },
_react2.default.createElement(_Avatar2.default, { top: true, user: teammate }),
_react2.default.createElement(
'span',
{ className: 'calendar__teammate_name' },
teammate.User.casualName
)
),
(idx === 0 && renderFirstCalendar || idx > 0 && renderAllCalendars) && _react2.default.createElement(_Calendar2.default, _extends({
className: '' + (idx === 0 && !renderFirstCalendar ? 'hide' : ''),
views: views,
events: events ? _this3.filterEvents(events, teammate) : [],
eventPropGetter: function eventPropGetter(event) {
return _this3.applyClassNames(event);
},
onSelectEvent: _this3.handleClickEvent,
onSelectSlot: function onSelectSlot(_ref10) {
var start = _ref10.start,
end = _ref10.end;
return _this3.handleClickOpenSlot(start, end, teammate);
},
onEventDrop: _this3.handleDropEvent,
onEventResize: _this3.handleResizeEvent,
canDrag: _this3.handleCanDrag,
canResize: _this3.handleCanResize,
popup: selectedView === 'month'
}, calendarProps))
);
})
)
)
);
}
}]);
return BigCalendar;
}(_react.Component);
exports.default = BigCalendar;
BigCalendar.propTypes = {
auth: _propTypes2.default.object.isRequired,
teammates: _propTypes2.default.array,
supportedViews: _propTypes2.default.array.isRequired, //NOT IMPLEMENTED
defaultView: _propTypes2.default.string.isRequired,
supportedModes: _propTypes2.default.array.isRequired, //NOT IMPLEMENTED
defaultMode: _propTypes2.default.string.isRequired,
storeSchedule: _propTypes2.default.objectOf.isRequired,
teamDayViewWidth: _propTypes2.default.number,
handleClickEvent: _propTypes2.default.func,
handleClickOpenSlot: _propTypes2.default.func,
handleDropEvent: _propTypes2.default.func,
handleResizeEvent: _propTypes2.default.func
};
BigCalendar.defaultProps = {
supportedViews: ['day', 'week', 'month'], //NOT IMPLEMENTED
defaultView: 'day',
supportedModes: ['user', 'team'], //NOT IMPLEMENTED
defaultMode: 'user',
teamDayViewWidth: 250
};