Fix End challenge search to load participant based on search query (#15520)

* Load all participants when end challenge modal is opened.

* Fetch members in batches until members are loaded

* Fix challenge winner search to load all participants

Separated loading flags to prevent conflicts between modals

* Rename end challenge members flag to be more clear

* await load members

* Implement challenge member search only when searching w/debounce
This commit is contained in:
Fiz
2025-09-30 16:33:36 -05:00
committed by GitHub
parent 2029739a1b
commit e8eeb76cab
2 changed files with 32 additions and 10 deletions

View File

@@ -7,7 +7,6 @@
@update-challenge="updateChallenge"
/>
<close-challenge-modal
:members="members"
:challenge-id="challenge._id"
:prize="challenge.prize"
:flag-count="challenge.flagCount"
@@ -697,7 +696,6 @@ export default {
this.members = [];
},
closeChallenge () {
this.initialMembersLoad();
this.$root.$emit('bv::show::modal', 'close-challenge-modal');
},
edit () {

View File

@@ -350,6 +350,7 @@
</style>
<script>
import debounce from 'lodash/debounce';
import searchIcon from '@/assets/svg/for-css/search.svg?raw';
import deleteIcon from '@/assets/svg/delete.svg?raw';
import gemIcon from '@/assets/svg/gem.svg?raw';
@@ -362,13 +363,14 @@ export default {
components: {
closeX,
},
props: ['challengeId', 'members', 'prize', 'flagCount'],
props: ['challengeId', 'prize', 'flagCount'],
data () {
return {
winner: {},
searchTerm: '',
showResults: false,
filteredMembers: [],
isSearching: false,
icons: Object.freeze({
search: searchIcon,
deleteIcon,
@@ -388,20 +390,42 @@ export default {
return this.flagCount > 0;
},
},
created () {
this.searchMembersDebounced = debounce(this.performSearch, 500);
},
methods: {
searchMembers () {
if (!this.searchTerm) {
this.filteredMembers = [];
this.isSearching = false;
return;
}
const searchLower = this.searchTerm.toLowerCase().replace('@', '');
this.filteredMembers = this.members.filter(member => {
const username = member.auth?.local?.username || '';
const displayName = member.profile?.name || '';
return username.toLowerCase().includes(searchLower)
|| displayName.toLowerCase().includes(searchLower);
}).slice(0, 10);
this.isSearching = true;
this.searchMembersDebounced();
},
async performSearch () {
if (!this.searchTerm) {
this.filteredMembers = [];
this.isSearching = false;
return;
}
const searchTerm = this.searchTerm.replace('@', '');
try {
const members = await this.$store.dispatch('members:getChallengeMembers', {
challengeId: this.challengeId,
searchTerm,
includeAllPublicFields: true,
});
this.filteredMembers = members.slice(0, 10);
} catch (err) {
this.filteredMembers = [];
} finally {
this.isSearching = false;
}
},
getMemberDisplayName (member) {
if (member.auth?.local?.username) {