FEATURE: Bookmark reminder type changes and bugfixes (#9329)

New Reminder Types
-------------------------------------

* Add a "later this week" reminder which is today + 2 days, will not show if we are on the days Thu-Sun
* Add a "start of next business week" reminder which is 8am Monday

Bugfixes and Tweaks
--------------------------------------

* Move dates out of translation for reminder types and yield HTML for tap-tile for more customizable content and styling
* Make sure double clicking the bookmark icon in quick access takes users to the new bookmarks-with-reminders page
* Sane default to 8am (start of day) for custom reminder with no time
This commit is contained in:
Martin Brennan 2020-04-02 09:57:48 +10:00 committed by GitHub
parent 393215266f
commit d261a809e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 139 additions and 113 deletions

View File

@ -3,7 +3,6 @@ import { Promise } from "rsvp";
import ModalFunctionality from "discourse/mixins/modal-functionality";
import discourseComputed from "discourse-common/utils/decorators";
import { popupAjaxError } from "discourse/lib/ajax-error";
import { htmlSafe } from "@ember/template";
import { ajax } from "discourse/lib/ajax";
const START_OF_DAY_HOUR = 8;
@ -17,7 +16,9 @@ const REMINDER_TYPES = {
NEXT_MONTH: "next_month",
CUSTOM: "custom",
LAST_CUSTOM: "last_custom",
NONE: "none"
NONE: "none",
START_OF_NEXT_BUSINESS_WEEK: "start_of_next_business_week",
LATER_THIS_WEEK: "later_this_week"
};
export default Controller.extend(ModalFunctionality, {
@ -115,60 +116,48 @@ export default Controller.extend(ModalFunctionality, {
);
},
@discourseComputed()
showLaterThisWeek() {
return this.now().day() < 4; // 4 is Thursday
},
@discourseComputed("parsedLastCustomReminderDatetime")
lastCustomFormatted(parsedLastCustomReminderDatetime) {
return htmlSafe(
I18n.t("bookmarks.reminders.last_custom", {
date: parsedLastCustomReminderDatetime.format(
return parsedLastCustomReminderDatetime.format(
I18n.t("dates.long_no_year")
)
})
);
},
@discourseComputed()
startNextBusinessWeekFormatted() {
return this.nextWeek()
.day("Monday")
.format(I18n.t("dates.long_no_year"));
},
@discourseComputed()
laterTodayFormatted() {
return htmlSafe(
I18n.t("bookmarks.reminders.later_today", {
date: this.laterToday().format(I18n.t("dates.time"))
})
);
return this.laterToday().format(I18n.t("dates.time"));
},
@discourseComputed()
tomorrowFormatted() {
return htmlSafe(
I18n.t("bookmarks.reminders.tomorrow", {
date: this.tomorrow().format(I18n.t("dates.time_short_day"))
})
);
},
@discourseComputed()
nextBusinessDayFormatted() {
return htmlSafe(
I18n.t("bookmarks.reminders.next_business_day", {
date: this.nextBusinessDay().format(I18n.t("dates.time_short_day"))
})
);
return this.tomorrow().format(I18n.t("dates.time_short_day"));
},
@discourseComputed()
nextWeekFormatted() {
return htmlSafe(
I18n.t("bookmarks.reminders.next_week", {
date: this.nextWeek().format(I18n.t("dates.long_no_year"))
})
);
return this.nextWeek().format(I18n.t("dates.long_no_year"));
},
@discourseComputed()
laterThisWeekFormatted() {
return this.laterThisWeek().format(I18n.t("dates.time_short_day"));
},
@discourseComputed()
nextMonthFormatted() {
return htmlSafe(
I18n.t("bookmarks.reminders.next_month", {
date: this.nextMonth().format(I18n.t("dates.long_no_year"))
})
);
return this.nextMonth().format(I18n.t("dates.long_no_year"));
},
@discourseComputed()
@ -237,9 +226,17 @@ export default Controller.extend(ModalFunctionality, {
return this.tomorrow();
case REMINDER_TYPES.NEXT_WEEK:
return this.nextWeek();
case REMINDER_TYPES.START_OF_NEXT_BUSINESS_WEEK:
return this.nextWeek().day("Monday");
case REMINDER_TYPES.LATER_THIS_WEEK:
return this.laterThisWeek();
case REMINDER_TYPES.NEXT_MONTH:
return this.nextMonth();
case REMINDER_TYPES.CUSTOM:
this.set(
"customReminderTime",
this.customReminderTime || `0${START_OF_DAY_HOUR}:00`
);
const customDateTime = this.parseCustomDateTime(
this.customReminderDate,
this.customReminderTime
@ -265,23 +262,6 @@ export default Controller.extend(ModalFunctionality, {
return this.startOfDay(this.now().add(1, "month"));
},
nextBusinessDay() {
const currentDay = this.now().isoWeekday(); // 1=Mon, 7=Sun
let next = null;
// friday
if (currentDay === 5) {
next = this.now().add(3, "days");
// saturday
} else if (currentDay === 6) {
next = this.now().add(2, "days");
} else {
next = this.now().add(1, "day");
}
return this.startOfDay(next);
},
tomorrow() {
return this.startOfDay(this.now().add(1, "day"));
},
@ -301,6 +281,13 @@ export default Controller.extend(ModalFunctionality, {
: later.add(30, "minutes").startOf("hour");
},
laterThisWeek() {
if (!this.showLaterThisWeek) {
return;
}
return this.startOfDay(this.now().add(2, "days"));
},
handleSaveError(e) {
this.isSavingBookmarkManually = false;
if (typeof e === "string") {

View File

@ -1,2 +1,2 @@
{{d-icon icon}}
{{text}}
{{ yield }}

View File

@ -21,21 +21,51 @@
{{#if userHasTimezoneSet}}
{{#tap-tile-grid activeTile=selectedReminderType as |grid|}}
{{#if showAtDesktop}}
{{tap-tile icon="desktop" text=(i18n "bookmarks.reminders.at_desktop") tileId=reminderTypes.AT_DESKTOP activeTile=grid.activeTile onChange=(action "selectReminderType")}}
{{#tap-tile icon="desktop" tileId=reminderTypes.AT_DESKTOP activeTile=grid.activeTile onChange=(action "selectReminderType")}}
{{i18n "bookmarks.reminders.at_desktop"}}
{{/tap-tile}}
{{/if}}
{{#if showLaterToday}}
{{tap-tile icon="far-moon" text=laterTodayFormatted tileId=reminderTypes.LATER_TODAY activeTile=grid.activeTile onChange=(action "selectReminderType")}}
{{#tap-tile icon="far-moon" tileId=reminderTypes.LATER_TODAY activeTile=grid.activeTile onChange=(action "selectReminderType")}}
{{i18n "bookmarks.reminders.later_today"}}<br>
{{laterTodayFormatted}}
{{/tap-tile}}
{{/if}}
{{tap-tile icon="briefcase" text=nextBusinessDayFormatted tileId=reminderTypes.NEXT_BUSINESS_DAY activeTile=grid.activeTile onChange=(action "selectReminderType")}}
{{tap-tile icon="far-sun" text=tomorrowFormatted tileId=reminderTypes.TOMORROW activeTile=grid.activeTile onChange=(action "selectReminderType")}}
{{tap-tile icon="far-clock" text=nextWeekFormatted tileId=reminderTypes.NEXT_WEEK activeTile=grid.activeTile onChange=(action "selectReminderType")}}
{{tap-tile icon="far-calendar-plus" text=nextMonthFormatted tileId=reminderTypes.NEXT_MONTH activeTile=grid.activeTile onChange=(action "selectReminderType")}}
{{tap-tile icon="calendar-alt" text=(I18n "bookmarks.reminders.custom") tileId=reminderTypes.CUSTOM activeTile=grid.activeTile onChange=(action "selectReminderType")}}
{{#tap-tile icon="far-sun" tileId=reminderTypes.TOMORROW activeTile=grid.activeTile onChange=(action "selectReminderType")}}
{{i18n "bookmarks.reminders.tomorrow"}}<br>
{{tomorrowFormatted}}
{{/tap-tile}}
{{#if showLaterThisWeek}}
{{#tap-tile icon="angle-double-right" tileId=reminderTypes.LATER_THIS_WEEK activeTile=grid.activeTile onChange=(action "selectReminderType")}}
{{i18n "bookmarks.reminders.later_this_week"}}<br>
{{laterThisWeekFormatted}}
{{/tap-tile}}
{{/if}}
{{#tap-tile icon="briefcase" tileId=reminderTypes.START_OF_NEXT_BUSINESS_WEEK activeTile=grid.activeTile onChange=(action "selectReminderType")}}
{{i18n "bookmarks.reminders.start_of_next_business_week"}}<br>
{{startNextBusinessWeekFormatted}}
{{/tap-tile}}
{{#tap-tile icon="far-clock" tileId=reminderTypes.NEXT_WEEK activeTile=grid.activeTile onChange=(action "selectReminderType")}}
{{i18n "bookmarks.reminders.next_week"}}<br>
{{nextWeekFormatted}}
{{/tap-tile}}
{{#tap-tile icon="far-calendar-plus" tileId=reminderTypes.NEXT_MONTH activeTile=grid.activeTile onChange=(action "selectReminderType")}}
{{i18n "bookmarks.reminders.next_month"}}<br>
{{nextMonthFormatted}}
{{/tap-tile}}
{{#tap-tile icon="calendar-alt" tileId=reminderTypes.CUSTOM activeTile=grid.activeTile onChange=(action "selectReminderType")}}
{{i18n "bookmarks.reminders.custom"}}
{{/tap-tile}}
{{#if showLastCustom}}
{{tap-tile icon="undo" text=lastCustomFormatted tileId=reminderTypes.LAST_CUSTOM activeTile=grid.activeTile onChange=(action "selectReminderType")}}
{{#tap-tile icon="undo" tileId=reminderTypes.LAST_CUSTOM activeTile=grid.activeTile onChange=(action "selectReminderType")}}
{{i18n "bookmarks.reminders.last_custom"}}<br>
{{lastCustomFormatted}}
{{/tap-tile}}
{{/if}}
{{tap-tile icon="ban" text=(I18n "bookmarks.reminders.none") tileId=reminderTypes.NONE activeTile=grid.activeTile onChange=(action "selectReminderType")}}
{{#tap-tile icon="ban" tileId=reminderTypes.NONE activeTile=grid.activeTile onChange=(action "selectReminderType")}}
{{i18n "bookmarks.reminders.none"}}
{{/tap-tile}}
{{/tap-tile-grid}}
{{#if customDateTimeSelected}}
<div class="control-group custom-date-time-wrap">

View File

@ -56,13 +56,16 @@ createWidget("user-menu-links", {
},
bookmarksGlyph() {
let path = this.siteSettings.enable_bookmarks_with_reminders
? "bookmarks-with-reminders"
: "bookmarks";
return {
action: UserMenuAction.QUICK_ACCESS,
actionParam: QuickAccess.BOOKMARKS,
label: "user.bookmarks",
className: "user-bookmarks-link",
icon: "bookmark",
href: `${this.attrs.path}/activity/bookmarks`
href: `${this.attrs.path}/activity/${path}`
};
},

View File

@ -67,7 +67,9 @@ class Bookmark < ActiveRecord::Base
tomorrow: 3,
next_week: 4,
next_month: 5,
custom: 6
custom: 6,
start_of_next_business_week: 7,
later_this_week: 8
)
end
end

View File

@ -316,13 +316,15 @@ en:
list_permission_denied: "You do not have permission to view this user's bookmarks."
reminders:
at_desktop: "Next time I'm at my desktop"
later_today: "Later today <br/>{{date}}"
next_business_day: "Next business day <br/>{{date}}"
tomorrow: "Tomorrow <br/>{{date}}"
next_week: "Next week <br/>{{date}}"
next_month: "Next month <br/>{{date}}"
later_today: "Later today"
next_business_day: "Next business day"
tomorrow: "Tomorrow"
next_week: "Next week"
later_this_week: "Later this week"
start_of_next_business_week: "Next Monday"
next_month: "Next month"
custom: "Custom date and time"
last_custom: "Last <br/>{{date}}"
last_custom: "Last"
none: "No reminder needed"
drafts:

View File

@ -6,6 +6,7 @@ moduleFor("controller:bookmark", {
beforeEach() {
logIn();
BookmarkController = this.subject({ currentUser: User.current() });
BookmarkController.onShow();
},
afterEach() {
@ -58,54 +59,34 @@ QUnit.test("nextMonth gets next month correctly", function(assert) {
);
});
QUnit.test(
"nextBusinessDay gets next business day of monday correctly if today is friday",
function(assert) {
mockMomentTz("2019-12-13T08:00:00");
QUnit.test("laterThisWeek gets 2 days from now", function(assert) {
mockMomentTz("2019-12-10T08:00:00");
assert.equal(
BookmarkController.nextBusinessDay().format("YYYY-MM-DD"),
"2019-12-16"
);
}
);
QUnit.test(
"nextBusinessDay gets next business day of monday correctly if today is saturday",
function(assert) {
mockMomentTz("2019-12-14T08:00:00");
assert.equal(
BookmarkController.nextBusinessDay().format("YYYY-MM-DD"),
"2019-12-16"
);
}
);
QUnit.test(
"nextBusinessDay gets next business day of monday correctly if today is sunday",
function(assert) {
mockMomentTz("2019-12-15T08:00:00");
assert.equal(
BookmarkController.nextBusinessDay().format("YYYY-MM-DD"),
"2019-12-16"
);
}
);
QUnit.test(
"nextBusinessDay gets next business day of thursday correctly if today is wednesday",
function(assert) {
mockMomentTz("2019-12-11T08:00:00");
assert.equal(
BookmarkController.nextBusinessDay().format("YYYY-MM-DD"),
BookmarkController.laterThisWeek().format("YYYY-MM-DD"),
"2019-12-12"
);
}
);
});
QUnit.test("laterThisWeek returns null if we are at Thursday already", function(
assert
) {
mockMomentTz("2019-12-12T08:00:00");
assert.equal(BookmarkController.laterThisWeek(), null);
});
QUnit.test("showLaterThisWeek returns true if < Thursday", function(assert) {
mockMomentTz("2019-12-10T08:00:00");
assert.equal(BookmarkController.showLaterThisWeek, true);
});
QUnit.test("showLaterThisWeek returns false if > Thursday", function(assert) {
mockMomentTz("2019-12-12T08:00:00");
assert.equal(BookmarkController.showLaterThisWeek, false);
});
QUnit.test("tomorrow gets tomorrow correctly", function(assert) {
mockMomentTz("2019-12-11T08:00:00");
@ -154,6 +135,27 @@ QUnit.test(
}
);
QUnit.test(
"reminderAt - custom - defaults to 8:00am if the time is not selected",
function(assert) {
BookmarkController.customReminderDate = "2028-12-12";
BookmarkController.selectedReminderType =
BookmarkController.reminderTypes.CUSTOM;
const reminderAt = BookmarkController.reminderAt();
assert.equal(BookmarkController.customReminderTime, "08:00");
assert.equal(
reminderAt.toString(),
moment
.tz(
"2028-12-12 08:00",
BookmarkController.currentUser.resolvedTimezone()
)
.toString(),
"the custom date and time are parsed correctly with default time"
);
}
);
QUnit.test(
"loadLastUsedCustomReminderDatetime fills the custom reminder date + time if present in localStorage",
function(assert) {