Client Fixed (#9017)

* fix spacing between rewards and items

* fix rewards description

* rewards cost in bold

* fix gp notifications

* fix dailies gray text

* fix cancel in task edit modal

* tags: use AND not OR for filtering

* fix tasksDefaults so that monthlies can be created correctly

* tags: usable if no task selected, saving checklist and tags saved the one being added without requiting to press enter

* remove tags from tasks when they are deleted

* fix tags removal when multiple tags are deleted and fix tags editing
This commit is contained in:
Matteo Pagliazzi
2017-09-02 18:08:32 +02:00
committed by GitHub
parent c2aaa9b592
commit 0424d214c5
11 changed files with 92 additions and 60 deletions

View File

@@ -54,7 +54,7 @@ export default {
challengeId: this.brokenChallengeTask.challenge.id,
keep: keepOption,
});
await this.$store.dispatch('tasks:fetchUserTasks', true);
await this.$store.dispatch('tasks:fetchUserTasks', {forceLoad: true});
this.close();
return;
}

View File

@@ -18,7 +18,7 @@
@editTask="editTask",
:group='group',
)
template(v-if="isUser === true && type === 'reward' && activeFilter.label !== 'custom'")
template(v-if="hasRewardsList")
.reward-items
shopItem(
v-for="reward in inAppRewards",
@@ -31,7 +31,7 @@
.column-background(
v-if="isUser === true",
:class="{'initial-description': tasks[`${type}s`].length === 0}",
:class="{'initial-description': initialColumnDescription}",
ref="columnBackground",
)
.svg-icon(v-html="icons[type]", :class="`icon-${type}`", v-once)
@@ -46,7 +46,7 @@
height: 556px;
}
.task + .reward-items {
.task-wrapper + .reward-items {
margin-top: 16px;
}
@@ -243,6 +243,17 @@ export default {
inAppRewards () {
return inAppRewards(this.user);
},
hasRewardsList () {
return this.isUser === true && this.type === 'reward' && this.activeFilter.label !== 'custom';
},
initialColumnDescription () {
// Show the column description in the middle only if there are no elements (tasks or in app items)
if (this.hasRewardsList) {
if (this.inAppRewards && this.inAppRewards.length >= 0) return false;
}
return this.tasks[`${this.type}s`].length === 0;
},
},
watch: {
taskList: {
@@ -299,11 +310,11 @@ export default {
const selectedTags = this.selectedTags;
if (selectedTags && selectedTags.length > 0) {
const hasSelectedTag = task.tags.find(tagId => {
return selectedTags.indexOf(tagId) !== -1;
const hasAllSelectedTag = selectedTags.every(tagId => {
return task.tags.indexOf(tagId) !== -1;
});
if (!hasSelectedTag) return false;
if (!hasAllSelectedTag) return false;
}
// Text

View File

@@ -1,5 +1,5 @@
<template lang="pug">
div
.task-wrapper
broken-task-modal(:brokenChallengeTask='brokenChallengeTask')
.task(@click='castEnd($event, task)')
approval-header(:task='task', v-if='this.task.group.id', :group='group')
@@ -260,6 +260,7 @@ div
margin-top: 4px;
color: $yellow-10;
font-style: initial;
font-weight: bold;
}
}
</style>
@@ -358,13 +359,11 @@ export default {
return false;
},
controlClass () {
const dueDate = this.dueDate || new Date();
return this.getTaskClasses(this.task, 'control', dueDate);
return this.getTaskClasses(this.task, 'control', this.dueDate);
},
contentClass () {
const classes = [];
const dueDate = this.dueDate || new Date();
classes.push(this.getTaskClasses(this.task, 'content'), dueDate);
classes.push(this.getTaskClasses(this.task, 'content', this.dueDate));
if (this.task.type === 'reward' || this.task.type === 'habit') {
classes.push('no-right-border');
}

View File

@@ -11,10 +11,10 @@
slot="modal-header",
:class="[cssClass]",
)
.row
h1.col-8 {{ title }}
.col-4
span.cancel-task-btn(v-once, @click="cancel()") {{ $t('cancel') }}
.clearfix
h1.float-left {{ title }}
.float-right.d-flex.align-items-center
span.cancel-task-btn.mr-2(v-if="purpose !== 'create'", v-once, @click="cancel()") {{ $t('cancel') }}
button.btn.btn-secondary(type="submit", v-once) {{ $t('save') }}
.form-group
label(v-once) {{ `${$t('title')}*` }}
@@ -335,8 +335,12 @@
}
}
.cancel-task-btn {
margin-right: .5em;
.delete-task-btn, .cancel-task-btn {
cursor: pointer;
&:hover, &:focus, &:active {
text-decoration: underline;
}
}
.task-modal-footer {
@@ -346,13 +350,7 @@
border-top-right-radius: 8px;
margin-top: 50px;
.delete-task-btn, .cancel-task-btn {
cursor: pointer;
&:hover, &:focus, &:active {
text-decoration: underline;
}
}
.delete-task-btn {
color: $red-50;
@@ -528,7 +526,7 @@ export default {
completed: false,
});
this.newChecklistItem = null;
e.preventDefault();
if (e) e.preventDefault();
},
removeChecklistItem (i) {
this.task.checklist.splice(i, 1);
@@ -537,6 +535,8 @@ export default {
return moment.weekdaysMin(dayNumber);
},
submit () {
if (this.newChecklistItem) this.addChecklistItem();
if (this.purpose === 'create') {
if (this.challengeId) {
this.$store.dispatch('tasks:createChallengeTasks', {

View File

@@ -12,7 +12,11 @@
.input-group
input.form-control.input-search(type="text", :placeholder="$t('search')", v-model="searchText")
.filter-panel(v-if="isFilterPanelOpen")
.tags-category.d-flex(v-for="tagsType in tagsByType", v-if="tagsType.tags.length > 0", :key="tagsType.key")
.tags-category.d-flex(
v-for="tagsType in tagsByType",
v-if="tagsType.tags.length > 0 || tagsType.key === 'tags'",
:key="tagsType.key"
)
.tags-header
strong(v-once) {{ $t(tagsType.key) }}
a.d-block(v-if="tagsType.key === 'tags' && !editingTags", @click="editTags()") {{ $t('editTags2') }}
@@ -21,7 +25,7 @@
template(v-if="editingTags && tagsType.key === 'tags'")
.col-6(v-for="(tag, tagIndex) in tagsSnap")
.inline-edit-input-group.tag-edit-item.input-group
input.tag-edit-input.inline-edit-input.form-control(type="text", :value="tag.name")
input.tag-edit-input.inline-edit-input.form-control(type="text", v-model="tag.name")
span.input-group-btn(@click="removeTag(tagIndex)")
.svg-icon.destroy-icon(v-html="icons.destroy")
.col-6
@@ -377,6 +381,7 @@ export default {
this.tagsSnap.splice(index, 1);
},
saveTags () {
if (this.newTag) this.addTag();
this.setUser({tags: this.tagsSnap});
this.cancelTagsEditing();
},

View File

@@ -6,23 +6,8 @@ export default {
...mapState({notifications: 'notificationStore'}),
},
methods: {
/**
Show '+ 5 {gold_coin} 3 {silver_coin}'
*/
coins (money) {
let absolute;
let gold;
let silver;
absolute = Math.abs(money);
gold = Math.floor(absolute);
silver = Math.floor((absolute - gold) * 100);
if (gold && silver > 0) {
return `${gold} <span class='notification-icon shop_gold'></span> ${silver} <span class='notification-icon shop_silver'></span>`;
} else if (gold > 0) {
return `${gold} <span class='notification-icon shop_gold'></span>`;
} else if (silver > 0) {
return `${silver} <span class='notification-icon shop_silver'></span>`;
}
return this.round(money, 2);
},
crit (val) {
let message = `${this.$t('critBonus')} ${Math.round(val)} %`;
@@ -105,8 +90,8 @@ export default {
}
return sign;
},
round (number) {
return Math.abs(number.toFixed(1));
round (number, nDigits) {
return Math.abs(number.toFixed(nDigits || 1));
},
notify (html, type, icon, sign) {
this.notifications.push({

View File

@@ -3,7 +3,7 @@ import axios from 'axios';
import compact from 'lodash/compact';
import omit from 'lodash/omit';
export function fetchUserTasks (store, forceLoad = false) {
export function fetchUserTasks (store, options = {}) {
return loadAsyncResource({
store,
path: 'tasks',
@@ -15,7 +15,7 @@ export function fetchUserTasks (store, forceLoad = false) {
return store.dispatch('tasks:order', [response.data.data, userResource.data.tasksOrder]);
});
},
forceLoad,
forceLoad: options.forceLoad,
});
}

View File

@@ -19,7 +19,7 @@ export function fetch (store, forceLoad = false) { // eslint-disable-line no-sha
});
}
export function set (store, changes) {
export async function set (store, changes) {
const user = store.state.user.data;
for (let key in changes) {
@@ -30,6 +30,22 @@ export function set (store, changes) {
});
user.tags = changes[key].concat(oldTags);
// Remove deleted tags from tasks
const userTasksByType = (await store.dispatch('tasks:fetchUserTasks')).data; // eslint-disable-line no-await-in-loop
Object.keys(userTasksByType).forEach(taskType => {
userTasksByType[taskType].forEach(task => {
const tagsIndexesToRemove = [];
task.tags.forEach((tagId, tagIndex) => {
if (user.tags.find(tag => tag.id === tagId)) return; // eslint-disable-line max-nested-callbacks
tagsIndexesToRemove.push(tagIndex);
});
tagsIndexesToRemove.forEach(i => task.tags.splice(i, 1));
});
});
} else {
setProps(user, key, changes[key]);
}

View File

@@ -61,7 +61,7 @@ export function getTaskClasses (store) {
}
break;
case 'content':
if (type === 'daily' && (task.completed || !task.isDue) || type === 'todo' && task.completed) {
if (type === 'daily' && (task.completed || !shouldDo(dueDate, task, userPreferences)) || type === 'todo' && task.completed) {
return 'task-daily-todo-content-disabled';
}
break;

View File

@@ -25,8 +25,13 @@ module.exports = function taskDefaults (task = {}) {
challenge: {
shortName: 'None',
},
group: {},
yesterDaily: true,
group: {
approval: {
required: false,
approved: false,
requested: false,
},
},
reminders: [],
attribute: 'str',
createdAt: new Date(), // TODO these are going to be overwritten by the server...
@@ -74,6 +79,9 @@ module.exports = function taskDefaults (task = {}) {
startDate: moment().startOf('day').toDate(),
everyX: 1,
frequency: 'weekly',
daysOfMonth: [],
weeksOfMonth: [],
yesterDaily: true,
});
}

View File

@@ -285,6 +285,8 @@ api.updateUser = {
async handler (req, res) {
let user = res.locals.user;
let promisesForTagsRemoval = [];
_.each(req.body, (val, key) => {
let purchasable = requiresPurchase[key];
@@ -321,20 +323,26 @@ api.updateUser = {
user.tags.push(Tag.sanitize(t));
});
// Remove from all the tasks TODO test
Tasks.Task.update({
userId: user._id,
}, {
$pull: {
tags: {$in: [removedTagsIds]},
},
}, {multi: true}).exec();
// Remove from all the tasks
// NOTE each tag to remove requires a query
promisesForTagsRemoval = removedTagsIds.map(tagId => {
return Tasks.Task.update({
userId: user._id,
}, {
$pull: {
tags: tagId,
},
}, {multi: true}).exec();
});
} else {
throw new NotAuthorized(res.t('messageUserOperationProtected', { operation: key }));
}
});
await user.save();
await Promise.all([user.save()].concat(promisesForTagsRemoval));
return res.respond(200, user);
},
};