2016-02-23 07:48:07 +08:00
|
|
|
/** @babel */
|
|
|
|
import _ from 'underscore';
|
|
|
|
import React, {Component, PropTypes} from 'react';
|
2016-02-25 02:26:47 +08:00
|
|
|
import {DateUtils} from 'nylas-exports'
|
2016-02-23 07:48:07 +08:00
|
|
|
import {RetinaImg} from 'nylas-component-kit';
|
|
|
|
import SnoozeActions from './snooze-actions'
|
|
|
|
import {DATE_FORMAT_LONG} from './snooze-constants'
|
|
|
|
|
|
|
|
|
|
|
|
const SnoozeOptions = [
|
|
|
|
[
|
2016-02-25 09:56:40 +08:00
|
|
|
'Later today',
|
2016-02-23 07:48:07 +08:00
|
|
|
'Tonight',
|
|
|
|
'Tomorrow',
|
|
|
|
],
|
|
|
|
[
|
2016-02-25 09:56:40 +08:00
|
|
|
'This weekend',
|
|
|
|
'Next week',
|
|
|
|
'Next month',
|
2016-02-23 07:48:07 +08:00
|
|
|
],
|
|
|
|
]
|
|
|
|
|
|
|
|
const SnoozeDateGenerators = {
|
2016-02-25 09:56:40 +08:00
|
|
|
'Later today': DateUtils.laterToday,
|
2016-02-23 07:48:07 +08:00
|
|
|
'Tonight': DateUtils.tonight,
|
|
|
|
'Tomorrow': DateUtils.tomorrow,
|
2016-02-25 09:56:40 +08:00
|
|
|
'This weekend': DateUtils.thisWeekend,
|
|
|
|
'Next week': DateUtils.nextWeek,
|
|
|
|
'Next month': DateUtils.nextMonth,
|
2016-02-23 07:48:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
const SnoozeIconNames = {
|
2016-02-25 09:56:40 +08:00
|
|
|
'Later today': 'later',
|
2016-02-23 07:48:07 +08:00
|
|
|
'Tonight': 'tonight',
|
|
|
|
'Tomorrow': 'tomorrow',
|
2016-02-25 09:56:40 +08:00
|
|
|
'This weekend': 'weekend',
|
|
|
|
'Next week': 'week',
|
|
|
|
'Next month': 'month',
|
2016-02-23 07:48:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class SnoozePopoverBody extends Component {
|
|
|
|
static displayName = 'SnoozePopoverBody';
|
|
|
|
|
|
|
|
static propTypes = {
|
|
|
|
threads: PropTypes.array.isRequired,
|
2016-02-25 09:33:20 +08:00
|
|
|
isFixedPopover: PropTypes.bool,
|
2016-02-23 07:48:07 +08:00
|
|
|
swipeCallback: PropTypes.func,
|
2016-02-25 02:26:47 +08:00
|
|
|
closePopover: PropTypes.func,
|
2016-02-23 07:48:07 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static defaultProps = {
|
2016-02-25 09:33:20 +08:00
|
|
|
isFixedPopover: true,
|
2016-02-23 07:48:07 +08:00
|
|
|
swipeCallback: ()=> {},
|
2016-02-25 02:26:47 +08:00
|
|
|
closePopover: ()=> {},
|
2016-02-23 07:48:07 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
constructor() {
|
|
|
|
super();
|
2016-02-25 09:33:20 +08:00
|
|
|
this.didSnooze = false;
|
2016-02-23 07:48:07 +08:00
|
|
|
this.state = {
|
|
|
|
inputDate: null,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-25 09:33:20 +08:00
|
|
|
componentWillUnmount() {
|
|
|
|
this.props.swipeCallback(this.didSnooze);
|
|
|
|
}
|
|
|
|
|
2016-02-23 07:48:07 +08:00
|
|
|
onSnooze(dateGenerator) {
|
|
|
|
const utcDate = dateGenerator().utc()
|
|
|
|
const formatted = DateUtils.format(utcDate)
|
|
|
|
SnoozeActions.snoozeThreads(this.props.threads, formatted);
|
2016-02-25 09:33:20 +08:00
|
|
|
this.didSnooze = true;
|
2016-02-25 02:26:47 +08:00
|
|
|
this.props.closePopover()
|
2016-02-23 07:48:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
onBlur = ()=> {
|
2016-02-25 09:33:20 +08:00
|
|
|
if (!this.props.isFixedPopover) return;
|
2016-02-23 07:48:07 +08:00
|
|
|
if (this._focusingInput) {
|
|
|
|
this._focusingInput = false;
|
|
|
|
return;
|
|
|
|
}
|
2016-02-25 02:26:47 +08:00
|
|
|
this.props.closePopover();
|
2016-02-23 07:48:07 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
onKeyDown = (event)=> {
|
2016-02-25 09:33:20 +08:00
|
|
|
if (!this.props.isFixedPopover) return;
|
2016-02-23 07:48:07 +08:00
|
|
|
if (event.key === "Escape") {
|
2016-02-25 02:26:47 +08:00
|
|
|
this.props.closePopover();
|
2016-02-23 07:48:07 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
onInputChange = (event)=> {
|
2016-02-25 09:33:20 +08:00
|
|
|
const inputDate = DateUtils.futureDateFromString(event.target.value)
|
|
|
|
this.setState({inputDate})
|
2016-02-23 07:48:07 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
onInputKeyDown = (event)=> {
|
2016-02-25 09:33:20 +08:00
|
|
|
const {value} = event.target;
|
|
|
|
if (value.length > 0 && ["Enter", "Return"].includes(event.key)) {
|
|
|
|
const inputDate = DateUtils.futureDateFromString(value)
|
|
|
|
if (inputDate) {
|
|
|
|
this.onSnooze(()=> inputDate)
|
|
|
|
}
|
2016-02-23 07:48:07 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
onInputMouseDown = ()=> {
|
|
|
|
this._focusingInput = true;
|
|
|
|
};
|
|
|
|
|
|
|
|
renderItem = (label)=> {
|
|
|
|
const dateGenerator = SnoozeDateGenerators[label];
|
|
|
|
const iconName = SnoozeIconNames[label]
|
|
|
|
const iconPath = `nylas://thread-snooze/assets/ic-snoozepopover-${iconName}@2x.png`
|
|
|
|
return (
|
|
|
|
<div
|
|
|
|
key={label}
|
|
|
|
className="snooze-item"
|
|
|
|
onMouseDown={this.onSnooze.bind(this, dateGenerator)}>
|
|
|
|
<RetinaImg
|
|
|
|
url={iconPath}
|
2016-02-24 14:38:56 +08:00
|
|
|
mode={RetinaImg.Mode.ContentPreserve} />
|
2016-02-23 07:48:07 +08:00
|
|
|
{label}
|
|
|
|
</div>
|
|
|
|
)
|
|
|
|
};
|
|
|
|
|
|
|
|
renderRow = (options, idx)=> {
|
|
|
|
const items = _.map(options, this.renderItem)
|
|
|
|
return (
|
|
|
|
<div key={`snooze-popover-row-${idx}`} className="snooze-row">
|
|
|
|
{items}
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
renderInputRow = (inputDate)=> {
|
|
|
|
let formatted = null
|
|
|
|
if (inputDate) {
|
|
|
|
formatted = 'Snooze until ' + DateUtils.format(inputDate, DATE_FORMAT_LONG)
|
|
|
|
}
|
|
|
|
return (
|
|
|
|
<div className="snooze-input">
|
|
|
|
<input
|
|
|
|
type="text"
|
|
|
|
tabIndex="1"
|
2016-02-25 03:19:03 +08:00
|
|
|
placeholder="Or type a time, like 'next Monday at 2PM'"
|
2016-02-23 07:48:07 +08:00
|
|
|
onMouseDown={this.onInputMouseDown}
|
|
|
|
onKeyDown={this.onInputKeyDown}
|
|
|
|
onChange={this.onInputChange}/>
|
2016-02-25 07:33:13 +08:00
|
|
|
<span className="input-date-value">{formatted}</span>
|
2016-02-23 07:48:07 +08:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
render() {
|
|
|
|
const {inputDate} = this.state
|
|
|
|
const rows = SnoozeOptions.map(this.renderRow)
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div className="snooze-container" onBlur={this.onBlur} onKeyDown={this.onKeyDown}>
|
|
|
|
{rows}
|
|
|
|
{this.renderInputRow(inputDate)}
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
export default SnoozePopoverBody;
|