From c28ec24c33482f5a9e6eafa4780515e6f46c79fd Mon Sep 17 00:00:00 2001 From: Keith Holliday Date: Thu, 14 Dec 2017 12:12:43 -0600 Subject: [PATCH] Added notification for when leader is updated (#9674) * Added notification for when leader is updated * Abstracted challenge member search component * Added challenge member search modal to challenge detail * Added group search --- .../groups/GET-groups_groupId_members.test.js | 15 +++++ .../components/challenges/challengeDetail.vue | 12 ++-- .../challenges/closeChallengeModal.vue | 13 ++--- .../components/groups/groupFormModal.vue | 25 ++++---- .../client/components/groups/membersModal.vue | 14 ++++- .../members/groupMemberSearchDropdown.vue | 58 +++++++++++++++++++ .../members/memberSearchDropdown.vue | 42 ++++++++++++++ website/client/store/actions/members.js | 6 ++ website/common/locales/en/challenge.json | 3 +- website/common/locales/en/groups.json | 3 +- website/server/controllers/api-v3/members.js | 4 ++ 11 files changed, 162 insertions(+), 33 deletions(-) create mode 100644 website/client/components/members/groupMemberSearchDropdown.vue create mode 100644 website/client/components/members/memberSearchDropdown.vue diff --git a/test/api/v3/integration/groups/GET-groups_groupId_members.test.js b/test/api/v3/integration/groups/GET-groups_groupId_members.test.js index e74c6acfa6..126cedaf5e 100644 --- a/test/api/v3/integration/groups/GET-groups_groupId_members.test.js +++ b/test/api/v3/integration/groups/GET-groups_groupId_members.test.js @@ -161,4 +161,19 @@ describe('GET /groups/:groupId/members', () => { let resIds = res.concat(res2).map(member => member._id); expect(resIds).to.eql(expectedIds.sort()); }); + + it('searches members', async () => { + let group = await generateGroup(user, {type: 'party', name: generateUUID()}); + + let usersToGenerate = []; + for (let i = 0; i < 2; i++) { + usersToGenerate.push(generateUser({party: {_id: group._id}})); + } + const usersCreated = await Promise.all(usersToGenerate); + const userToSearch = usersCreated[0].profile.name; + + let res = await user.get(`/groups/party/members?search=${userToSearch}`); + expect(res.length).to.equal(1); + expect(res[0].profile.name).to.equal(userToSearch); + }); }); diff --git a/website/client/components/challenges/challengeDetail.vue b/website/client/components/challenges/challengeDetail.vue index 392f0c3f16..add3e53011 100644 --- a/website/client/components/challenges/challengeDetail.vue +++ b/website/client/components/challenges/challengeDetail.vue @@ -33,10 +33,7 @@ .col-7.offset-5 span.view-progress strong {{ $t('viewProgressOf') }} - b-dropdown.create-dropdown(text="Select a Participant") - input.form-control(type='text', v-model='searchTerm') - b-dropdown-item(v-for="member in memberResults", :key="member._id", @click="openMemberProgressModal(member._id)") - | {{ member.profile.name }} + member-search-dropdown(:text="$t('selectParticipant')", :members='members', :challengeId='challengeId', @member-selected='openMemberProgressModal') span(v-if='isLeader || isAdmin') b-dropdown.create-dropdown(:text="$t('addTaskToChallenge')", :variant="'success'") b-dropdown-item(v-for="type in columns", :key="type", @click="createTask(type)") @@ -51,7 +48,6 @@ v-on:taskEdited='taskEdited', @taskDestroyed='taskDestroyed' ) - .row task-column.col-12.col-sm-6( v-for="column in columns", @@ -185,6 +181,7 @@ import omit from 'lodash/omit'; import uuid from 'uuid'; import { mapState } from 'client/libs/store'; +import memberSearchDropdown from 'client/components/members/memberSearchDropdown'; import closeChallengeModal from './closeChallengeModal'; import Column from '../tasks/column'; import TaskModal from '../tasks/taskModal'; @@ -211,6 +208,7 @@ export default { leaveChallengeModal, challengeModal, challengeMemberProgressModal, + memberSearchDropdown, TaskColumn: Column, TaskModal, }, @@ -388,8 +386,8 @@ export default { updatedChallenge (eventData) { Object.assign(this.challenge, eventData.challenge); }, - openMemberProgressModal (memberId) { - this.progressMemberId = memberId; + openMemberProgressModal (member) { + this.progressMemberId = member._id; this.$root.$emit('bv::show::modal', 'challenge-member-modal'); }, async exportChallengeCsv () { diff --git a/website/client/components/challenges/closeChallengeModal.vue b/website/client/components/challenges/closeChallengeModal.vue index ea2d93e756..736066ade7 100644 --- a/website/client/components/challenges/closeChallengeModal.vue +++ b/website/client/components/challenges/closeChallengeModal.vue @@ -10,10 +10,7 @@ div .col-12 strong(v-once) {{$t('selectChallengeWinnersDescription')}} .col-12 - b-dropdown.create-dropdown(:text="winnerText") - input.form-control(type='text', v-model='searchTerm') - b-dropdown-item(v-for="member in memberResults", :key="member._id", @click="selectMember(member)") - | {{ member.profile.name }} + member-search-dropdown(:text='winnerText', :members='members', :challengeId='challengeId', @member-selected='selectMember') .col-12 button.btn.btn-primary(v-once, @click='closeChallenge') {{$t('awardWinners')}} .col-12 @@ -74,16 +71,16 @@ div diff --git a/website/client/components/members/memberSearchDropdown.vue b/website/client/components/members/memberSearchDropdown.vue new file mode 100644 index 0000000000..3e24436e69 --- /dev/null +++ b/website/client/components/members/memberSearchDropdown.vue @@ -0,0 +1,42 @@ + + + + + diff --git a/website/client/store/actions/members.js b/website/client/store/actions/members.js index ed9fb88d0b..864b6d4d5b 100644 --- a/website/client/store/actions/members.js +++ b/website/client/store/actions/members.js @@ -6,9 +6,15 @@ let apiV3Prefix = '/api/v3'; export async function getGroupMembers (store, payload) { let url = `${apiV3Prefix}/groups/${payload.groupId}/members`; + if (payload.includeAllPublicFields) { url += '?includeAllPublicFields=true'; } + + if (payload.searchTerm) { + url += `?search=${payload.searchTerm}`; + } + let response = await axios.get(url); return response.data.data; } diff --git a/website/common/locales/en/challenge.json b/website/common/locales/en/challenge.json index d1f3618902..e47e35cd18 100644 --- a/website/common/locales/en/challenge.json +++ b/website/common/locales/en/challenge.json @@ -130,5 +130,6 @@ "categoiresRequired": "One or more categories must be selected", "viewProgressOf": "View Progress Of", "selectMember": "Select Member", - "confirmKeepChallengeTasks": "Do you want to keep challenge tasks?" + "confirmKeepChallengeTasks": "Do you want to keep challenge tasks?", + "selectParticipant": "Select a Participant" } diff --git a/website/common/locales/en/groups.json b/website/common/locales/en/groups.json index 128191516f..a421be7f84 100644 --- a/website/common/locales/en/groups.json +++ b/website/common/locales/en/groups.json @@ -413,5 +413,6 @@ "groupBilling": "Group Billing", "wouldYouParticipate": "Would you like to participate?", "managerAdded": "Manager added successfully", - "managerRemoved": "Manager removed successfully" + "managerRemoved": "Manager removed successfully", + "leaderChanged": "Leader has been changed" } diff --git a/website/server/controllers/api-v3/members.js b/website/server/controllers/api-v3/members.js index e2690cc74f..dfa6780b1e 100644 --- a/website/server/controllers/api-v3/members.js +++ b/website/server/controllers/api-v3/members.js @@ -246,6 +246,10 @@ function _getMembersForItem (type) { addComputedStats = true; } } + + if (req.query.search) { + query['profile.name'] = {$regex: req.query.search}; + } } else if (type === 'group-invites') { if (group.type === 'guild') { // eslint-disable-line no-lonely-if query['invitations.guilds.id'] = group._id;