Files
habitica/website/client/components/groups/membersModal.vue
Keith Holliday a317b351be Sept 23 fixes (#9074)
* Discover challenges

* Fixed hero loading

* Moved add task button

* Fixed bailey showing

* Added logs for bad sub data

* Fixed blurb editing

* Added confirmation for deleteing message

* Reset invite modals on invite

* fixed group member sorting

* Fixed chat time styles

* Fixed hover on liked

* Fixed like count

* Added reverse

* Fixed editing party

* Added leader conditions

* Added search

* Added loading

* Reset members when leaving party

* Rounded pending

* Fixed overflow on collecting quests

* Added to invite friends

* Hid summary from party

* Fixed button styles

* Fixed button class

* Removed okay button

* Fixed renav for profile modal

* Added subscription back to menu

* Fixed static link

* Added daily due setting

* Added local auth adding

* Fixed centering of text

* Removed message locally

* Added count for new message

* Added style fix for profile pet

* Fixed achievement popovers

* Fixed white boxes

* Added plain color backgrounds

* fixed challenge mutability

* Fixed challenge editing

* Added notation for large numbers

* Add color text to guild sizes

* Removed membership filters from discover challenges

* Added invites to group

* Cmd + enter send message

* Made leader clickable

* Updated group validation

* Added cancelling autocomplete

* Added mention icon

* Added removing member

* Removed extra string
2017-09-25 13:02:12 -05:00

381 lines
10 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template lang="pug">
// @TODO: Move this to a member directory
div
remove-member-modal(:member-to-remove='memberToRemove', :group-id='this.groupId' @member-removed='memberRemoved')
b-modal#members-modal(:title="$t('createGuild')", size='md', :hide-footer='true')
.header-wrap(slot="modal-header")
.row
.col-6
h1(v-once) {{$t('members')}}
.col-6
button(type="button" aria-label="Close" class="close", @click='close()')
span(aria-hidden="true") ×
.row
.form-group.col-6
input.form-control.search(type="text", :placeholder="$t('search')", v-model='searchTerm')
.col-5.offset-1
span.dropdown-label {{ $t('sortBy') }}
b-dropdown(:text="$t('sort')", right=true)
b-dropdown-item(v-for='sortOption in sortOptions', @click='sort(sortOption.value)', :key='sortOption.value') {{sortOption.text}}
.row(v-if='invites.length > 0')
.col-6.offset-3.nav
.nav-item(@click='viewMembers()', :class="{active: selectedPage === 'members'}") {{ $t('members') }}
.nav-item(@click='viewInvites()', :class="{active: selectedPage === 'invites'}") {{ $t('invites') }}
div(v-if='selectedPage === "members"')
.row(v-for='(member, index) in sortedMembers')
.col-11.no-padding-left
member-details(:member='member')
.col-1.actions
b-dropdown(right=true)
.svg-icon.inline.dots(slot='button-content', v-html="icons.dots")
b-dropdown-item(@click='removeMember(member, index)', v-if='isLeader')
span.dropdown-icon-item
.svg-icon.inline(v-html="icons.removeIcon", v-if='isLeader')
span.text {{$t('removeMember')}}
b-dropdown-item(@click='sendMessage(member._id)')
span.dropdown-icon-item
.svg-icon.inline(v-html="icons.messageIcon")
span.text {{$t('sendMessage')}}
b-dropdown-item(@click='sort(option.value)', v-if='isLeader')
span.dropdown-icon-item
.svg-icon.inline(v-html="icons.starIcon")
span.text {{$t('promoteToLeader')}}
b-dropdown-item(@click='sort(option.value)', v-if='isLeader && groupIsSubscribed')
span.dropdown-icon-item
.svg-icon.inline(v-html="icons.starIcon")
span.text {{$t('addManager')}}
b-dropdown-item(@click='sort(option.value)', v-if='isLeader && groupIsSubscribed')
span.dropdown-icon-item
.svg-icon.inline(v-html="icons.removeIcon")
span.text {{$t('removeManager2')}}
.row(v-if='groupId === "challenge"')
.col-12.text-center
button.btn.btn-secondary(@click='loadMoreMembers()') {{ $t('loadMore') }}
.row.gradient(v-if='members.length > 3')
div(v-if='selectedPage === "invites"')
.row(v-for='member in invites')
.col-11.no-padding-left
member-details(:member='member')
.modal-footer
button.btn.btn-primary(@click='close()') {{ $t('close') }}
</template>
<style lang='scss'>
#members-modal {
.small-text, .character-name {
color: #878190;
}
.no-padding-left, .modal-body {
padding-left: 0;
}
.member-details {
margin: 0;
}
.actions .dropdown-toggle::after {
content: none !important;
}
}
</style>
<style lang='scss' scoped>
header {
background-color: #edecee;
border-radius: 4px 4px 0 0;
}
.header-wrap {
width: 100%;
}
h1 {
color: #4f2a93;
}
.actions {
padding-top: 5em;
.dots {
height: 16px;
width: 4px;
}
.btn-group {
margin-left: -2em;
margin-top: -2em;
}
.action-icon {
margin-right: 1em;
}
}
#members-modal_modal_body {
padding: 0;
max-height: 450px;
.col-8 {
margin-left: 0;
}
.member-details {
margin: 0;
}
.member-stats {
width: 382px;
height: 147px;
}
.gradient {
background-image: linear-gradient(to bottom, rgba(255, 255, 255, 0), #ffffff);
height: 50px;
width: 100%;
position: absolute;
bottom: 0px;
margin-left: -15px;
}
}
.dropdown-icon-item .svg-icon {
width: 20px;
}
.nav {
font-weight: bold;
margin-bottom: .5em;
margin-top: .5em;
}
.nav-item {
display: inline-block;
font-size: 16px;
margin: 0 auto;
padding: .5em;
color: #878190;
}
.nav-item:hover, .nav-item.active {
color: #4f2a93;
border-bottom: 2px solid #4f2a93;
cursor: pointer;
}
</style>
<script>
import sortBy from 'lodash/sortBy';
import bModal from 'bootstrap-vue/lib/components/modal';
import bDropdown from 'bootstrap-vue/lib/components/dropdown';
import bDropdownItem from 'bootstrap-vue/lib/components/dropdown-item';
import { mapState } from 'client/libs/store';
import privateMessageModal from 'client/components/private-message-modal';
import removeMemberModal from 'client/components/members/removeMemberModal';
import MemberDetails from '../memberDetails';
import removeIcon from 'assets/members/remove.svg';
import messageIcon from 'assets/members/message.svg';
import starIcon from 'assets/members/star.svg';
import dots from 'assets/svg/dots.svg';
export default {
props: ['hideBadge'],
components: {
bModal,
bDropdown,
bDropdownItem,
MemberDetails,
privateMessageModal,
removeMemberModal,
},
data () {
return {
sortOption: '',
selectedPage: 'members',
members: [],
invites: [],
memberToRemove: {},
sortOptions: [
{
value: 'level',
text: this.$t('tier'),
},
{
value: 'name',
text: this.$t('name'),
},
{
value: 'lvl',
text: this.$t('level'),
},
{
value: 'class',
text: this.$t('class'),
},
],
searchTerm: '',
icons: Object.freeze({
removeIcon,
messageIcon,
starIcon,
dots,
}),
userIdToMessage: '',
};
},
mounted () {
this.getMembers();
},
computed: {
...mapState({user: 'user.data'}),
isLeader () {
if (!this.group || !this.group.leader) return false;
return this.user._id === this.group.leader || this.user._id === this.group.leader._id;
},
groupIsSubscribed () {
return this.group.purchased.active;
},
group () {
return this.$store.state.memberModalOptions.group;
},
groupId () {
return this.$store.state.memberModalOptions.groupId || this.group._id;
},
challengeId () {
return this.$store.state.memberModalOptions.challengeId;
},
sortedMembers () {
let sortedMembers = this.members;
if (this.searchTerm) {
sortedMembers = sortedMembers.filter(member => {
return member.profile.name.toLowerCase().indexOf(this.searchTerm.toLowerCase) !== -1;
});
}
if (!this.sortOption) return sortedMembers;
sortedMembers = sortBy(this.members, [(member) => {
if (this.sortOption === 'tier') {
if (!member.contributor) return;
return member.contributor.level;
} else if (this.sortOption === 'name') {
return member.profile.name;
} else if (this.sortOption === 'lvl') {
return member.stats.lvl;
} else if (this.sortOption === 'class') {
return member.stats.class;
}
}]);
return sortedMembers;
},
},
watch: {
groupId () {
// @TOOD: We might not need this since groupId is computed now
this.getMembers();
},
group () {
this.getMembers();
},
},
methods: {
sendMessage () {
this.$store.state.userIdToMessage = this.user._id;
this.$root.$emit('show::modal', 'private-message');
},
async getMembers () {
let groupId = this.groupId;
if (groupId && groupId !== 'challenge') {
let members = await this.$store.dispatch('members:getGroupMembers', {
groupId,
includeAllPublicFields: true,
});
this.members = members;
let invites = await this.$store.dispatch('members:getGroupInvites', {
groupId,
includeAllPublicFields: true,
});
this.invites = invites;
}
if (this.$store.state.memberModalOptions.viewingMembers.length > 0) {
this.members = this.$store.state.memberModalOptions.viewingMembers;
}
},
async clickMember (uid, forceShow) {
let user = this.$store.state.user.data;
if (user._id === uid && !forceShow) {
if (this.$route.name === 'tasks') {
this.$route.router.go('options.profile.avatar');
return;
}
this.$route.router.go('tasks');
return;
}
await this.$store.dispatch('members:selectMember', {
memberId: uid,
});
this.$root.$emit('show::modal', 'members-modal');
},
async removeMember (member, index) {
this.memberToRemove = member;
this.memberToRemove.index = index;
this.$root.$emit('show::modal', 'remove-member');
},
memberRemoved () {
this.members.splice(this.memberToRemove.index, 1);
this.group.memberCount -= 1;
this.memberToRemove = {};
},
async quickReply (uid) {
this.memberToReply = uid;
await this.$store.dispatch('members:selectMember', {
memberId: uid,
});
this.$root.$emit('show::modal', 'private-message'); // MemberModalCtrl
},
async addManager (memberId) {
await this.$store.dispatch('group:addManager', {
memberId,
});
},
async removeManager (memberId) {
await this.$store.dispatch('group:removeManager', {
memberId,
});
},
close () {
this.$root.$emit('hide::modal', 'members-modal');
},
sort (option) {
this.sortOption = option;
},
async loadMoreMembers () {
const lastMember = this.members[this.members.length - 1];
if (!lastMember) return;
let newMembers = await this.$store.dispatch('members:getChallengeMembers', {
challengeId: this.challengeId,
lastMemberId: lastMember._id,
});
this.members = this.members.concat(newMembers);
},
viewMembers () {
this.selectedPage = 'members';
},
viewInvites () {
this.selectedPage = 'invites';
},
},
};
</script>