Client: remove unnecessary API calls + members fixes (#12179)
* wip * refactor world state * allow resource to be reloaded when the server is updated * fix #9242 * fix event listeners * remove un-needed code * add tests for asyncResourceFactory reloadOnAppVersionChange * fix double cron notifications and party members showing up in the header after a party invitation is accepted * remove console.log * do not send vm info to loggly due to circular dependency + fix typo * fix #12181 * do not load invites multiple times in members modal * add hover to challenge member count * groups: load members only on demand * minor ui fixes * choose class: fix vue duplicate key warning * minor ui fixes * challanges: load members on demand * add loading spinner * change loading mechanism * fix loading gryphon issues * reduce code duplication
This commit is contained in:
@@ -385,7 +385,7 @@
|
||||
import extend from 'lodash/extend';
|
||||
import groupUtilities from '@/mixins/groupsUtilities';
|
||||
import styleHelper from '@/mixins/styleHelper';
|
||||
import { mapState } from '@/libs/store';
|
||||
import { mapState, mapGetters } from '@/libs/store';
|
||||
import * as Analytics from '@/libs/analytics';
|
||||
import startQuestModal from './startQuestModal';
|
||||
import questDetailsModal from './questDetailsModal';
|
||||
@@ -447,6 +447,7 @@ export default {
|
||||
bronzeGuildBadgeIcon,
|
||||
}),
|
||||
members: [],
|
||||
membersLoaded: false,
|
||||
selectedQuest: {},
|
||||
chat: {
|
||||
submitDisable: false,
|
||||
@@ -455,7 +456,12 @@ export default {
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState({ user: 'user.data' }),
|
||||
...mapState({
|
||||
user: 'user.data',
|
||||
}),
|
||||
...mapGetters({
|
||||
partyMembers: 'party:members',
|
||||
}),
|
||||
partyStore () {
|
||||
return this.$store.state.party;
|
||||
},
|
||||
@@ -487,10 +493,15 @@ export default {
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
async mounted () {
|
||||
if (this.isParty) this.searchId = 'party';
|
||||
if (!this.searchId) this.searchId = this.groupId;
|
||||
this.load();
|
||||
await this.fetchGuild();
|
||||
|
||||
this.$root.$on('updatedGroup', this.onGroupUpdate);
|
||||
},
|
||||
beforeDestroy () {
|
||||
this.$root.$off('updatedGroup', this.onGroupUpdate);
|
||||
},
|
||||
beforeRouteUpdate (to, from, next) {
|
||||
this.$set(this, 'searchId', to.params.groupId);
|
||||
@@ -501,19 +512,9 @@ export default {
|
||||
acceptCommunityGuidelines () {
|
||||
this.$store.dispatch('user:set', { 'flags.communityGuidelinesAccepted': true });
|
||||
},
|
||||
async load () {
|
||||
if (this.isParty) {
|
||||
this.searchId = 'party';
|
||||
// @TODO: Set up from old client. Decide what we need and what we don't
|
||||
// Check Desktop notifs
|
||||
// Load invites
|
||||
}
|
||||
await this.fetchGuild();
|
||||
|
||||
this.$root.$on('updatedGroup', group => {
|
||||
const updatedGroup = extend(this.group, group);
|
||||
this.$set(this.group, updatedGroup);
|
||||
});
|
||||
onGroupUpdate (group) {
|
||||
const updatedGroup = extend(this.group, group);
|
||||
this.$set(this.group, updatedGroup);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -531,6 +532,26 @@ export default {
|
||||
return this.$store.dispatch('members:getGroupMembers', payload);
|
||||
},
|
||||
showMemberModal () {
|
||||
this.$store.state.memberModalOptions.loading = true;
|
||||
|
||||
if (this.isParty) {
|
||||
this.membersLoaded = true;
|
||||
this.members = this.partyMembers;
|
||||
this.$store.state.memberModalOptions.loading = false;
|
||||
} else if (!this.membersLoaded) {
|
||||
this.membersLoaded = true;
|
||||
|
||||
this.loadMembers({
|
||||
groupId: this.group._id,
|
||||
includeAllPublicFields: true,
|
||||
}).then(m => {
|
||||
this.members.push(...m);
|
||||
this.$store.state.memberModalOptions.loading = false;
|
||||
});
|
||||
} else {
|
||||
this.$store.state.memberModalOptions.loading = false;
|
||||
}
|
||||
|
||||
this.$root.$emit('habitica:show-member-modal', {
|
||||
groupId: this.group._id,
|
||||
group: this.group,
|
||||
@@ -565,19 +586,13 @@ export default {
|
||||
|
||||
const groupId = this.searchId === 'party' ? this.user.party._id : this.searchId;
|
||||
if (this.hasUnreadMessages(groupId)) {
|
||||
// Delay by 1sec to make sure it returns after
|
||||
// other requests that don't have the notification marked as read
|
||||
setTimeout(() => {
|
||||
this.$store.dispatch('chat:markChatSeen', { groupId });
|
||||
this.$delete(this.user.newMessages, groupId);
|
||||
}, 1000);
|
||||
const notification = this.user
|
||||
.notifications.find(n => n.type === 'NEW_CHAT_MESSAGE' && n.data.group.id === groupId);
|
||||
const notificationId = notification && notification.id;
|
||||
this.$store.dispatch('chat:markChatSeen', { groupId, notificationId });
|
||||
}
|
||||
|
||||
this.members = await this.loadMembers({
|
||||
groupId: this.group._id,
|
||||
includeAllPublicFields: true,
|
||||
});
|
||||
},
|
||||
// returns the notification id or false
|
||||
hasUnreadMessages (groupId) {
|
||||
if (this.user.newMessages[groupId]) return true;
|
||||
|
||||
|
||||
@@ -99,14 +99,21 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="selectedPage === 'members'">
|
||||
<loading-gryphon v-if="loading" />
|
||||
<div
|
||||
v-if="selectedPage === 'members' && !loading"
|
||||
:class="{'mt-1': invites.length === 0}"
|
||||
>
|
||||
<div
|
||||
v-for="(member, index) in sortedMembers"
|
||||
:key="member._id"
|
||||
class="row"
|
||||
>
|
||||
<div class="col-11 no-padding-left">
|
||||
<member-details :member="member" />
|
||||
<member-details
|
||||
:member="member"
|
||||
:class-badge-position="'next-to-name'"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-1 actions">
|
||||
<b-dropdown right="right">
|
||||
@@ -201,7 +208,7 @@
|
||||
class="row gradient"
|
||||
></div>
|
||||
</div>
|
||||
<div v-if="selectedPage === 'invites'">
|
||||
<div v-if="selectedPage === 'invites' && !loading">
|
||||
<div
|
||||
v-for="(member, index) in invites"
|
||||
:key="member._id"
|
||||
@@ -270,6 +277,8 @@
|
||||
.modal-body {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
padding-bottom: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.member-details {
|
||||
@@ -378,6 +387,7 @@ import isEmpty from 'lodash/isEmpty';
|
||||
import { mapState } from '@/libs/store';
|
||||
|
||||
import removeMemberModal from '@/components/members/removeMemberModal';
|
||||
import loadingGryphon from '@/components/ui/loadingGryphon';
|
||||
import MemberDetails from '../memberDetails';
|
||||
import removeIcon from '@/assets/members/remove.svg';
|
||||
import messageIcon from '@/assets/members/message.svg';
|
||||
@@ -388,6 +398,7 @@ export default {
|
||||
components: {
|
||||
MemberDetails,
|
||||
removeMemberModal,
|
||||
loadingGryphon,
|
||||
},
|
||||
props: ['hideBadge'],
|
||||
data () {
|
||||
@@ -474,6 +485,9 @@ export default {
|
||||
challengeId () {
|
||||
return this.$store.state.memberModalOptions.challengeId;
|
||||
},
|
||||
loading () {
|
||||
return this.$store.state.memberModalOptions.loading;
|
||||
},
|
||||
sortedMembers () {
|
||||
let sortedMembers = this.members.slice(); // shallow clone to avoid infinite loop
|
||||
|
||||
@@ -504,16 +518,6 @@ export default {
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
groupId () {
|
||||
// @TODO: We might not need this since groupId is computed now
|
||||
this.getMembers();
|
||||
},
|
||||
challengeId () {
|
||||
this.getMembers();
|
||||
},
|
||||
group () {
|
||||
this.getMembers();
|
||||
},
|
||||
// Watches `searchTerm` and if present, performs a `searchMembers` action
|
||||
// and usual `getMembers` otherwise
|
||||
searchTerm () {
|
||||
@@ -537,7 +541,7 @@ export default {
|
||||
this.getMembers();
|
||||
});
|
||||
},
|
||||
destroyed () {
|
||||
beforeDestroy () {
|
||||
this.$root.$off('habitica:show-member-modal');
|
||||
},
|
||||
methods: {
|
||||
@@ -558,8 +562,9 @@ export default {
|
||||
});
|
||||
},
|
||||
async getMembers () {
|
||||
const { groupId } = this;
|
||||
this.members = this.$store.state.memberModalOptions.viewingMembers;
|
||||
|
||||
const { groupId } = this;
|
||||
if (groupId && groupId !== 'challenge') {
|
||||
const invites = await this.$store.dispatch('members:getGroupInvites', {
|
||||
groupId,
|
||||
@@ -567,8 +572,6 @@ export default {
|
||||
});
|
||||
this.invites = invites;
|
||||
}
|
||||
|
||||
this.members = this.$store.state.memberModalOptions.viewingMembers;
|
||||
},
|
||||
async clickMember (uid, forceShow) {
|
||||
const user = this.$store.state.user.data;
|
||||
|
||||
@@ -209,7 +209,7 @@ export default {
|
||||
|
||||
this.$root.$on('selectQuest', this.selectQuest);
|
||||
},
|
||||
destroyed () {
|
||||
beforeDestroy () {
|
||||
this.$root.$off('selectQuest', this.selectQuest);
|
||||
},
|
||||
methods: {
|
||||
|
||||
Reference in New Issue
Block a user