WIP(teams): reimplement open tasking

This commit is contained in:
Sabe Jones 2021-02-08 17:03:19 -06:00 committed by SabreCat
parent 6e39c79cff
commit 248e1c6fe9
7 changed files with 76 additions and 77 deletions

View file

@ -3,9 +3,9 @@
<div
class="task transition"
:class="[{
'groupTask': task.group.id,
'task-not-editable': !teamManagerAccess},
`type_${task.type}`
'groupTask': task.group.id,
'task-not-editable': !teamManagerAccess
}, `type_${task.type}`
]"
@click="castEnd($event, task)"
>
@ -16,8 +16,7 @@
/>
<div
class="d-flex"
:class="{'task-not-scoreable': isUser !== true || task.group.approval.requested
&& !(task.group.approval.approved && task.type === 'habit')}"
:class="{'task-not-scoreable': showTaskLockIcon }"
>
<!-- Habits left side control-->
<div
@ -31,19 +30,16 @@
<div
class="task-control habit-control"
:class="[{
'habit-control-positive-enabled': task.up && isUser,
'habit-control-positive-disabled': !task.up && isUser,
'task-not-scoreable': isUser !== true
|| (task.group.approval.requested && !task.group.approval.approved),
'habit-control-positive-enabled': task.up && !showTaskLockIcon,
'habit-control-positive-disabled': !task.up && !showTaskLockIcon,
'task-not-scoreable': showTaskLockIcon,
}, controlClass.up.inner]"
tabindex="0"
@click="(isUser && task.up && (!task.group.approval.requested
|| task.group.approval.approved)) ? score('up') : null"
@keypress.enter="(isUser && task.up && (!task.group.approval.requested
|| task.group.approval.approved)) ? score('up') : null"
@click="score('up')"
@keypress.enter="score('up')"
>
<div
v-if="!isUser"
v-if="showTaskLockIcon"
class="svg-icon lock"
:class="task.up ? controlClass.up.icon : 'positive'"
v-html="icons.lock"
@ -67,13 +63,11 @@
class="task-control daily-todo-control"
:class="controlClass.inner"
tabindex="0"
@click="isUser && !task.group.approval.requested
? score(task.completed ? 'down' : 'up' ) : null"
@keypress.enter="isUser && !task.group.approval.requested
? score(task.completed ? 'down' : 'up' ) : null"
@click="score(task.completed ? 'down' : 'up' )"
@keypress.enter="score(task.completed ? 'down' : 'up' )"
>
<div
v-if="!isUser"
v-if="showTaskLockIcon"
class="svg-icon lock"
:class="controlClass.icon"
v-html="icons.lock"
@ -346,19 +340,16 @@
<div
class="task-control habit-control"
:class="[{
'habit-control-negative-enabled': task.down && isUser,
'habit-control-negative-disabled': !task.down && isUser,
'task-not-scoreable': isUser !== true
|| (task.group.approval.requested && !task.group.approval.approved),
'habit-control-negative-enabled': task.down && !showTaskLockIcon,
'habit-control-negative-disabled': !task.down && !showTaskLockIcon,
'task-not-scoreable': showTaskLockIcon,
}, controlClass.down.inner]"
tabindex="0"
@click="(isUser && task.down && (!task.group.approval.requested
|| task.group.approval.approved)) ? score('down') : null"
@keypress.enter="(isUser && task.down && (!task.group.approval.requested
|| task.group.approval.approved)) ? score('down') : null"
@click="score('down')"
@keypress.enter="score('down')"
>
<div
v-if="!isUser"
v-if="showTaskLockIcon"
class="svg-icon lock"
:class="task.down ? controlClass.down.icon : 'negative'"
v-html="icons.lock"
@ -376,8 +367,8 @@
class="right-control d-flex align-items-center justify-content-center reward-control"
:class="controlClass.bg"
tabindex="0"
@click="isUser ? score('down') : null"
@keypress.enter="isUser ? score('down') : null"
@click="score('down')"
@keypress.enter="score('down')"
>
<div
class="svg-icon"
@ -389,10 +380,9 @@
</div>
</div>
<approval-footer
v-if="task.group.id"
v-if="task.group.id && !isOpenTask"
:task="task"
:group="group"
@claimRewards="score('up')"
/>
</div>
</div>
@ -1048,12 +1038,26 @@ export default {
},
teamManagerAccess () {
if (!this.isGroupTask || !this.group) return true;
if (!this.group.leader && !this.group.managers) return false;
return (this.group.leader._id === this.user._id || this.group.managers[this.user._id]);
},
displayNotes () {
if (this.isGroupTask && !this.isUser) return this.task.group.managerNotes;
return this.task.notes;
},
isOpenTask () {
if (!this.isGroupTask) return false;
if (this.task.group.assignedUsers.length > 0) return false;
return true;
},
showTaskLockIcon () {
if (this.isUser) return false;
if (this.isGroupTask) {
if (this.isOpenTask) return false;
if (this.task.group.assignedUsers.indexOf(this.user._id) !== -1) return false;
}
return true;
},
},
methods: {
...mapActions({
@ -1121,6 +1125,8 @@ export default {
setTimeout(() => this.$root.$emit('castEnd', task, 'task', e), 0);
},
async score (direction) {
if (this.showTaskLockIcon) return;
if (this.task.type === 'habit' && !this.task[direction]) return;
if (this.isYesterdaily === true) {
await this.beforeTaskScore(this.task);
this.task.completed = !this.task.completed;

View file

@ -84,6 +84,7 @@
import moment from 'moment';
import { mapState } from '@/libs/store';
import scoreTask from '@/mixins/scoreTask';
import sync from '@/mixins/sync';
import Task from './task';
import LoadingSpinner from '../ui/loadingSpinner';
@ -92,7 +93,7 @@ export default {
Task,
LoadingSpinner,
},
mixins: [scoreTask],
mixins: [scoreTask, sync],
props: {
yesterDailies: {
type: Array,
@ -180,6 +181,7 @@ export default {
this.isLoading = false;
this.$root.$emit('bv::hide::modal', 'yesterdaily');
if (this.$route.fullPath.indexOf('task-information') !== -1) this.sync();
},
},
};

View file

@ -114,15 +114,20 @@ export function canEdit (store) {
};
}
function _nonInteractive (task) {
return (task.group && task.group.id && !task.userId)
|| (task.challenge && task.challenge.id && !task.userId)
|| (task.group && task.group.approval && task.group.approval.requested
&& task.type !== 'habit');
function _nonInteractive (task, userId) {
if (task.userId) return false;
if (task.challenge && task.challenge.id) return true;
if (
task.group
&& task.group.assignedUsers.length > 0
&& task.group.assignedUsers.indexOf(userId) === -1
) return true;
return false;
}
export function getTaskClasses (store) {
const userPreferences = store.state.user.data.preferences;
const userId = store.state.user.data._id;
// Purpose can be one of the following strings:
// Edit Modal: edit-modal-bg, edit-modal-text, edit-modal-icon
@ -171,7 +176,7 @@ export function getTaskClasses (store) {
if (type === 'todo' || type === 'daily') {
if (task.completed || (!shouldDo(dueDate, task, userPreferences) && type === 'daily')) {
return {
bg: _nonInteractive(task) ? 'task-disabled-daily-todo-control-bg-noninteractive' : 'task-disabled-daily-todo-control-bg',
bg: _nonInteractive(task, userId) ? 'task-disabled-daily-todo-control-bg-noninteractive' : 'task-disabled-daily-todo-control-bg',
checkbox: 'task-disabled-daily-todo-control-checkbox',
inner: 'task-disabled-daily-todo-control-inner',
content: 'task-disabled-daily-todo-control-content',
@ -179,28 +184,28 @@ export function getTaskClasses (store) {
}
return {
bg: _nonInteractive(task) ? `task-${color}-control-bg-noninteractive` : `task-${color}-control-bg`,
bg: _nonInteractive(task, userId) ? `task-${color}-control-bg-noninteractive` : `task-${color}-control-bg`,
checkbox: `task-${color}-control-checkbox`,
inner: `task-${color}-control-inner-daily-todo`,
icon: `task-${color}-control-icon`,
};
} if (type === 'reward') {
return {
bg: _nonInteractive(task) ? 'task-reward-control-bg-noninteractive' : 'task-reward-control-bg',
bg: _nonInteractive(task, userId) ? 'task-reward-control-bg-noninteractive' : 'task-reward-control-bg',
};
} if (type === 'habit') {
return {
up: task.up
? {
bg: _nonInteractive(task) ? `task-${color}-control-bg-noninteractive` : `task-${color}-control-bg`,
inner: _nonInteractive(task) ? `task-${color}-control-inner-habit-noninteractive` : `task-${color}-control-inner-habit`,
bg: _nonInteractive(task, userId) ? `task-${color}-control-bg-noninteractive` : `task-${color}-control-bg`,
inner: _nonInteractive(task, userId) ? `task-${color}-control-inner-habit-noninteractive` : `task-${color}-control-inner-habit`,
icon: `task-${color}-control-icon`,
}
: { bg: 'task-disabled-habit-control-bg', inner: 'task-disabled-habit-control-inner', icon: `task-${color}-control-icon` },
down: task.down
? {
bg: _nonInteractive(task) ? `task-${color}-control-bg-noninteractive` : `task-${color}-control-bg`,
inner: _nonInteractive(task) ? `task-${color}-control-inner-habit-noninteractive` : `task-${color}-control-inner-habit`,
bg: _nonInteractive(task, userId) ? `task-${color}-control-bg-noninteractive` : `task-${color}-control-bg`,
inner: _nonInteractive(task, userId) ? `task-${color}-control-inner-habit-noninteractive` : `task-${color}-control-inner-habit`,
icon: `task-${color}-control-icon`,
}
: { bg: 'task-disabled-habit-control-bg', inner: 'task-disabled-habit-control-inner', icon: `task-${color}-control-icon` },

View file

@ -104,7 +104,7 @@ function _gainMP (user, val) {
// ===== CONSTITUTION =====
// TODO Decreases HP loss from bad habits / missed dailies by 0.5% per point.
function _subtractPoints (user, task, stats, delta) {
if (task.group.id && !task.userId) return stats.hp;
if (task.group.id && !task.userId && task.type === 'daily') return stats.hp;
let conBonus = 1 - statsComputed(user).con / 250;
if (conBonus < 0.1) conBonus = 0.1;

View file

@ -654,13 +654,6 @@ api.updateTask = {
// the other of the keys when using .toObject()
// see https://github.com/Automattic/mongoose/issues/2749
task.group.approval.required = false;
if (sanitizedObj.requiresApproval) {
task.group.approval.required = true;
}
if (sanitizedObj.sharedCompletion) {
task.group.sharedCompletion = sanitizedObj.sharedCompletion;
}
if (sanitizedObj.managerNotes) {
task.group.managerNotes = sanitizedObj.managerNotes;
}

View file

@ -208,26 +208,13 @@ api.assignTask = {
const group = await Group.getGroup({ user, groupId: task.group.id, fields: groupFields });
if (!group) throw new NotFound(res.t('groupNotFound'));
if (canNotEditTasks(group, user, assignedUserId)) throw new NotAuthorized(res.t('onlyGroupLeaderCanEditTasks'));
if (canNotEditTasks(group, user)) throw new NotAuthorized(res.t('onlyGroupLeaderCanEditTasks'));
const promises = [];
const taskText = task.text;
const userName = `@${user.auth.local.username}`;
if (user._id === assignedUserId) {
const managerIds = Object.keys(group.managers);
managerIds.push(group.leader);
const managers = await User.find({ _id: managerIds }, 'notifications preferences').exec();
managers.forEach(manager => {
if (manager._id === user._id) return;
manager.addNotification('GROUP_TASK_CLAIMED', {
message: res.t('taskClaimed', { userName, taskText }, manager.preferences.language),
groupId: group._id,
taskId: task._id,
});
promises.push(manager.save());
});
} else {
if (user._id !== assignedUserId) {
assignedUser.addNotification('GROUP_TASK_ASSIGNED', {
message: res.t('youHaveBeenAssignedTask', { managerName: userName, taskText }),
taskId: task._id,
@ -283,7 +270,7 @@ api.unassignTask = {
const group = await Group.getGroup({ user, groupId: task.group.id, fields });
if (!group) throw new NotFound(res.t('groupNotFound'));
if (canNotEditTasks(group, user, assignedUserId)) throw new NotAuthorized(res.t('onlyGroupLeaderCanEditTasks'));
if (canNotEditTasks(group, user)) throw new NotAuthorized(res.t('onlyGroupLeaderCanEditTasks'));
await group.unlinkTask(task, assignedUser);
@ -531,7 +518,7 @@ api.getGroupApprovals = {
if (canNotEditTasks(group, user)) {
approvals = await Tasks.Task.find({
'group.id': groupId,
'group.approval.approved': false,
'group.approval.approved': { $ne: true },
'group.approval.requested': true,
'group.assignedUsers': user._id,
userId: user._id,
@ -541,7 +528,7 @@ api.getGroupApprovals = {
} else {
approvals = await Tasks.Task.find({
'group.id': groupId,
'group.approval.approved': false,
'group.approval.approved': { $ne: true },
'group.approval.requested': true,
}, 'userId group text')
.populate('userId', 'profile')

View file

@ -216,8 +216,6 @@ TaskSchema.statics.findMultipleByIdOrAlias = async function findByIdOrAlias (
if (!userId) throw new Error('User identifier is a required argument');
const query = _.cloneDeep(additionalQueries);
query.userId = userId;
const ids = [];
const aliases = [];
@ -229,10 +227,18 @@ TaskSchema.statics.findMultipleByIdOrAlias = async function findByIdOrAlias (
}
});
query.$or = [
{ _id: { $in: ids } },
{ alias: { $in: aliases } },
];
if (ids.length > 0 && aliases.length > 0) {
query.$or = [
{ _id: { $in: ids } },
{ alias: { $in: aliases } },
];
} else if (ids.length > 0) {
query._id = { $in: ids };
} else if (aliases.length > 0) {
query.alias = { $in: aliases };
} else {
throw new Error('No identifiers found.'); // Should be covered by the !identifiers check, but..
}
const tasks = await this.find(query).exec();