diff --git a/app/assets/javascripts/discourse/controllers/bookmark.js b/app/assets/javascripts/discourse/controllers/bookmark.js index 891dd2daf43..0a8ba8a063f 100644 --- a/app/assets/javascripts/discourse/controllers/bookmark.js +++ b/app/assets/javascripts/discourse/controllers/bookmark.js @@ -7,6 +7,7 @@ import { htmlSafe } from "@ember/template"; import { ajax } from "discourse/lib/ajax"; const START_OF_DAY_HOUR = 8; +const LATER_TODAY_CUTOFF_HOUR = 17; const REMINDER_TYPES = { AT_DESKTOP: "at_desktop", LATER_TODAY: "later_today", @@ -14,7 +15,9 @@ const REMINDER_TYPES = { TOMORROW: "tomorrow", NEXT_WEEK: "next_week", NEXT_MONTH: "next_month", - CUSTOM: "custom" + CUSTOM: "custom", + LAST_CUSTOM: "last_custom", + NONE: "none" }; export default Controller.extend(ModalFunctionality, { @@ -27,17 +30,42 @@ export default Controller.extend(ModalFunctionality, { onCloseWithoutSaving: null, customReminderDate: null, customReminderTime: null, + lastCustomReminderDate: null, + lastCustomReminderTime: null, onShow() { this.setProperties({ errorMessage: null, name: null, - selectedReminderType: null, + selectedReminderType: REMINDER_TYPES.NONE, closeWithoutSaving: false, isSavingBookmarkManually: false, customReminderDate: null, - customReminderTime: null + customReminderTime: null, + lastCustomReminderDate: null, + lastCustomReminderTime: null }); + + this.loadLastUsedCustomReminderDatetime(); + }, + + loadLastUsedCustomReminderDatetime() { + let lastTime = localStorage.lastCustomBookmarkReminderTime; + let lastDate = localStorage.lastCustomBookmarkReminderDate; + + if (lastTime && lastDate) { + let parsed = this.parseCustomDateTime(lastDate, lastTime); + + if (parsed < this.now()) { + return; + } + + this.setProperties({ + lastCustomReminderDate: lastDate, + lastCustomReminderTime: lastTime, + parsedLastCustomReminderDatetime: parsed + }); + } }, // we always want to save the bookmark unless the user specifically @@ -71,9 +99,29 @@ export default Controller.extend(ModalFunctionality, { return REMINDER_TYPES; }, + @discourseComputed() + showLastCustom() { + return this.lastCustomReminderTime && this.lastCustomReminderDate; + }, + @discourseComputed() showLaterToday() { - return !this.laterToday().isSame(this.tomorrow(), "date"); + let later = this.laterToday(); + return ( + !later.isSame(this.tomorrow(), "date") && + later.hour() <= LATER_TODAY_CUTOFF_HOUR + ); + }, + + @discourseComputed("parsedLastCustomReminderDatetime") + lastCustomFormatted(parsedLastCustomReminderDatetime) { + return htmlSafe( + I18n.t("bookmarks.reminders.last_custom", { + date: parsedLastCustomReminderDatetime.format( + I18n.t("dates.long_no_year") + ) + }) + ); }, @discourseComputed() @@ -130,12 +178,26 @@ export default Controller.extend(ModalFunctionality, { const reminderAt = this.reminderAt(); const reminderAtISO = reminderAt ? reminderAt.toISOString() : null; - if (!reminderAt && this.selectedReminderType === REMINDER_TYPES.CUSTOM) { - return Promise.reject(I18n.t("bookmarks.invalid_custom_datetime")); + if (this.selectedReminderType === REMINDER_TYPES.CUSTOM) { + if (!reminderAt) { + return Promise.reject(I18n.t("bookmarks.invalid_custom_datetime")); + } + + localStorage.lastCustomBookmarkReminderTime = this.customReminderTime; + localStorage.lastCustomBookmarkReminderDate = this.customReminderDate; + } + + let reminderType; + if (this.selectedReminderType === REMINDER_TYPES.NONE) { + reminderType = null; + } else if (this.selectedReminderType === REMINDER_TYPES.LAST_CUSTOM) { + reminderType = REMINDER_TYPES.CUSTOM; + } else { + reminderType = this.selectedReminderType; } const data = { - reminder_type: this.selectedReminderType, + reminder_type: reminderType, reminder_at: reminderAtISO, name: this.name, post_id: this.model.postId @@ -148,6 +210,10 @@ export default Controller.extend(ModalFunctionality, { }); }, + parseCustomDateTime(date, time) { + return moment.tz(date + " " + time, this.userTimezone()); + }, + reminderAt() { if (!this.selectedReminderType) { return; @@ -167,9 +233,9 @@ export default Controller.extend(ModalFunctionality, { case REMINDER_TYPES.NEXT_MONTH: return this.nextMonth(); case REMINDER_TYPES.CUSTOM: - const customDateTime = moment.tz( - this.customReminderDate + " " + this.customReminderTime, - this.userTimezone() + const customDateTime = this.parseCustomDateTime( + this.customReminderDate, + this.customReminderTime ); if (!customDateTime.isValid()) { this.setProperties({ @@ -179,6 +245,8 @@ export default Controller.extend(ModalFunctionality, { return; } return customDateTime; + case REMINDER_TYPES.LAST_CUSTOM: + return this.parsedLastCustomReminderDatetime; } }, diff --git a/app/assets/javascripts/discourse/templates/modal/bookmark.hbs b/app/assets/javascripts/discourse/templates/modal/bookmark.hbs index 7adab91b633..192e10fc2f6 100644 --- a/app/assets/javascripts/discourse/templates/modal/bookmark.hbs +++ b/app/assets/javascripts/discourse/templates/modal/bookmark.hbs @@ -9,10 +9,6 @@ {{/if}}
- - {{input value=name name="name" class="bookmark-name" enter=(action "saveAndClose") placeholder=(i18n "post.bookmarks.name_placeholder")}}
@@ -36,6 +32,10 @@ {{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")}} + {{#if showLastCustom}} + {{tap-tile icon="undo" text=lastCustomFormatted tileId=reminderTypes.LAST_CUSTOM activeTile=grid.activeTile onChange=(action "selectReminderType")}} + {{/if}} + {{tap-tile icon="ban" text=(I18n "bookmarks.reminders.none") tileId=reminderTypes.NONE activeTile=grid.activeTile onChange=(action "selectReminderType")}} {{/tap-tile-grid}} {{#if customDateTimeSelected}}
diff --git a/app/assets/stylesheets/common/components/tap-tile.scss b/app/assets/stylesheets/common/components/tap-tile.scss index 7e8149650ab..d7259710e13 100644 --- a/app/assets/stylesheets/common/components/tap-tile.scss +++ b/app/assets/stylesheets/common/components/tap-tile.scss @@ -7,6 +7,7 @@ $horizontal-tile-padding: 5px; .tap-tile { + color: $primary-high; padding: 10px $horizontal-tile-padding; display: flex; flex-direction: column; diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 7c2a761c6a1..2fa6a8879f2 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -321,6 +321,8 @@ en: next_week: "Next week
{{date}}" next_month: "Next month
{{date}}" custom: "Custom date and time" + last_custom: "Last
{{date}}" + none: "No reminder needed" drafts: resume: "Resume" @@ -2676,8 +2678,8 @@ en: create: "Create bookmark" created: "Created" name: "Name" - name_placeholder: "Name the bookmark to help jog your memory" - set_reminder: "Set a reminder" + name_placeholder: "What is this bookmark for?" + set_reminder: "Remind me" actions: delete_bookmark: name: "Delete bookmark" diff --git a/test/javascripts/controllers/bookmark-test.js.es6 b/test/javascripts/controllers/bookmark-test.js.es6 index d94d866125b..f8fc3720110 100644 --- a/test/javascripts/controllers/bookmark-test.js.es6 +++ b/test/javascripts/controllers/bookmark-test.js.es6 @@ -19,22 +19,27 @@ function mockMomentTz(dateString) { QUnit.test("showLaterToday when later today is tomorrow do not show", function( assert ) { - mockMomentTz("2019-12-11T13:00:00Z"); + mockMomentTz("2019-12-11T22:00:00"); assert.equal(BookmarkController.get("showLaterToday"), false); }); +QUnit.test("showLaterToday when later today is after 5pm", function(assert) { + mockMomentTz("2019-12-11T15:00:00"); + assert.equal(BookmarkController.get("showLaterToday"), false); +}); + QUnit.test( "showLaterToday when later today is before the end of the day, show", function(assert) { - mockMomentTz("2019-12-11T08:00:00Z"); + mockMomentTz("2019-12-11T10:00:00"); assert.equal(BookmarkController.get("showLaterToday"), true); } ); QUnit.test("nextWeek gets next week correctly", function(assert) { - mockMomentTz("2019-12-11T08:00:00Z"); + mockMomentTz("2019-12-11T08:00:00"); assert.equal( BookmarkController.nextWeek().format("YYYY-MM-DD"), @@ -43,7 +48,7 @@ QUnit.test("nextWeek gets next week correctly", function(assert) { }); QUnit.test("nextMonth gets next month correctly", function(assert) { - mockMomentTz("2019-12-11T08:00:00Z"); + mockMomentTz("2019-12-11T08:00:00"); assert.equal( BookmarkController.nextMonth().format("YYYY-MM-DD"), @@ -54,7 +59,7 @@ 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:00Z"); + mockMomentTz("2019-12-13T08:00:00"); assert.equal( BookmarkController.nextBusinessDay().format("YYYY-MM-DD"), @@ -66,7 +71,7 @@ QUnit.test( QUnit.test( "nextBusinessDay gets next business day of monday correctly if today is saturday", function(assert) { - mockMomentTz("2019-12-14T08:00:00Z"); + mockMomentTz("2019-12-14T08:00:00"); assert.equal( BookmarkController.nextBusinessDay().format("YYYY-MM-DD"), @@ -78,7 +83,7 @@ QUnit.test( QUnit.test( "nextBusinessDay gets next business day of monday correctly if today is sunday", function(assert) { - mockMomentTz("2019-12-15T08:00:00Z"); + mockMomentTz("2019-12-15T08:00:00"); assert.equal( BookmarkController.nextBusinessDay().format("YYYY-MM-DD"), @@ -90,7 +95,7 @@ QUnit.test( QUnit.test( "nextBusinessDay gets next business day of thursday correctly if today is wednesday", function(assert) { - mockMomentTz("2019-12-11T08:00:00Z"); + mockMomentTz("2019-12-11T08:00:00"); assert.equal( BookmarkController.nextBusinessDay().format("YYYY-MM-DD"), @@ -100,7 +105,7 @@ QUnit.test( ); QUnit.test("tomorrow gets tomorrow correctly", function(assert) { - mockMomentTz("2019-12-11T08:00:00Z"); + mockMomentTz("2019-12-11T08:00:00"); assert.equal( BookmarkController.tomorrow().format("YYYY-MM-DD"), @@ -112,7 +117,7 @@ QUnit.test( "startOfDay changes the time of the provided date to 8:00am correctly", function(assert) { let dt = moment.tz( - "2019-12-11T11:37:16Z", + "2019-12-11T11:37:16", BookmarkController.currentUser.timezone ); @@ -126,11 +131,11 @@ QUnit.test( QUnit.test( "laterToday gets 3 hours from now and if before half-past, it sets the time to half-past", function(assert) { - mockMomentTz("2019-12-11T08:13:00Z"); + mockMomentTz("2019-12-11T08:13:00"); assert.equal( BookmarkController.laterToday().format("YYYY-MM-DD HH:mm:ss"), - "2019-12-11 21:30:00" + "2019-12-11 11:30:00" ); } ); @@ -138,11 +143,39 @@ QUnit.test( QUnit.test( "laterToday gets 3 hours from now and if after half-past, it rounds up to the next hour", function(assert) { - mockMomentTz("2019-12-11T08:43:00Z"); + mockMomentTz("2019-12-11T08:43:00"); assert.equal( BookmarkController.laterToday().format("YYYY-MM-DD HH:mm:ss"), - "2019-12-11 22:00:00" + "2019-12-11 12:00:00" ); } ); + +QUnit.test( + "loadLastUsedCustomReminderDatetime fills the custom reminder date + time if present in localStorage", + function(assert) { + mockMomentTz("2019-12-11T08:00:00"); + localStorage.lastCustomBookmarkReminderDate = "2019-12-12"; + localStorage.lastCustomBookmarkReminderTime = "08:00"; + + BookmarkController.loadLastUsedCustomReminderDatetime(); + + assert.equal(BookmarkController.lastCustomReminderDate, "2019-12-12"); + assert.equal(BookmarkController.lastCustomReminderTime, "08:00"); + } +); + +QUnit.test( + "loadLastUsedCustomReminderDatetime does not fills the custom reminder date + time if the datetime in localStorage is < now", + function(assert) { + mockMomentTz("2019-12-11T08:00:00"); + localStorage.lastCustomBookmarkReminderDate = "2019-12-11"; + localStorage.lastCustomBookmarkReminderTime = "07:00"; + + BookmarkController.loadLastUsedCustomReminderDatetime(); + + assert.equal(BookmarkController.lastCustomReminderDate, null); + assert.equal(BookmarkController.lastCustomReminderTime, null); + } +);