Fix casting items on parties that exceed it limit by showing Load More Button (#13509)

* Fixed party size and notification when inviting

Fixed party limit to 30 members (previously 31) and pop-up when trying
to invite someone, when party has already reached it's members limit, to properly
show members number.

* Fixed View Party button in header

Fixed View Party button in header to properly show Load More button
when party size exceeds party limit.

* Fixed View Party button to properly open party

Fixed View Party button to properly open party members list on refreshing the main page, this bug was
caused by previous commit.

* Fixed SelectMembersModal to properly show Load More button

Fixed SelectMembersModal (the modal that apperas when casting
cards/specials on party member) to properly show Load More button when party size exceeds party limit

* fix(test): limit now technically 29 plus leader

* fix(test): adjust for tweakage

Co-authored-by: Sabe Jones <sabrecat@gmail.com>
This commit is contained in:
KoRnoliX
2021-10-07 22:41:22 +02:00
committed by GitHub
parent 879e8e72b2
commit d2a0d4194a
5 changed files with 81 additions and 11 deletions

View File

@@ -7,7 +7,7 @@ import {
} from '../../../../helpers/api-integration/v3'; } from '../../../../helpers/api-integration/v3';
const INVITES_LIMIT = 100; const INVITES_LIMIT = 100;
const PARTY_LIMIT_MEMBERS = 30; const PARTY_LIMIT_MEMBERS = 29;
const MAX_EMAIL_INVITES_BY_USER = 200; const MAX_EMAIL_INVITES_BY_USER = 200;
describe('Post /groups/:groupId/invite', () => { describe('Post /groups/:groupId/invite', () => {
@@ -650,7 +650,7 @@ describe('Post /groups/:groupId/invite', () => {
.to.eventually.be.rejected.and.eql({ .to.eventually.be.rejected.and.eql({
code: 400, code: 400,
error: 'BadRequest', error: 'BadRequest',
message: t('partyExceedsMembersLimit', { maxMembersParty: PARTY_LIMIT_MEMBERS }), message: t('partyExceedsMembersLimit', { maxMembersParty: PARTY_LIMIT_MEMBERS + 1 }),
}); });
}).timeout(10000); }).timeout(10000);
}); });

View File

@@ -145,6 +145,9 @@ export default {
currentWidth: 0, currentWidth: 0,
inviteModalGroup: undefined, inviteModalGroup: undefined,
inviteModalGroupType: undefined, inviteModalGroupType: undefined,
group: {},
members: [],
membersLoaded: false,
}; };
}, },
computed: { computed: {
@@ -236,14 +239,26 @@ export default {
this.$root.$emit('bv::show::modal', 'create-party-modal'); this.$root.$emit('bv::show::modal', 'create-party-modal');
} }
}, },
async showPartyMembers () { loadMembers (payload = null) {
const party = await this.$store.dispatch('party:getParty'); // Remove unnecessary data
if (payload && payload.challengeId) {
delete payload.challengeId;
}
return this.$store.dispatch('members:getGroupMembers', payload);
},
async showPartyMembers () {
this.group = await this.$store.dispatch('party:getParty');
this.group = this.$store.state.party.data;
this.membersLoaded = true;
this.members = this.partyMembers;
this.$store.state.memberModalOptions.loading = false;
this.$root.$emit('habitica:show-member-modal', { this.$root.$emit('habitica:show-member-modal', {
groupId: party.data._id, groupId: this.group._id,
viewingMembers: this.partyMembers, group: this.group,
group: party.data, memberCount: this.group.memberCount,
fetchMoreMembers: p => this.$store.dispatch('members:getGroupMembers', p), viewingMembers: this.members,
fetchMoreMembers: this.loadMembers,
}); });
}, },
setPartyMembersWidth ($event) { setPartyMembersWidth ($event) {

View File

@@ -74,6 +74,19 @@
v-if="members.length > 3" v-if="members.length > 3"
class="row gradient" class="row gradient"
></div> ></div>
<div
v-if="isLoadMoreAvailable"
class="row"
>
<div class="col-12 text-center">
<button
class="btn btn-secondary"
@click="loadMoreMembers()"
>
{{ $t('loadMore') }}
</button>
</div>
</div>
</b-modal> </b-modal>
</div> </div>
</template> </template>
@@ -157,11 +170,13 @@ export default {
components: { components: {
MemberDetails, MemberDetails,
}, },
props: ['group', 'hideBadge', 'item'], props: ['hideBadge', 'item'],
data () { data () {
return { return {
sortOption: '', sortOption: '',
members: [], members: [],
group: {},
invites: [],
memberToRemove: '', memberToRemove: '',
sortOptions: [ sortOptions: [
{ {
@@ -210,6 +225,14 @@ export default {
return this.members; return this.members;
}, },
isLoadMoreAvailable () {
// Only available if the current length of `members` is less than the
// total size of the Group/Challenge
return this.members.length < this.$store.state.memberModalOptions.memberCount;
},
challengeId () {
return this.$store.state.memberModalOptions.challengeId;
},
groupId () { groupId () {
return this.$store.state.groupId || this.group._id; return this.$store.state.groupId || this.group._id;
}, },
@@ -222,7 +245,20 @@ export default {
}, },
}, },
methods: { methods: {
loadMembers (payload = null) {
// Remove unnecessary data
if (payload && payload.challengeId) {
delete payload.challengeId;
}
return this.$store.dispatch('members:getGroupMembers', payload);
},
async getMembers () { async getMembers () {
this.group = await this.$store.dispatch('party:getParty');
this.group = this.$store.state.party.data;
this.$store.state.memberModalOptions.memberCount = this.group.memberCount;
this.$store.state.memberModalOptions.fetchMoreMembers = this.loadMembers;
const { groupId } = this; const { groupId } = this;
if (groupId && groupId !== 'challenge') { if (groupId && groupId !== 'challenge') {
const members = await this.$store.dispatch('members:getGroupMembers', { const members = await this.$store.dispatch('members:getGroupMembers', {
@@ -230,6 +266,11 @@ export default {
includeAllPublicFields: true, includeAllPublicFields: true,
}); });
this.members = members; this.members = members;
const invites = await this.$store.dispatch('members:getGroupInvites', {
groupId,
includeAllPublicFields: true,
});
this.invites = invites;
} }
if ((!this.members || this.members.length === 0) if ((!this.members || this.members.length === 0)
@@ -241,6 +282,20 @@ export default {
if (!this.members || (this.members.length === 0 && !this.groupId)) { if (!this.members || (this.members.length === 0 && !this.groupId)) {
this.members = [this.user]; this.members = [this.user];
} }
this.$store.state.memberModalOptions.viewingMembers = this.members;
},
async loadMoreMembers () {
const lastMember = this.members[this.members.length - 1];
if (!lastMember) return;
const newMembers = await this.$store.state.memberModalOptions.fetchMoreMembers({
challengeId: this.challengeId,
groupId: this.groupId,
lastMemberId: lastMember._id,
includeAllPublicFields: true,
});
this.members = this.members.concat(newMembers);
}, },
close () { close () {
this.$root.$emit('bv::hide::modal', 'select-member-modal'); this.$root.$emit('bv::hide::modal', 'select-member-modal');

View File

@@ -28,7 +28,7 @@ export const SUPPORTED_SOCIAL_NETWORKS = [
export const GUILDS_PER_PAGE = 30; // number of guilds to return per page when using pagination export const GUILDS_PER_PAGE = 30; // number of guilds to return per page when using pagination
export const PARTY_LIMIT_MEMBERS = 30; export const PARTY_LIMIT_MEMBERS = 29;
export const MINIMUM_PASSWORD_LENGTH = 8; export const MINIMUM_PASSWORD_LENGTH = 8;

View File

@@ -491,7 +491,7 @@ schema.statics.validateInvitations = async function getInvitationErr (invites, r
memberCount += totalInvites; memberCount += totalInvites;
if (memberCount > shared.constants.PARTY_LIMIT_MEMBERS) { if (memberCount > shared.constants.PARTY_LIMIT_MEMBERS) {
throw new BadRequest(res.t('partyExceedsMembersLimit', { maxMembersParty: shared.constants.PARTY_LIMIT_MEMBERS })); throw new BadRequest(res.t('partyExceedsMembersLimit', { maxMembersParty: shared.constants.PARTY_LIMIT_MEMBERS + 1 }));
} }
} }
}; };