WIP(tasks): new summary modal

This commit is contained in:
SabreCat
2022-07-21 15:35:59 -05:00
parent 153561dd42
commit e06a0e5e7f
8 changed files with 353 additions and 226 deletions
@@ -14,6 +14,11 @@
@taskEdited="loadTasks"
@taskDestroyed="taskDestroyed"
/>
<task-summary
ref="taskSummary"
:task="editingTask"
@cancel="cancelTaskModal()"
/>
<div class="row tasks-navigation mb-4">
<div class="col-12 col-md-4 d-flex align-items-center">
<h1>{{ group.name }}</h1>
@@ -95,6 +100,7 @@
:search-text="searchText"
:draggable-override="canCreateTasks"
@editTask="editTask"
@taskSummary="taskSummary"
@loadGroupCompletedTodos="loadGroupCompletedTodos"
@taskDestroyed="taskDestroyed"
/>
@@ -163,6 +169,7 @@ import moment from 'moment';
import taskDefaults from '@/../../common/script/libs/taskDefaults';
import TaskColumn from '../tasks/column';
import TaskModal from '../tasks/taskModal';
import TaskSummary from '../tasks/taskSummary';
import GroupPlanOverviewModal from './groupPlanOverviewModal';
import toggleSwitch from '@/components/ui/toggleSwitch';
@@ -183,6 +190,7 @@ export default {
components: {
TaskColumn,
TaskModal,
TaskSummary,
GroupPlanOverviewModal,
toggleSwitch,
},
@@ -341,6 +349,12 @@ export default {
this.$root.$emit('bv::show::modal', 'task-modal');
});
},
taskSummary (task) {
this.editingTask = cloneDeep(task);
Vue.nextTick(() => {
this.$root.$emit('bv::show::modal', 'task-summary');
});
},
async loadGroupCompletedTodos () {
const completedTodos = await this.$store.dispatch('tasks:getCompletedGroupTasks', {
groupId: this.searchId,
@@ -102,6 +102,7 @@
:group="group"
:challenge="challenge"
@editTask="editTask"
@taskSummary="taskSummary"
@moveTo="moveTo"
@taskDestroyed="taskDestroyed"
/>
@@ -652,6 +653,9 @@ export default {
editTask (task) {
this.$emit('editTask', task);
},
taskSummary (task) {
this.$emit('taskSummary', task);
},
activateFilter (type, filter = '') {
// Needs a separate API call as this data may not reside in store
if (type === 'todo' && filter === 'complete2') {
+12 -5
View File
@@ -88,7 +88,7 @@
:class="contentClass"
>
<div
class="task-clickable-area pt-1 px-75 pb-0"
class="task-clickable-area pt-1 pl-75 pb-0"
:class="{ 'cursor-auto': !teamManagerAccess }"
tabindex="0"
@click="edit($event, task)"
@@ -105,7 +105,7 @@
ref="taskDropdown"
v-b-tooltip.hover.top="$t('options')"
tabindex="0"
class="task-dropdown"
class="task-dropdown mr-1"
:right="task.type === 'reward'"
>
<div slot="dropdown-toggle">
@@ -564,7 +564,11 @@
}
.task-dropdown {
max-height: 18px;
height: 16px;
width: 16px;
display: flex;
justify-content: center;
align-items: center;
}
.task-dropdown ::v-deep .dropdown-menu {
@@ -1120,7 +1124,7 @@ export default {
return this.task.date && this.$t('dueIn', { dueIn });
},
edit (e, task) {
if (this.isRunningYesterdailies || !this.showEdit) return;
if (this.isRunningYesterdailies) return;
const target = e.target || e.srcElement;
/*
@@ -1138,8 +1142,11 @@ export default {
const isEditAction = this.$refs.editTaskItem && this.$refs.editTaskItem.contains(target);
if (isDropdown && !isEditAction) return;
if (this.$store.state.spellOptions.castingSpell) return;
if (!this.$store.state.spellOptions.castingSpell) {
if (!this.showEdit) {
this.$emit('taskSummary', task);
} else {
this.$emit('editTask', task);
}
},
+24 -215
View File
@@ -6,7 +6,7 @@
size="sm"
:hide-footer="true"
@hidden="onClose()"
@show="handleOpen()"
@show="syncTask()"
@shown="focusInput()"
>
<div
@@ -22,17 +22,7 @@
>
{{ title }}
</h2>
<span
v-if="groupAccessRequiredAndOnPersonalPage"
class="svg-icon icon-12 close-icon"
aria-hidden="true"
tabindex="0"
@click="cancel()"
@keypress.enter="cancel()"
v-html="icons.close"
></span>
<div
v-else
class="ml-auto d-flex align-items-center"
>
<button
@@ -67,7 +57,7 @@
<div class="form-group">
<lockable-label
:class-override="cssClass('headings')"
:locked="groupAccessRequiredAndOnPersonalPage || challengeAccessRequired"
:locked="challengeAccessRequired"
:text="`${$t('text')}*`"
/>
<input
@@ -78,7 +68,7 @@
type="text"
required="required"
spellcheck="true"
:disabled="groupAccessRequiredAndOnPersonalPage || challengeAccessRequired"
:disabled="challengeAccessRequired"
:placeholder="$t('addATitle')"
>
</div>
@@ -89,7 +79,7 @@
<lockable-label
class="mr-auto"
:class-override="cssClass('headings')"
:locked="groupAccessRequiredAndOnPersonalPage || challengeAccessRequired"
:locked="challengeAccessRequired"
:text="`${$t('notes')}`"
/>
<small
@@ -106,7 +96,7 @@
v-model="task.notes"
class="form-control input-notes"
:class="cssClass('input')"
:disabled="groupAccessRequiredAndOnPersonalPage || challengeAccessRequired"
:disabled="challengeAccessRequired"
:placeholder="$t('addNotes')"
></textarea>
</div>
@@ -130,13 +120,6 @@
>
</div>
</div>
<div
v-if="task && groupAccessRequiredAndOnPersonalPage
&& (task.type === 'daily' || task.type === 'todo')"
class="summary-sentence py-3 px-4 mb-n4"
v-html="summarySentence"
>
</div>
<div
v-if="task"
class="task-modal-content px-4"
@@ -179,8 +162,6 @@
>
<checklist
:items.sync="task.checklist"
:disable-items="groupAccessRequiredAndOnPersonalPage"
:disable-drag="groupAccessRequiredAndOnPersonalPage"
/>
</div>
<div
@@ -192,7 +173,7 @@
class="habit-option-container no-transition
d-flex flex-column justify-content-center align-items-center"
:class="!task.up ? cssClass('habit-control-disabled') : ''"
:disabled="challengeAccessRequired || groupAccessRequiredAndOnPersonalPage"
:disabled="challengeAccessRequired"
@click="toggleUpDirection()"
>
<div
@@ -218,7 +199,7 @@
class="habit-option-container no-transition
d-flex flex-column justify-content-center align-items-center"
:class="!task.down ? cssClass('habit-control-disabled') : ''"
:disabled="challengeAccessRequired || groupAccessRequiredAndOnPersonalPage"
:disabled="challengeAccessRequired"
@click="toggleDownDirection()"
>
<div
@@ -241,11 +222,11 @@
</button>
</div>
<template
v-if="task.type !== 'reward' && !groupAccessRequiredAndOnPersonalPage"
v-if="task.type !== 'reward'"
>
<div class="d-flex mt-3">
<lockable-label
:locked="groupAccessRequiredAndOnPersonalPage || challengeAccessRequired"
:locked="challengeAccessRequired"
:text="$t('difficulty')"
/>
<div
@@ -256,13 +237,12 @@
</div>
<select-difficulty
:value="task.priority"
:disabled="groupAccessRequiredAndOnPersonalPage || challengeAccessRequired"
:disabled="challengeAccessRequired"
@select="setDifficulty($event)"
/>
</template>
<div
v-if="task.type === 'todo' && !groupAccessRequiredAndOnPersonalPage
&& (!challengeAccessRequired || task.date)"
v-if="task.type === 'todo' && (!challengeAccessRequired || task.date)"
class="option mt-3"
>
<div class="form-group">
@@ -279,7 +259,7 @@
</div>
</div>
<div
v-if="task.type === 'daily' && !groupAccessRequiredAndOnPersonalPage"
v-if="task.type === 'daily'"
class="option mt-3"
>
<div class="form-group">
@@ -295,7 +275,7 @@
</div>
</div>
<div
v-if="task.type === 'daily' && !groupAccessRequiredAndOnPersonalPage"
v-if="task.type === 'daily'"
class="option mt-3"
>
<div class="form-group">
@@ -312,7 +292,7 @@
</div>
</div>
<div
v-if="task.type === 'daily' && !groupAccessRequiredAndOnPersonalPage"
v-if="task.type === 'daily'"
class="option mt-3"
>
<div class="form-group">
@@ -342,8 +322,7 @@
</div>
</div>
<div
v-if="task.type === 'daily' && task.frequency === 'weekly'
&& !groupAccessRequiredAndOnPersonalPage"
v-if="task.type === 'daily' && task.frequency === 'weekly'"
class="option mt-3"
>
<div class="form-group">
@@ -403,7 +382,7 @@
</div>
</div>
<div
v-if="!challengeAccessRequired && !groupAccessRequiredAndOnPersonalPage"
v-if="!challengeAccessRequired"
class="tags-select option mt-3"
>
<div class="tags-inline form-group row">
@@ -431,11 +410,11 @@
>
<div class="form-group">
<lockable-label
:locked="challengeAccessRequired || groupAccessRequiredAndOnPersonalPage"
:locked="challengeAccessRequired"
:text="$t('resetCounter')"
/>
<select-translated-array
:disabled="challengeAccessRequired || groupAccessRequiredAndOnPersonalPage"
:disabled="challengeAccessRequired"
:items="['daily', 'weekly', 'monthly']"
:value="task.frequency"
@select="task.frequency = $event"
@@ -585,9 +564,7 @@
</b-collapse>
</div>
<div
v-if="purpose !== 'create'
&& !challengeAccessRequired
&& !groupAccessRequiredAndOnPersonalPage"
v-if="purpose !== 'create' && !challengeAccessRequired"
class="d-flex justify-content-center mt-4 mb-4"
>
<button
@@ -1004,12 +981,6 @@
}
}
.summary-sentence {
background-color: $gray-700;
line-height: 1.71;
border-radius: 0px 0px 8px 8px;
}
.input-group-text {
font-size: 14px;
font-weight: bold;
@@ -1030,9 +1001,6 @@
<script>
import axios from 'axios';
import clone from 'lodash/clone';
import keys from 'lodash/keys';
import pickBy from 'lodash/pickBy';
import moment from 'moment';
import Datepicker from '@/components/ui/datepicker';
import toggleCheckbox from '@/components/ui/toggleCheckbox';
@@ -1044,6 +1012,8 @@ import selectDifficulty from '@/components/tasks/modal-controls/selectDifficulty
import selectTranslatedArray from '@/components/tasks/modal-controls/selectTranslatedArray';
import lockableLabel from '@/components/tasks/modal-controls/lockableLabel';
import syncTask from '../../mixins/syncTask';
import informationIcon from '@/assets/svg/information.svg';
import positiveIcon from '@/assets/svg/positive.svg';
import negativeIcon from '@/assets/svg/negative.svg';
@@ -1053,7 +1023,7 @@ import goldIcon from '@/assets/svg/gold.svg';
import chevronIcon from '@/assets/svg/chevron.svg';
import calendarIcon from '@/assets/svg/calendar.svg';
import gripIcon from '@/assets/svg/grip.svg';
import closeIcon from '@/assets/svg/close.svg';
export default {
components: {
@@ -1068,6 +1038,7 @@ export default {
directives: {
markdown: markdownDirective,
},
mixins: [syncTask],
// purpose is either create or edit, task is the task created or edited
props: ['task', 'purpose', 'challengeId', 'groupId'],
data () {
@@ -1084,7 +1055,6 @@ export default {
streak: streakIcon,
calendar: calendarIcon,
grip: gripIcon,
close: closeIcon,
}),
members: [],
membersNameAndId: [],
@@ -1099,15 +1069,6 @@ export default {
per: 'perception',
},
calendarHighlights: { dates: [new Date()] },
expandDayString: {
su: 'Sunday',
m: 'Monday',
t: 'Tuesday',
w: 'Wednesday',
th: 'Thursday',
f: 'Friday',
s: 'Saturday',
},
};
},
computed: {
@@ -1126,7 +1087,6 @@ export default {
|| this.task.type === 'todo'
|| this.purpose === 'create'
|| !this.isUserTask
|| this.groupAccessRequiredAndOnPersonalPage
) {
return false;
}
@@ -1140,14 +1100,8 @@ export default {
return true;
},
groupAccessRequiredAndOnPersonalPage () {
if (!this.groupId && this.task.group && this.task.group.id) return true;
return false;
},
checklistEnabled () {
return ['daily', 'todo'].indexOf(this.task.type) > -1
&& !this.isOriginalChallengeTask
&& (!this.groupAccessRequiredAndOnPersonalPage || this.checklist.length > 0);
return ['daily', 'todo'].indexOf(this.task.type) > -1 && !this.isOriginalChallengeTask;
},
isChallengeTask () {
return Boolean(this.task.challenge && this.task.challenge.id);
@@ -1171,7 +1125,6 @@ export default {
},
title () {
const type = this.$t(this.task.type);
if (this.groupAccessRequiredAndOnPersonalPage) return this.$t('taskSummary', { type });
return this.$t(this.purpose === 'edit' ? 'editATask' : 'createTask', { type });
},
isUserTask () {
@@ -1211,23 +1164,6 @@ export default {
selectedTags () {
return this.getTagsFor(this.task);
},
summarySentence () {
if (this.task.type === 'daily' && moment().isBefore(this.task.startDate)) {
return `This is ${this.formattedDifficulty(this.task.priority)}
task that will repeat
${this.formattedRepeatInterval(this.task.frequency, this.task.everyX)}${this.formattedDays(this.task.frequency, this.task.repeat, this.task.daysOfMonth, this.task.weeksOfMonth, this.task.startDate)}
starting on <strong>${moment(this.task.startDate).format('MM/DD/YYYY')}</strong>.`;
}
if (this.task.type === 'daily') {
return `This is ${this.formattedDifficulty(this.task.priority)}
task that repeats
${this.formattedRepeatInterval(this.task.frequency, this.task.everyX)}${this.formattedDays(this.task.frequency, this.task.repeat, this.task.daysOfMonth, this.task.weeksOfMonth, this.task.startDate)}.`;
}
if (this.task.date) {
return `This is ${this.formattedDifficulty(this.task.priority)} task that is due <strong>${moment(this.task.date).format('MM/DD/YYYY')}.`;
}
return `This is ${this.formattedDifficulty(this.task.priority)} task.`;
},
},
watch: {
task () {
@@ -1255,35 +1191,6 @@ export default {
createTask: 'tasks:create',
createTag: 'tags:createTag',
}),
async syncTask () {
if (this.groupId) {
const members = await this.$store.dispatch('members:getGroupMembers', {
groupId: this.groupId,
includeAllPublicFields: true,
});
this.members = members;
this.membersNameAndId = [];
this.members.forEach(member => {
this.membersNameAndId.push({
id: member._id,
name: member.profile.name,
addlText: `@${member.auth.local.username}`,
});
this.memberNamesById[member._id] = member.profile.name;
});
this.assignedMembers = [];
if (this.task.group?.assignedUsers) {
this.assignedMembers = this.task.group.assignedUsers;
}
}
// @TODO: This whole component is mutating a prop
// and that causes issues. We need to not copy the prop similar to group modals
if (this.task) this.checklist = clone(this.task.checklist);
},
async handleOpen () {
this.syncTask();
},
cssClass (suffix) {
if (!this.task) {
return '';
@@ -1309,104 +1216,6 @@ export default {
formattedDate (date) {
return moment(date).format('MM/DD/YYYY');
},
formattedDays (frequency, repeat, daysOfMonth, weeksOfMonth, startDate) {
let activeDays;
const dayStringArray = [];
switch (frequency) {
case 'weekly':
activeDays = keys(pickBy(repeat, value => value === true));
if (activeDays.length === 0) return ' on <strong>no days</strong>';
if (activeDays.length === 7) return ' on <strong>every day of the week</strong>';
dayStringArray.push(' on <strong>');
activeDays.forEach((value, index) => {
if (activeDays.length > 1 && index === activeDays.length - 1) dayStringArray.push(' and');
dayStringArray.push(` ${this.expandDayString[value]}`);
if (activeDays.length > 2 && index !== activeDays.length - 1) dayStringArray.push(',');
});
dayStringArray.push('</strong>');
break;
case 'monthly':
dayStringArray.push(' on <strong>the ');
if (daysOfMonth.length > 0) {
daysOfMonth.forEach((value, index) => {
const stringDay = String(value);
const stringFinalDigit = stringDay.slice(-1);
let ordinalSuffix = 'th';
if (stringFinalDigit === '1' && stringDay !== '11') ordinalSuffix = 'st';
if (stringFinalDigit === '2' && stringDay !== '12') ordinalSuffix = 'nd';
if (stringFinalDigit === '3' && stringDay !== '13') ordinalSuffix = 'rd';
if (daysOfMonth.length > 1 && index === daysOfMonth.length - 1) dayStringArray.push(' and');
dayStringArray.push(`${stringDay}${ordinalSuffix}`);
if (daysOfMonth.length > 2 && index !== daysOfMonth.length - 1) dayStringArray.push(',');
});
dayStringArray.push('</strong>');
} else if (weeksOfMonth.length > 0) {
switch (weeksOfMonth[0]) {
case 0:
dayStringArray.push('first');
break;
case 1:
dayStringArray.push('second');
break;
case 2:
dayStringArray.push('third');
break;
case 3:
dayStringArray.push('fourth');
break;
case 4:
dayStringArray.push('fifth');
break;
default:
break;
}
activeDays = keys(pickBy(repeat, value => value === true));
dayStringArray.push(` ${this.expandDayString[activeDays[0]]} of the month</strong>`);
}
break;
case 'yearly':
return ` on <strong>${moment(startDate).format('MMMM Do')}</strong>`;
default:
return '';
}
return dayStringArray.join('');
},
formattedDifficulty (priority) {
switch (priority) {
case 0.1:
return 'a <strong>trivial</strong>';
case 1:
return 'an <strong>easy</strong>';
case 1.5:
return 'a <strong>medium</strong>';
case 2:
return 'a <strong>hard</strong>';
default:
return null;
}
},
formattedRepeatInterval (frequency, everyX) {
const numericX = Number(everyX);
switch (frequency) {
case 'daily':
if (numericX === 1) return '<strong>every day</strong>';
if (numericX === 2) return '<strong>every other day</strong>';
return `<strong>every ${numericX} days</strong>`;
case 'weekly':
if (numericX === 1) return '<strong>every week</strong>';
if (numericX === 2) return '<strong>every other week</strong>';
return `<strong>every ${numericX} weeks</strong>`;
case 'monthly':
if (numericX === 1) return '<strong>every month</strong>';
if (numericX === 2) return '<strong>every other month</strong>';
return `<strong>every ${numericX} months</strong>`;
case 'yearly':
if (numericX === 1) return '<strong>every year</strong>';
return `<strong>every ${everyX} years</strong>`;
default:
return null;
}
},
calculateMonthlyRepeatDays (newRepeatsOn) {
if (!this.task) return;
const { task } = this;
@@ -0,0 +1,251 @@
<template>
<b-modal
id="task-summary"
:hide-footer="true"
@show="syncTask()"
@hidden="$emit('cancel')"
>
<div
v-if="task"
slot="modal-header"
class="task-modal-header px-4 d-flex align-items-center"
:class="cssClass('bg')"
>
<h2
class="my-auto"
:class="cssClass('headings')"
>
{{ title }}
</h2>
<div
class="svg-icon color-stroke icon-12 close-x ml-auto my-auto"
:class="cssClass('headings')"
aria-hidden="true"
tabindex="0"
@click="cancel()"
@keypress.enter="cancel()"
v-html="icons.close"
></div>
</div>
</b-modal>
</template>
<style lang="scss">
@import '~@/assets/scss/colors.scss';
#task-summary {
.modal-content {
border-top-left-radius: 10px;
border-top-right-radius: 10px;
border: none;
box-shadow: 0 14px 28px 0 rgba($black, 0.24), 0 10px 10px 0 rgba($black, 0.28);
}
.modal-header, .modal-body, .modal-footer {
padding: 0px;
border: none;
}
.modal-dialog {
width: 448px;
margin-top: 50vh;
transform: translateY(-50%);
}
.modal-header {
padding: 0px;
}
}
</style>
<style lang="scss" scoped>
@import '~@/assets/scss/colors.scss';
.close-x {
height: 12px;
width: 12px;
position: relative;
opacity: 0.75;
&:hover, &:focus {
opacity: 1;
}
}
.task-modal-header {
color: $white;
height: 60px;
width: 100%;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
h2 {
color: $white;
}
}
</style>
<script>
import keys from 'lodash/keys';
import moment from 'moment';
import pickBy from 'lodash/pickBy';
import syncTask from '../../mixins/syncTask';
import { mapGetters } from '@/libs/store';
import closeIcon from '@/assets/svg/close.svg';
export default {
mixins: [syncTask],
props: ['task'],
data () {
return {
expandDayString: {
su: 'Sunday',
m: 'Monday',
t: 'Tuesday',
w: 'Wednesday',
th: 'Thursday',
f: 'Friday',
s: 'Saturday',
},
icons: Object.freeze({
close: closeIcon,
}),
};
},
computed: {
...mapGetters({
getTaskClasses: 'tasks:getTaskClasses',
}),
summarySentence () {
if (this.task.type === 'daily' && moment().isBefore(this.task.startDate)) {
return `This is ${this.formattedDifficulty(this.task.priority)} task that will repeat
${this.formattedRepeatInterval(this.task.frequency, this.task.everyX)}${this.formattedDays(this.task.frequency, this.task.repeat, this.task.daysOfMonth, this.task.weeksOfMonth, this.task.startDate)}
starting on <strong>${moment(this.task.startDate).format('MM/DD/YYYY')}</strong>.`;
}
if (this.task.type === 'daily') {
return `This is ${this.formattedDifficulty(this.task.priority)} task that repeats
${this.formattedRepeatInterval(this.task.frequency, this.task.everyX)}${this.formattedDays(this.task.frequency, this.task.repeat, this.task.daysOfMonth, this.task.weeksOfMonth, this.task.startDate)}.`;
}
if (this.task.date) {
return `This is ${this.formattedDifficulty(this.task.priority)} task that is due <strong>${moment(this.task.date).format('MM/DD/YYYY')}.`;
}
return `This is ${this.formattedDifficulty(this.task.priority)} task.`;
},
title () {
const type = this.$t(this.task.type);
return this.$t('taskSummary', { type });
},
},
methods: {
cancel () {
this.$root.$emit('bv::hide::modal', 'task-summary');
},
cssClass (suffix) {
if (!this.task) {
return '';
}
return this.getTaskClasses(this.task, `edit-modal-${suffix}`);
},
formattedDays (frequency, repeat, daysOfMonth, weeksOfMonth, startDate) {
let activeDays;
const dayStringArray = [];
switch (frequency) {
case 'weekly':
activeDays = keys(pickBy(repeat, value => value === true));
if (activeDays.length === 0) return ' on <strong>no days</strong>';
if (activeDays.length === 7) return ' on <strong>every day of the week</strong>';
dayStringArray.push(' on <strong>');
activeDays.forEach((value, index) => {
if (activeDays.length > 1 && index === activeDays.length - 1) dayStringArray.push(' and');
dayStringArray.push(` ${this.expandDayString[value]}`);
if (activeDays.length > 2 && index !== activeDays.length - 1) dayStringArray.push(',');
});
dayStringArray.push('</strong>');
break;
case 'monthly':
dayStringArray.push(' on <strong>the ');
if (daysOfMonth.length > 0) {
daysOfMonth.forEach((value, index) => {
const stringDay = String(value);
const stringFinalDigit = stringDay.slice(-1);
let ordinalSuffix = 'th';
if (stringFinalDigit === '1' && stringDay !== '11') ordinalSuffix = 'st';
if (stringFinalDigit === '2' && stringDay !== '12') ordinalSuffix = 'nd';
if (stringFinalDigit === '3' && stringDay !== '13') ordinalSuffix = 'rd';
if (daysOfMonth.length > 1 && index === daysOfMonth.length - 1) dayStringArray.push(' and');
dayStringArray.push(`${stringDay}${ordinalSuffix}`);
if (daysOfMonth.length > 2 && index !== daysOfMonth.length - 1) dayStringArray.push(',');
});
dayStringArray.push('</strong>');
} else if (weeksOfMonth.length > 0) {
switch (weeksOfMonth[0]) {
case 0:
dayStringArray.push('first');
break;
case 1:
dayStringArray.push('second');
break;
case 2:
dayStringArray.push('third');
break;
case 3:
dayStringArray.push('fourth');
break;
case 4:
dayStringArray.push('fifth');
break;
default:
break;
}
activeDays = keys(pickBy(repeat, value => value === true));
dayStringArray.push(` ${this.expandDayString[activeDays[0]]} of the month</strong>`);
}
break;
case 'yearly':
return ` on <strong>${moment(startDate).format('MMMM Do')}</strong>`;
default:
return '';
}
return dayStringArray.join('');
},
formattedDifficulty (priority) {
switch (priority) {
case 0.1:
return 'a <strong>trivial</strong>';
case 1:
return 'an <strong>easy</strong>';
case 1.5:
return 'a <strong>medium</strong>';
case 2:
return 'a <strong>hard</strong>';
default:
return null;
}
},
formattedRepeatInterval (frequency, everyX) {
const numericX = Number(everyX);
switch (frequency) {
case 'daily':
if (numericX === 1) return '<strong>every day</strong>';
if (numericX === 2) return '<strong>every other day</strong>';
return `<strong>every ${numericX} days</strong>`;
case 'weekly':
if (numericX === 1) return '<strong>every week</strong>';
if (numericX === 2) return '<strong>every other week</strong>';
return `<strong>every ${numericX} weeks</strong>`;
case 'monthly':
if (numericX === 1) return '<strong>every month</strong>';
if (numericX === 2) return '<strong>every other month</strong>';
return `<strong>every ${numericX} months</strong>`;
case 'yearly':
if (numericX === 1) return '<strong>every year</strong>';
return `<strong>every ${everyX} years</strong>`;
default:
return null;
}
},
},
};
</script>
+15 -1
View File
@@ -10,6 +10,11 @@
:purpose="creatingTask !== null ? 'create' : 'edit'"
@cancel="cancelTaskModal()"
/>
<task-summary
ref="taskSummary"
:task="editingTask"
@cancel="cancelTaskModal()"
/>
<div class="col-12">
<div class="row tasks-navigation">
<div class="col-12 col-md-4 offset-md-4">
@@ -212,6 +217,7 @@
:search-text="searchTextThrottled"
:selected-tags="selectedTags"
@editTask="editTask"
@taskSummary="taskSummary"
@openBuyDialog="openBuyDialog($event)"
/>
</div>
@@ -382,6 +388,7 @@ import cloneDeep from 'lodash/cloneDeep';
import draggable from 'vuedraggable';
import TaskColumn from './column';
import TaskModal from './taskModal';
import TaskSummary from './taskSummary';
import spells from './spells';
import markdown from '@/directives/markdown';
@@ -402,6 +409,7 @@ export default {
components: {
TaskColumn,
TaskModal,
TaskSummary,
spells,
brokenTaskModal,
draggable,
@@ -525,13 +533,19 @@ export default {
};
this.newTag = null;
},
// Need Vue.nextTick() otherwise the first time the modal is not rendered
editTask (task) {
this.editingTask = cloneDeep(task);
// Necessary otherwise the first time the modal is not rendered
Vue.nextTick(() => {
this.$root.$emit('bv::show::modal', 'task-modal');
});
},
taskSummary (task) {
this.editingTask = cloneDeep(task);
Vue.nextTick(() => {
this.$root.$emit('bv::show::modal', 'task-summary');
});
},
createTask (type) {
this.openCreateBtn = false;
this.creatingTask = taskDefaults({ type, text: '' }, this.user);
+32
View File
@@ -0,0 +1,32 @@
import clone from 'lodash/clone';
export default {
methods: {
async syncTask () {
if (this.groupId) {
const members = await this.$store.dispatch('members:getGroupMembers', {
groupId: this.groupId,
includeAllPublicFields: true,
});
this.members = members;
this.membersNameAndId = [];
this.members.forEach(member => {
this.membersNameAndId.push({
id: member._id,
name: member.profile.name,
addlText: `@${member.auth.local.username}`,
});
this.memberNamesById[member._id] = member.profile.name;
});
this.assignedMembers = [];
if (this.task.group?.assignedUsers) {
this.assignedMembers = this.task.group.assignedUsers;
}
}
// @TODO: Task modal component is mutating a prop
// and that causes issues. We need to not copy the prop similar to group modals
if (this.task) this.checklist = clone(this.task.checklist);
},
},
};
+1 -5
View File
@@ -101,11 +101,7 @@ export function canEdit (store) {
}
break;
case 'group':
if (!onUserDashboard) {
isUserCanEditTask = isUserGroupLeader || isUserGroupManager || isUserAdmin;
} else {
isUserCanEditTask = true;
}
isUserCanEditTask = isUserGroupLeader || isUserGroupManager || isUserAdmin;
break;
default:
break;