Teams Updates 201908 (#11347)

* fix(teams): no hover bg change for noninteractive checkboxes

* feat(teams): send notification to managers on task claim
Also fix client unit test broken by prev commit

* feat(groups): don't penalize for tasks assigned since last activity

* fix(tests): actually fix client unit

* fix(teams): improve task styles

* fix(teams): let people other than leader see relevant approvals
Also more style fixes

* fix(approvals): better filtering and task headings for approval data

* fix(test): correct test expectations for new GET /approvals behavior

* fix(groups): style tweaks

* different border for group and normal tasks

* fix(teams): remove extra click for claiming

* fix(teams): leaders & managers can check off approval-required tasks

* fix(teams): don't notify user of own claim

* fix group task margin and z-index on hover

* fix(menu): sporadic error in top bar

* fix(teams): more approval header and footer adjustments

* fix(tests): adjust expectations for self-approval

* fix(teams): address PR comments

* refactor(timestamps): date user activity on authenticated requests

* refactor(timestamps): update local user instead of direct db update
This commit is contained in:
Sabe Jones
2019-09-26 14:49:11 -04:00
committed by GitHub
parent 5f2032a9d5
commit 01d272d2c4
26 changed files with 314 additions and 145 deletions

View File

@@ -1,15 +1,15 @@
<template lang="pug">
.task-wrapper
.task(@click='castEnd($event, task)', :class="`type_${task.type}`")
approval-header(:task='task', v-if='this.task.group.id', :group='group')
.task(@click='castEnd($event, task)', :class="[{'groupTask': task.group.id}, `type_${task.type}`]")
approval-header(:task='task', v-if='task.group.id', :group='group')
.d-flex(:class="{'task-not-scoreable': isUser !== true}")
// Habits left side control
.left-control.d-flex.align-items-center.justify-content-center(v-if="task.type === 'habit'", :class="controlClass.up.bg")
.left-control.d-flex.align-items-center.justify-content-center(v-if="task.type === 'habit'", :class="[{'control-bottom-box': this.task.group.id, 'control-top-box': approvalsClass}, controlClass.up.bg]")
.task-control.habit-control(:class="controlClass.up.inner", @click="(isUser && task.up) ? score('up') : null")
.svg-icon.lock(v-if="this.task.group.id && !isUser", v-html="icons.lock", :class="controlClass.up.icon")
.svg-icon.positive(v-else, v-html="icons.positive")
// Dailies and todos left side control
.left-control.d-flex.justify-content-center(v-if="task.type === 'daily' || task.type === 'todo'", :class="controlClass.bg")
.left-control.d-flex.justify-content-center(v-if="task.type === 'daily' || task.type === 'todo'", :class="[{'control-bottom-box': this.task.group.id, 'control-top-box': approvalsClass}, controlClass.bg]")
.task-control.daily-todo-control(:class="controlClass.inner", @click="isUser ? score(task.completed ? 'down' : 'up') : null")
.svg-icon.lock(v-html="icons.lock", v-if="this.task.group.id && !isUser && !task.completed", :class="controlClass.icon")
.svg-icon.check(v-else, v-html="icons.check", :class="{'display-check-icon': task.completed, [controlClass.checkbox]: true}")
@@ -99,7 +99,7 @@
.tag-label(v-for="tag in getTagsFor(task)", v-markdown="tag")
// Habits right side control
.right-control.d-flex.align-items-center.justify-content-center(v-if="task.type === 'habit'", :class="controlClass.down.bg")
.right-control.d-flex.align-items-center.justify-content-center(v-if="task.type === 'habit'", :class="[{'control-bottom-box': this.task.group.id, 'control-top-box': approvalsClass}, controlClass.down.bg]")
.task-control.habit-control(:class="controlClass.down.inner", @click="(isUser && task.down) ? score('down') : null")
.svg-icon.lock(v-if="this.task.group.id && !isUser", v-html="icons.lock", :class="controlClass.down.icon")
.svg-icon.negative(v-else, v-html="icons.negative")
@@ -107,12 +107,23 @@
.right-control.d-flex.align-items-center.justify-content-center.reward-control(v-if="task.type === 'reward'", :class="controlClass.bg", @click="isUser ? score('down') : null")
.svg-icon(v-html="icons.gold")
.small-text {{task.value}}
approval-footer(:task='task', v-if='this.task.group.id', :group='group')
approval-footer(:task='task', v-if='task.group.id', :group='group')
</template>
<style lang="scss" scoped>
@import '~client/assets/scss/colors.scss';
.control-bottom-box {
border-bottom-left-radius: 0px !important;
border-bottom-right-radius: 0px !important;
}
.control-top-box {
border-top-left-radius: 0px !important;
border-top-right-radius: 0px !important;
}
.task {
margin-bottom: 2px;
box-shadow: 0 2px 2px 0 rgba($black, 0.16), 0 1px 4px 0 rgba($black, 0.12);
@@ -122,13 +133,29 @@
&:hover {
box-shadow: 0 1px 8px 0 rgba($black, 0.12), 0 4px 4px 0 rgba($black, 0.16);
z-index: 10;
}
}
.task:not(.groupTask) {
&:hover {
.left-control, .right-control, .task-content {
border-color: $purple-400;
}
}
}
.task.groupTask {
&:hover {
border: $purple-400 solid 1px;
border-radius: 3px;
margin: -1px; // to counter the border width
margin-bottom: 1px;
transition: none; // with transition, the border color switches from black to $purple-400
}
}
.task-habit-disabled-control-habit:hover {
cursor: initial;
}
@@ -622,6 +649,9 @@ export default {
if (task.type === 'habit') return true;
return false;
},
approvalsClass () {
return this.group && this.task.approvals && this.task.approvals.length > 0;
},
controlClass () {
return this.getTaskClasses(this.task, 'control', this.dueDate);
},
@@ -744,6 +774,16 @@ export default {
const user = this.user;
const task = this.task;
if (task.group.approval.required) {
task.group.approval.requested = true;
const groupResponse = await axios.get(`/api/v4/groups/${task.group.id}`);
let managers = Object.keys(groupResponse.data.data.managers);
managers.push(groupResponse.data.data.leader._id);
if (managers.indexOf(user._id) !== -1) {
task.group.approval.approved = true;
}
}
try {
scoreTask({task, user, direction});
} catch (err) {
@@ -767,8 +807,6 @@ export default {
}
if (task.group.approval.required) task.group.approval.requested = true;
Analytics.updateUser();
const response = await axios.post(`/api/v4/tasks/${task._id}/score/${direction}`);
const tmp = response.data.data._tmp || {}; // used to notify drops, critical hits and other bonuses