Repeatables fixes (#8538)

* Prevented watch functions from being called when task._edit is removed

* Added start date support on the UI task summary

* Fixed setting of monthly and calculations

* Fixed linting issues

* Added check for existence

* Added existence check

* Ensured correct start date is used on update

* Hid repeat options from anything not a daily

* Added missing locales

* Moved repeatables out of advance options
This commit is contained in:
Keith Holliday
2017-03-08 16:48:30 -07:00
committed by GitHub
parent 6486862242
commit 1082359f2c
8 changed files with 74 additions and 65 deletions

View File

@@ -283,7 +283,7 @@ angular.module('habitrpg')
modalScope.cancelTaskEdit = cancelTaskEdit;
modalScope.task._edit.repeatsOn = 'dayOfMonth';
if (modalScope.task === 'daily' && modalScope.task._edit.weeksOfMonth.length > 0) {
if (modalScope.task.type === 'daily' && modalScope.task._edit.weeksOfMonth && modalScope.task._edit.weeksOfMonth.length > 0) {
modalScope.task._edit.repeatsOn = 'dayOfWeek';
}
@@ -292,20 +292,19 @@ angular.module('habitrpg')
templateUrl: 'modals/task-edit.html',
controller: ['$scope', function ($scope) {
$scope.$watch('task._edit', function (newValue, oldValue) {
if ($scope.task.type !== 'daily') return;
if ($scope.task.type !== 'daily' || !task._edit) return;
$scope.summary = generateSummary($scope.task);
$scope.repeatSuffix = generateRepeatSuffix($scope.task);
if ($scope.task._edit.repeatsOn == 'dayOfMonth') {
var date = moment().date();
var date = moment(task._edit.startDate).date();
$scope.task._edit.weeksOfMonth = [];
$scope.task._edit.dayOfMonth = [date]; // @TODO This can handle multiple dates later
$scope.task._edit.daysOfMonth = [date]; // @TODO This can handle multiple dates later
} else if ($scope.task._edit.repeatsOn == 'dayOfWeek') {
var week = Math.ceil(moment().date() / 7) - 1;
var dayOfWeek = moment().day();
var week = Math.ceil(moment(task._edit.startDate).date() / 7) - 1;
var dayOfWeek = moment(task._edit.startDate).day();
var shortDay = numberToShortDay[dayOfWeek];
$scope.task._edit.dayOfMonth = [];
$scope.task._edit.daysOfMonth = [];
$scope.task._edit.weeksOfMonth = [week]; // @TODO: This can handle multiple weeks
for (var key in $scope.task._edit.repeat) {
$scope.task._edit.repeat[key] = false;
@@ -358,11 +357,11 @@ angular.module('habitrpg')
if (task._edit.frequency === 'weekly') summary += ' on ' + repeatDays;
if (task._edit.frequency === 'monthly' && task._edit.repeatsOn == 'dayOfMonth') {
var date = moment().date();
var date = moment(task._edit.startDate).date();
summary += ' on the ' + date;
} else if (task._edit.frequency === 'monthly' && task._edit.repeatsOn == 'dayOfWeek') {
var week = Math.ceil(moment().date() / 7) - 1;
var dayOfWeek = moment().day();
var week = Math.ceil(moment(task._edit.startDate).date() / 7) - 1;
var dayOfWeek = moment(task._edit.startDate).day();
var shortDay = numberToShortDay[dayOfWeek];
var longDay = shortDayToLongDayMap[shortDay];

View File

@@ -163,5 +163,7 @@
"years": "Years",
"confirmScoreNotes": "Confirm task scoring with notes",
"taskScoreNotesTooLong": "Task score notes must be less than 256 characters",
"groupTasksByChallenge": "Group tasks by challenge title"
"groupTasksByChallenge": "Group tasks by challenge title",
"monthlyRepeatHelpContent": "This task will be due every X months",
"yearlyRepeatHelpContent": "This task will be due every X years"
}

View File

@@ -97,6 +97,9 @@ export function shouldDo (day, dailyTask) {
return false;
}
day = moment(day).startOf('day').toDate();
let startDate = moment(dailyTask.startDate).startOf('day').toDate();
let daysOfTheWeek = [];
if (dailyTask.repeat) {
@@ -105,14 +108,13 @@ export function shouldDo (day, dailyTask) {
}
}
if (dailyTask.frequency === 'daily') {
if (!dailyTask.everyX) return false; // error condition
let schedule = moment(dailyTask.startDate).recur()
let schedule = moment(startDate).recur()
.every(dailyTask.everyX).days();
return schedule.matches(day);
} else if (dailyTask.frequency === 'weekly') {
let schedule = moment(dailyTask.startDate).recur();
let schedule = moment(startDate).recur();
if (dailyTask.everyX > 1) {
schedule = schedule.every(dailyTask.everyX).weeks();
@@ -122,21 +124,21 @@ export function shouldDo (day, dailyTask) {
return schedule.matches(day);
} else if (dailyTask.frequency === 'monthly') {
let schedule = moment(dailyTask.startDate).recur();
let schedule = moment(startDate).recur();
let differenceInMonths = moment(day).month() + 1 - moment(dailyTask.startDate).month() + 1;
let differenceInMonths = moment(day).month() + 1 - moment(startDate).month() + 1;
let matchEveryX = differenceInMonths % dailyTask.everyX === 0;
if (dailyTask.weeksOfMonth) {
if (dailyTask.weeksOfMonth && dailyTask.weeksOfMonth.length > 0) {
schedule = schedule.every(daysOfTheWeek).daysOfWeek()
.every(dailyTask.weeksOfMonth).weeksOfMonthByDay();
} else if (dailyTask.daysOfMonth) {
} else if (dailyTask.daysOfMonth && dailyTask.daysOfMonth.length > 0) {
schedule = schedule.every(dailyTask.daysOfMonth).daysOfMonth();
}
return schedule.matches(day) && matchEveryX;
} else if (dailyTask.frequency === 'yearly') {
let schedule = moment(dailyTask.startDate).recur();
let schedule = moment(startDate).recur();
schedule = schedule.every(dailyTask.everyX).years();

View File

@@ -34,9 +34,10 @@ module.exports = function taskClasses (task, filters = [], dayStart = 0, lastCro
}
if (type === 'todo' || type === 'daily') {
if (completed || (type === 'daily' && !shouldDo(Number(new Date()), task, { // eslint-disable-line no-extra-parens
dayStart,
}))) {
let notDue = !shouldDo(Number(new Date()), task, { dayStart });
let isNotDueDaily = type === 'daily' && notDue;
if (completed || isNotDueDaily) {
classes += ' completed';
} else {
classes += ' uncompleted';

View File

@@ -22,5 +22,14 @@ module.exports = function updateTask (task, req = {}) {
merge(task, omit(body, ['_id', 'id', 'type', 'reminders', 'checklist', 'tags']));
// Ensure arrays are emptied
if (body.daysOfMonth && body.daysOfMonth.length === 0) {
task.daysOfMonth = [];
}
if (body.weeksOfMonth && body.weeksOfMonth.length === 0) {
task.weeksOfMonth = [];
}
return [task];
};

View File

@@ -14,47 +14,6 @@ div(ng-if='(task.type !== "reward") || (!obj.auth && obj.purchased && obj.purcha
fieldset.option-group.advanced-option(ng-show="task._edit._advanced", ng-if="!obj.auth && obj.purchased && obj.purchased.active")
group-tasks-actions(task='task', group='obj')
div(ng-show='task._edit._advanced')
div(ng-if='::task.type == "daily"')
.form-group
legend.option-title
span.hint(popover-title=env.t('startDateHelpTitle'), popover=env.t("startDateHelp"), popover-trigger='mouseenter')
=env.t('startDate')
input.form-control(type='text', ng-model='task._edit.startDate',
datepicker-popup='{{::user.preferences.dateFormat}}', is-open='datepickerOpened',
ng-click='datepickerOpened = true', ng-disabled='!canEdit(task)')
hr
fieldset.option-group.advanced-option(ng-show="task._edit._advanced && task.type !== 'reward'")
select.form-control(ng-model='task._edit.frequency', ng-disabled='!canEdit(task)')
option(value='daily')=env.t('daily')
option(value='weekly')=env.t('weekly')
option(value='monthly')=env.t('monthly')
option(value='yearly')=env.t('yearly')
//- select.form-control(ng-model='task._edit.frequency', ng-disabled='!canEdit(task)')
//- option(value='weekly')=env.t('repeatWeek')
//- option(value='daily')=env.t('repeatDays')
include ./dailies/repeat_options
.form-group(ng-show='task._edit.frequency === "monthly"')
legend.option-title=env.t('repeatsOn')
label
input(type="radio", ng-model='task._edit.repeatsOn', value='dayOfMonth')
=env.t('dayOfMonth')
label
input(type="radio", ng-model='task._edit.repeatsOn', value='dayOfWeek')
=env.t('dayOfWeek')
.form-group
legend.option-title=env.t('summary')
div {{summary}}
hr
fieldset.option-group.advanced-option(ng-show="task._edit._advanced && task.type !== 'reward'")
legend.option-title
a.hint.priority-multiplier-help(href='http://habitica.wikia.com/wiki/Difficulty', target='_blank', popover-title=env.t('difficultyHelpTitle'), popover-trigger='mouseenter', popover=env.t('difficultyHelpContent'))=env.t('difficulty')

View File

@@ -48,12 +48,14 @@ div(ng-if='task._editing')
include ./habits/plus_minus
include ./dailies/calendar
//- include ./dailies/calendar
include ./rewards/pricing
include ./todos/due_date
include ./repeatables
.col-md-6
include ./tags

View File

@@ -0,0 +1,35 @@
fieldset.option-group.advanced-option(ng-show="task.type === 'daily'")
legend.option-title
span.hint(popover-title=env.t('startDateHelpTitle'), popover=env.t("startDateHelp"), popover-trigger='mouseenter')
=env.t('startDate')
input.form-control(type='text', ng-model='task._edit.startDate',
datepicker-popup='{{::user.preferences.dateFormat}}', is-open='datepickerOpened',
ng-click='datepickerOpened = true', ng-disabled='!canEdit(task)')
br
select.form-control(ng-model='task._edit.frequency', ng-disabled='!canEdit(task)')
option(value='daily')=env.t('daily')
option(value='weekly')=env.t('weekly')
option(value='monthly')=env.t('monthly')
option(value='yearly')=env.t('yearly')
//- select.form-control(ng-model='task._edit.frequency', ng-disabled='!canEdit(task)')
//- option(value='weekly')=env.t('repeatWeek')
//- option(value='daily')=env.t('repeatDays')
include ./dailies/repeat_options
.form-group(ng-show='task._edit.frequency === "monthly"')
legend.option-title=env.t('repeatsOn')
label
input(type="radio", ng-model='task._edit.repeatsOn', value='dayOfMonth')
=env.t('dayOfMonth')
label
input(type="radio", ng-model='task._edit.repeatsOn', value='dayOfWeek')
=env.t('dayOfWeek')
.form-group
legend.option-title=env.t('summary')
div {{summary}}