feat(snooze): Add snooze date label to snooze threads

- Adds a new InjectedComponentSet for the role 'ThreadList:Label'.
- Adds a new label to the thread list indicating the snooze date if the
  thread has been snoozed
- Coerces MailLabel to achieve this. This is a temporary hack, we should
  design a better view to display snooze date information
This commit is contained in:
Juan Tejada 2016-02-25 13:06:01 -08:00
parent f75eddb518
commit f22fdbae49
12 changed files with 107 additions and 18 deletions

View file

@ -80,7 +80,13 @@ c3 = new ListTabular.Column
labels.push c3LabelComponentCache[label.id]
<span className="details">
{labels}
<InjectedComponentSet
inline
containerRequired={false}
children={labels}
matching={role: "ThreadList:Label"}
className="thread-injected-mail-labels"
exposedProps={thread: thread}/>
<span className="subject">{subject(thread.subject)}</span>
<span className="snippet">{thread.snippet}</span>
{attachment}
@ -148,7 +154,13 @@ cNarrow = new ListTabular.Column
<div className="snippet-and-labels">
<div className="snippet">{thread.snippet}&nbsp;</div>
<div style={flex: 1, flexShrink: 1}></div>
{labels}
<InjectedComponentSet
inline
containerRequired={false}
children={labels}
matching={role: "ThreadList:Label"}
className="thread-injected-mail-labels-narrow"
exposedProps={thread: thread}/>
</div>
</div>

View file

@ -239,6 +239,9 @@
.thread-injected-icons {
vertical-align: top;
}
.thread-injected-mail-labels {
margin-right: 6px;
}
.thread-icon {
width:25px;
height:24px;

View file

@ -1,21 +1,24 @@
/** @babel */
import {ComponentRegistry} from 'nylas-exports';
import {ToolbarSnooze, BulkThreadSnooze} from './toolbar-components';
import QuickActionSnoozeButton from './quick-action-snooze-button'
import {ToolbarSnooze, BulkThreadSnooze} from './snooze-toolbar-components';
import SnoozeQuickActionButton from './snooze-quick-action-button'
import SnoozeMailLabel from './snooze-mail-label'
import SnoozeStore from './snooze-store'
export function activate() {
this.snoozeStore = new SnoozeStore()
ComponentRegistry.register(ToolbarSnooze, {role: 'message:Toolbar'});
ComponentRegistry.register(QuickActionSnoozeButton, {role: 'ThreadListQuickAction'});
ComponentRegistry.register(SnoozeQuickActionButton, {role: 'ThreadListQuickAction'});
ComponentRegistry.register(BulkThreadSnooze, {role: 'thread:BulkAction'});
ComponentRegistry.register(SnoozeMailLabel, {role: 'ThreadList:Label'});
}
export function deactivate() {
ComponentRegistry.unregister(ToolbarSnooze);
ComponentRegistry.unregister(QuickActionSnoozeButton);
ComponentRegistry.unregister(SnoozeQuickActionButton);
ComponentRegistry.unregister(BulkThreadSnooze);
ComponentRegistry.unregister(SnoozeMailLabel);
this.snoozeStore.deactivate()
}

View file

@ -5,4 +5,4 @@ export const PLUGIN_ID = plugin.appId[NylasEnv.config.get("env")];
export const PLUGIN_NAME = "Snooze Plugin"
export const SNOOZE_CATEGORY_NAME = "N1-Snoozed"
export const DATE_FORMAT_LONG = 'ddd, MMM D, YYYY h:mmA'
export const DATE_FORMAT_SHORT = 'MMM D h:mmA'
export const DATE_FORMAT_SHORT = 'MMM D, h:mmA'

View file

@ -0,0 +1,44 @@
import _ from 'underscore';
import React, {Component, PropTypes} from 'react';
import {RetinaImg, MailLabel} from 'nylas-component-kit';
import {SNOOZE_CATEGORY_NAME, PLUGIN_ID} from './snooze-constants';
import {snoozeMessage} from './snooze-utils';
class SnoozeMailLabel extends Component {
static displayName = 'SnoozeMailLabel';
static propTypes = {
thread: PropTypes.object,
};
render() {
const {thread} = this.props;
if (_.findWhere(thread.categories, {displayName: SNOOZE_CATEGORY_NAME})) {
const metadata = thread.metadataForPluginId(PLUGIN_ID);
if (metadata) {
// TODO this is such a hack
const {snoozeDate} = metadata;
const message = snoozeMessage(snoozeDate).replace('Snoozed', '')
const content = (
<span className="snooze-mail-label">
<RetinaImg
name="icon-snoozed.png"
mode={RetinaImg.Mode.ContentIsMask} />
<span className="date-message">{message}</span>
</span>
)
const label = {
displayName: content,
isLockedCategory: ()=> true,
hue: ()=> 259,
}
return <MailLabel label={label} key={'snooze-message-' + thread.id} />;
}
return <span />
}
return <span />
}
}
export default SnoozeMailLabel;

View file

@ -1,7 +1,7 @@
/** @babel */
import _ from 'underscore';
import {Actions, NylasAPI, AccountStore} from 'nylas-exports';
import {moveThreadsToSnooze} from './snooze-category-helpers';
import {moveThreadsToSnooze, moveThreadsFromSnooze} from './snooze-utils';
import {PLUGIN_ID, PLUGIN_NAME} from './snooze-constants';
import SnoozeActions from './snooze-actions';
@ -40,6 +40,7 @@ class SnoozeStore {
})
})
.catch((error)=> {
moveThreadsFromSnooze(threads)
Actions.closePopover();
NylasEnv.reportError(error);
NylasEnv.showErrorDialog(`Sorry, we were unable to save your snooze settings. ${error.message}`);

View file

@ -15,6 +15,25 @@ import {
} from 'nylas-exports';
import {SNOOZE_CATEGORY_NAME, DATE_FORMAT_SHORT} from './snooze-constants'
export function snoozeMessage(snoozeDate) {
let message = 'Snoozed'
if (snoozeDate) {
let dateFormat = DATE_FORMAT_SHORT
const date = moment(snoozeDate)
const now = moment()
const hourDifference = moment.duration(date.diff(now)).asHours()
if (hourDifference < 24) {
dateFormat = dateFormat.replace('MMM D, ', '');
}
if (date.minutes() === 0) {
dateFormat = dateFormat.replace(':mm', '');
}
message += ` until ${DateUtils.format(date, dateFormat)}`;
}
return message;
}
export function createSnoozeCategory(accountId, name = SNOOZE_CATEGORY_NAME) {
const category = new Category({
@ -76,7 +95,7 @@ export function getSnoozeCategoriesByAccount(accounts = AccountStore.accounts())
export function groupProcessedThreadsByAccountId(categoriesByAccountId, threads) {
return DatabaseStore.modelify(Thread, _.pluck(threads, 'id')).then((updatedThreads)=> {
return DatabaseStore.modelify(Thread, _.pluck(threads, 'clientId')).then((updatedThreads)=> {
const threadsByAccountId = {}
updatedThreads.forEach((thread)=> {
const accId = thread.accountId
@ -95,15 +114,9 @@ export function groupProcessedThreadsByAccountId(categoriesByAccountId, threads)
}
export function moveThreads(threads, categoriesByAccountId, {snooze, snoozeDate} = {}) {
export function moveThreads(threads, categoriesByAccountId, {snooze, description} = {}) {
const inbox = CategoryStore.getInboxCategory
const snoozeCat = (accId)=> categoriesByAccountId[accId]
let description = 'Snoozed'
if (snoozeDate) {
const date = moment(snoozeDate)
description += ` until ${DateUtils.format(date, DATE_FORMAT_SHORT)}`
}
const tasks = TaskFactory.tasksForApplyingCategories({
threads,
categoriesToRemove: snooze ? inbox : snoozeCat,
@ -125,7 +138,8 @@ export function moveThreads(threads, categoriesByAccountId, {snooze, snoozeDate}
export function moveThreadsToSnooze(threads, snoozeDate) {
return getSnoozeCategoriesByAccount()
.then((categoriesByAccountId)=> {
return moveThreads(threads, categoriesByAccountId, {snooze: true, snoozeDate})
const description = snoozeMessage(snoozeDate)
return moveThreads(threads, categoriesByAccountId, {snooze: true, description})
})
}
@ -133,6 +147,7 @@ export function moveThreadsToSnooze(threads, snoozeDate) {
export function moveThreadsFromSnooze(threads) {
return getSnoozeCategoriesByAccount()
.then((categoriesByAccountId)=> {
return moveThreads(threads, categoriesByAccountId, {snooze: false})
const description = 'Unsnoozed';
return moveThreads(threads, categoriesByAccountId, {snooze: false, description})
})
}

View file

@ -0,0 +1,11 @@
@snooze-color: #472B82;
.snooze-mail-label {
display: flex;
align-items: center;
img {
background-color: @snooze-color;
margin-right: 5px;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB