mirror of
https://github.com/Foundry376/Mailspring.git
synced 2025-03-01 02:25:45 +08:00
Summary: Adding tests Test Plan: Tests Reviewers: juan, bengotow Reviewed By: bengotow Differential Revision: https://phab.nylas.com/D2892
178 lines
4.6 KiB
JavaScript
178 lines
4.6 KiB
JavaScript
import _ from 'underscore'
|
|
import moment from 'moment'
|
|
import Proposal from './proposal'
|
|
import NylasStore from 'nylas-store'
|
|
import SchedulerActions from './scheduler-actions'
|
|
import {Event, Utils} from 'nylas-exports'
|
|
import {CALENDAR_ID} from './scheduler-constants'
|
|
|
|
// moment-round upon require patches `moment` with new functions.
|
|
require('moment-round')
|
|
|
|
/**
|
|
* Maintains the creation of "Proposed Times" when scheduling with people.
|
|
*
|
|
* The proposed times are displayed in various calendar views.
|
|
*
|
|
*/
|
|
class ProposedTimeCalendarStore extends NylasStore {
|
|
DURATIONS = [
|
|
[30, 'minutes', '30 min'],
|
|
[1, 'hour', '1 hr'],
|
|
[1.5, 'hours', '1½ hr'],
|
|
[2, 'hours', '2 hr'],
|
|
[2.5, 'hours', '2½ hr'],
|
|
[3, 'hours', '3 hr'],
|
|
]
|
|
|
|
activate() {
|
|
this._proposals = []
|
|
this._resetDragBuffer();
|
|
this._pendingSave = false;
|
|
this._duration = this.DURATIONS[0] // 30 min
|
|
this.unsubscribers = [
|
|
SchedulerActions.changeDuration.listen(this._onChangeDuration),
|
|
SchedulerActions.clearProposals.listen(this._onClearProposals),
|
|
SchedulerActions.addToProposedTimeBlock.listen(this._onAddToBlock),
|
|
SchedulerActions.startProposedTimeBlock.listen(this._onStartBlock),
|
|
SchedulerActions.endProposedTimeBlock.listen(this._onEndBlock),
|
|
SchedulerActions.removeProposedTime.listen(this._onRemoveProposedTime),
|
|
]
|
|
}
|
|
|
|
pendingSave() {
|
|
return this._pendingSave
|
|
}
|
|
|
|
deactivate() {
|
|
this.unsubscribers.forEach(unsub => unsub())
|
|
}
|
|
|
|
currentDuration() {
|
|
return this._duration
|
|
}
|
|
|
|
_dragBufferAsEvent() {
|
|
if (!this._dragBuffer.anchor) {
|
|
return []
|
|
}
|
|
const {start, end} = this._dragBuffer;
|
|
const event = new Event().fromJSON({
|
|
title: "Availability Block",
|
|
calendar_id: CALENDAR_ID,
|
|
when: {
|
|
object: "timespan",
|
|
start_time: start,
|
|
end_time: end,
|
|
},
|
|
})
|
|
event.proposalType = "availability"
|
|
return [event];
|
|
}
|
|
|
|
proposalsAsEvents() {
|
|
return _.map(this._proposals, (p) => {
|
|
const event = new Event().fromJSON({
|
|
title: "Proposed Time",
|
|
calendar_id: CALENDAR_ID,
|
|
when: {
|
|
object: "timespan",
|
|
start_time: p.start,
|
|
end_time: p.end,
|
|
},
|
|
})
|
|
event.proposalType = "proposal";
|
|
return event
|
|
}).concat(this._dragBufferAsEvent());
|
|
}
|
|
|
|
_convertBufferToProposedTimes() {
|
|
const bounds = this._dragBuffer;
|
|
const minMoment = moment.unix(bounds.start);
|
|
minMoment.floor(30, 'minutes');
|
|
|
|
const maxMoment = moment.unix(bounds.end);
|
|
maxMoment.ceil(30, 'minutes');
|
|
|
|
if (maxMoment.isSame(minMoment)) {
|
|
maxMoment.add(30, 'minutes')
|
|
}
|
|
|
|
const overlapBoundsTest = {start: bounds.start, end: bounds.end - 1}
|
|
this._proposals = _.reject(this._proposals, (p) =>
|
|
Utils.overlapsBounds(overlapBoundsTest, p)
|
|
)
|
|
|
|
const blockSize = this._duration.slice(0, 2)
|
|
blockSize[0] = blockSize[0] / 1; // moment requires a number
|
|
const isMinBlockSize = (bounds.end - bounds.start) >= moment.duration.apply(moment, blockSize).as('seconds');
|
|
while (minMoment.isBefore(maxMoment)) {
|
|
const start = minMoment.unix();
|
|
minMoment.add(blockSize[0], blockSize[1]);
|
|
const end = minMoment.unix() - 1;
|
|
if (end >= bounds.end && isMinBlockSize) { break; }
|
|
this._proposals.push(new Proposal({start, end}))
|
|
}
|
|
}
|
|
|
|
_resetDragBuffer() {
|
|
this._dragBuffer = {
|
|
anchor: null,
|
|
start: Number.MAX_SAFE_INTEGER,
|
|
end: 0,
|
|
}
|
|
}
|
|
|
|
_updateDragBuffer(newT) {
|
|
const {anchor, start, end} = this._dragBuffer
|
|
this._dragBuffer = {
|
|
anchor,
|
|
start: Math.min(newT.unix(), anchor),
|
|
end: Math.max(newT.unix(), anchor),
|
|
}
|
|
if (this._dragBuffer.start !== start || this._dragBuffer.end !== end) {
|
|
this.trigger()
|
|
}
|
|
}
|
|
|
|
_onStartBlock = (newT) => {
|
|
this._resetDragBuffer();
|
|
this._dragBuffer.anchor = newT.floor(30, 'minutes').unix()
|
|
}
|
|
|
|
_onAddToBlock = (newT) => {
|
|
this._updateDragBuffer(newT.round(30, 'minutes'));
|
|
}
|
|
|
|
_onEndBlock = () => {
|
|
if (this._dragBuffer.anchor) {
|
|
this._convertBufferToProposedTimes()
|
|
this._resetDragBuffer();
|
|
this.trigger();
|
|
}
|
|
}
|
|
|
|
_onChangeDuration = (newDuration) => {
|
|
this._duration = newDuration
|
|
this.trigger()
|
|
}
|
|
|
|
_onClearProposals = () => {
|
|
this._proposals = [];
|
|
this.trigger();
|
|
}
|
|
|
|
_onRemoveProposedTime = ({start}) => {
|
|
const startInt = parseInt(start, 10);
|
|
this._proposals = _.reject(this._proposals, (p) =>
|
|
p.start <= startInt && p.end > startInt
|
|
)
|
|
this.trigger()
|
|
}
|
|
|
|
proposals() {
|
|
return this._proposals
|
|
}
|
|
}
|
|
|
|
export default new ProposedTimeCalendarStore()
|