mirror of
https://github.com/sudoxnym/habitica.git
synced 2026-07-14 16:02:14 +00:00
clone selectMulti to selectSingle for assignedMember
This commit is contained in:
parent
f4feb09fbc
commit
7dbee4caed
3 changed files with 308 additions and 17 deletions
|
|
@ -1,4 +1,4 @@
|
|||
multi<template>
|
||||
<template>
|
||||
<div>
|
||||
<b-dropdown
|
||||
ref="dropdown"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,291 @@
|
|||
<template>
|
||||
<div>
|
||||
<b-dropdown
|
||||
ref="dropdown"
|
||||
class="inline-dropdown select-multi"
|
||||
:toggle-class="isOpened ? 'active' : null"
|
||||
@show="wasOpened()"
|
||||
@hide="hideCallback($event)"
|
||||
@toggle="openOrClose($event)"
|
||||
>
|
||||
<b-dropdown-header>
|
||||
<div class="mb-2">
|
||||
<b-form-input
|
||||
v-model="search"
|
||||
type="text"
|
||||
:placeholder="searchPlaceholder"
|
||||
@keyup.enter="handleSubmit"
|
||||
/>
|
||||
</div>
|
||||
</b-dropdown-header>
|
||||
<template v-slot:button-content>
|
||||
<div
|
||||
v-if="selectedItem !== null"
|
||||
v-markdown="allItemsMap[selectedItem].name"
|
||||
class="label"
|
||||
></div>
|
||||
</template>
|
||||
<div
|
||||
v-if="addNew || availableToSelect.length > 0"
|
||||
:class="{
|
||||
'item-group': true,
|
||||
'add-new': availableToSelect.length === 0 && search !== '',
|
||||
'scroll': availableToSelect.length > 5
|
||||
}"
|
||||
>
|
||||
<b-dropdown-item-button
|
||||
v-for="item in availableToSelect"
|
||||
:key="item.id"
|
||||
class="ignore-hide multi-item"
|
||||
:class="{ 'none': item.id === 'none', selectListItem: true }"
|
||||
@click.prevent.stop="selectItem(item)"
|
||||
>
|
||||
<div
|
||||
v-markdown="item.name"
|
||||
class="label"
|
||||
></div>
|
||||
<div
|
||||
v-if="item.challenge"
|
||||
class="addl-text"
|
||||
>
|
||||
{{ $t('challenge') }}
|
||||
</div>
|
||||
<div
|
||||
v-else-if="item.addlText"
|
||||
class="addl-text"
|
||||
>
|
||||
{{ item.addlText }}
|
||||
</div>
|
||||
</b-dropdown-item-button>
|
||||
|
||||
<div
|
||||
v-if="addNew"
|
||||
class="hint"
|
||||
>
|
||||
{{ $t('pressEnterToAddTag', { tagName: search }) }}
|
||||
</div>
|
||||
</div>
|
||||
</b-dropdown>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@import '~@/assets/scss/colors.scss';
|
||||
|
||||
$itemHeight: 2rem;
|
||||
|
||||
.select-multi {
|
||||
.dropdown-toggle {
|
||||
padding-left: 0.75rem;
|
||||
}
|
||||
|
||||
.dropdown-header {
|
||||
background-color: $gray-700;
|
||||
padding-bottom: 0;
|
||||
min-height: 3rem;
|
||||
}
|
||||
|
||||
.dropdown-item, .dropdown-header {
|
||||
padding-left: 0.75rem;
|
||||
padding-right: 0.75rem;
|
||||
}
|
||||
|
||||
.none {
|
||||
cursor: default;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.multi-item button {
|
||||
height: $itemHeight;
|
||||
display: flex;
|
||||
|
||||
.label {
|
||||
height: 1.5rem;
|
||||
font-size: 14px;
|
||||
line-height: 1.71;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.addl-text {
|
||||
height: 1rem;
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
font-stretch: normal;
|
||||
font-style: normal;
|
||||
line-height: 1.33;
|
||||
letter-spacing: normal;
|
||||
text-align: right;
|
||||
color: $gray-100;
|
||||
align-self: center;
|
||||
margin-top: 0.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
margin-right: 0.25rem;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.addl-text {
|
||||
color: $purple-300;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item-group {
|
||||
max-height: #{5*$itemHeight};
|
||||
|
||||
&.add-new {
|
||||
height: 30px;
|
||||
|
||||
.hint {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
&.scroll {
|
||||
overflow-y: scroll;
|
||||
}
|
||||
}
|
||||
|
||||
.hint {
|
||||
display: none;
|
||||
height: 2rem;
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
font-stretch: normal;
|
||||
font-style: normal;
|
||||
line-height: 1.33;
|
||||
letter-spacing: normal;
|
||||
color: $gray-100;
|
||||
|
||||
margin-left: 0.75rem;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import Vue from 'vue';
|
||||
import markdownDirective from '@/directives/markdown';
|
||||
|
||||
export default {
|
||||
directives: {
|
||||
markdown: markdownDirective,
|
||||
},
|
||||
components: {
|
||||
},
|
||||
props: {
|
||||
addNew: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
allItems: {
|
||||
type: Array,
|
||||
},
|
||||
emptyMessage: {
|
||||
type: String,
|
||||
},
|
||||
pillInvert: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
searchPlaceholder: {
|
||||
type: String,
|
||||
},
|
||||
selectedItem: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
preventHide: true,
|
||||
isOpened: false,
|
||||
selected: this.selectedItem,
|
||||
search: '',
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
allItemsMap () {
|
||||
const obj = {};
|
||||
this.allItems.forEach(t => {
|
||||
obj[t.id] = t;
|
||||
});
|
||||
return obj;
|
||||
},
|
||||
selectedItemAsObject () {
|
||||
return this.selected ? this.allItemsMap[this.selected] : null;
|
||||
},
|
||||
availableToSelect () {
|
||||
const availableItems = this.allItems.filter(t => t.id !== this.selected);
|
||||
|
||||
const searchString = this.search.toLowerCase();
|
||||
|
||||
const filteredItems = availableItems.filter(i => i.name.toLowerCase().includes(searchString));
|
||||
|
||||
return filteredItems;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
selected () {
|
||||
this.$emit('changed', this.selected);
|
||||
},
|
||||
},
|
||||
created () {
|
||||
document.addEventListener('keyup', this.handleEsc);
|
||||
},
|
||||
beforeDestroy () {
|
||||
document.removeEventListener('keyup', this.handleEsc);
|
||||
},
|
||||
mounted () {
|
||||
this.$refs.dropdown.clickOutHandler = () => {
|
||||
this.closeSelectPopup();
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
closeSelectPopup () {
|
||||
this.preventHide = false;
|
||||
this.isOpened = false;
|
||||
Vue.nextTick(() => {
|
||||
this.$refs.dropdown.hide();
|
||||
});
|
||||
},
|
||||
openOrClose ($event) {
|
||||
if (this.isOpened) {
|
||||
this.closeSelectPopup();
|
||||
$event.preventDefault();
|
||||
}
|
||||
},
|
||||
closeIfOpen () {
|
||||
this.closeSelectPopup();
|
||||
},
|
||||
selectItem (item) {
|
||||
this.$emit('toggle', item.id);
|
||||
},
|
||||
removeItem () {
|
||||
this.$emit('toggle', null);
|
||||
},
|
||||
hideCallback ($event) {
|
||||
if (this.preventHide) {
|
||||
$event.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
this.isOpened = false;
|
||||
},
|
||||
wasOpened () {
|
||||
this.isOpened = true;
|
||||
this.preventHide = true;
|
||||
},
|
||||
handleEsc (e) {
|
||||
if (e.keyCode === 27) {
|
||||
this.closeSelectPopup();
|
||||
}
|
||||
},
|
||||
handleSubmit () {
|
||||
if (!this.addNew) return;
|
||||
const { search } = this;
|
||||
this.$emit('addNew', search);
|
||||
|
||||
this.search = '';
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
@ -454,13 +454,11 @@
|
|||
class="col-12 mb-1"
|
||||
>{{ $t('assignedTo') }}</label>
|
||||
<div class="col-12">
|
||||
<select-multi
|
||||
ref="assignMembers"
|
||||
<select-single
|
||||
:all-items="membersNameAndId"
|
||||
:empty-message="$t('unassigned')"
|
||||
:pill-invert="true"
|
||||
:search-placeholder="$t('chooseTeamMember')"
|
||||
:selected-items="assignedMembers"
|
||||
:selected-item="assignedMember"
|
||||
@toggle="toggleAssignment($event)"
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -1044,9 +1042,11 @@ 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 SelectSingle from './modal-controls/selectSingle';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SelectSingle,
|
||||
SelectMulti,
|
||||
Datepicker,
|
||||
checklist,
|
||||
|
|
@ -1079,7 +1079,7 @@ export default {
|
|||
members: [],
|
||||
membersNameAndId: [],
|
||||
memberNamesById: {},
|
||||
assignedMembers: [],
|
||||
assignedMember: null,
|
||||
managers: [],
|
||||
showAdvancedOptions: false,
|
||||
attributesStrings: {
|
||||
|
|
@ -1270,9 +1270,10 @@ export default {
|
|||
});
|
||||
this.memberNamesById[member._id] = member.profile.name;
|
||||
});
|
||||
this.assignedMembers = [];
|
||||
if (this.task.group && this.task.group.assignedUsers) {
|
||||
this.assignedMembers = this.task.group.assignedUsers;
|
||||
this.assignedMember = null;
|
||||
if (this.task.group?.assignedUsers?.length > 0) {
|
||||
// eslint-disable-next-line prefer-destructuring
|
||||
this.assignedMember = this.task.group.assignedUsers[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1457,12 +1458,11 @@ export default {
|
|||
tasks: [this.task],
|
||||
});
|
||||
Object.assign(this.task, response);
|
||||
const promises = this.assignedMembers.map(memberId => this.$store.dispatch('tasks:assignTask', {
|
||||
await this.$store.dispatch('tasks:assignTask', {
|
||||
taskId: this.task._id,
|
||||
userId: memberId,
|
||||
}));
|
||||
Promise.all(promises);
|
||||
this.task.group.assignedUsers = this.assignedMembers;
|
||||
userId: this.assignedMember,
|
||||
});
|
||||
this.task.group.assignedUsers = [this.assignedMember];
|
||||
this.$emit('taskCreated', this.task);
|
||||
} else {
|
||||
this.createTask(this.task);
|
||||
|
|
@ -1493,9 +1493,7 @@ export default {
|
|||
return;
|
||||
}
|
||||
|
||||
const assignedIndex = this.assignedMembers.indexOf(memberId);
|
||||
|
||||
if (assignedIndex === -1) {
|
||||
if (this.assignedMember === null) {
|
||||
await this.$store.dispatch('tasks:unassignTask', {
|
||||
taskId: this.task._id,
|
||||
userId: memberId,
|
||||
|
|
@ -1506,6 +1504,8 @@ export default {
|
|||
userId: memberId,
|
||||
});
|
||||
}
|
||||
|
||||
this.assignedMember = memberId;
|
||||
},
|
||||
focusInput () {
|
||||
this.$refs.inputToFocus.focus();
|
||||
|
|
|
|||
Loading…
Reference in a new issue