mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-17 14:47:53 +01:00
Tasks v2 Part 2 (#9236)
* start updating colors for tasks controls * finish updating controls colors * change hoevr behavior * change transition duration * update color with transition * refactor menu wip * wip * upgrade vue deps * fix warnings * fix menu * misc fixes * more fixes * fix badge * fix margins in menu * wip tooltips * tooltips * fix checklist colors * add badges * fix quick add input * add transition to task controls too * add batch add * fix task filtering * finish tasks badges * fix menu * upgrade deps * fix shop items using all the same image * fix animation * disable client tests until we remove phantomjs * revert changes to tasks colors * fix opacity in task modal inputs * remove client unit tests from travis * wip task dropdown * fix z-index for task footer/header * fixes and add files * fixes * bigger clickable area * more space to open task dropdown * droddown position * fix menu position * make sure other dropdowns get closed correctly * fixes * start to fix z-index * draggable = false for task dropdown * fix for dropdown position * implement move to top / bottom * fix push to bottom * typo * fix drag and drop * use standard code * wider click area for dropdown * unify badge look * fix padding * misc fixes * more fixes * make dropdown scrollable * misc fixes * fix padding for notes * use existing code instead of new props
This commit is contained in:
285
website/client/components/header/notificationsDropdown.vue
Normal file
285
website/client/components/header/notificationsDropdown.vue
Normal file
@@ -0,0 +1,285 @@
|
||||
<template lang="pug">
|
||||
menu-dropdown.item-notifications(:right="true")
|
||||
div(slot="dropdown-toggle")
|
||||
div
|
||||
message-count(v-if='notificationsCount > 0', :count="notificationsCount", :top="true")
|
||||
.svg-icon.notifications(v-html="icons.notifications")
|
||||
div(slot="dropdown-content")
|
||||
h4.dropdown-item.dropdown-separated(v-if='!hasNoNotifications()') {{ $t('notifications') }}
|
||||
h4.dropdown-item.toolbar-notifs-no-messages(v-if='hasNoNotifications()') {{ $t('noNotifications') }}
|
||||
a.dropdown-item(v-if='user.party.quest && user.party.quest.RSVPNeeded')
|
||||
div {{ $t('invitedTo', {name: quests.quests[user.party.quest.key].text()}) }}
|
||||
div
|
||||
button.btn.btn-primary(@click.stop='questAccept(user.party._id)') Accept
|
||||
button.btn.btn-primary(@click.stop='questReject(user.party._id)') Reject
|
||||
a.dropdown-item(v-if='user.purchased.plan.mysteryItems.length', @click='go("/inventory/items")')
|
||||
span.glyphicon.glyphicon-gift
|
||||
span {{ $t('newSubscriberItem') }}
|
||||
a.dropdown-item(v-for='(party, index) in user.invitations.parties')
|
||||
div
|
||||
span.glyphicon.glyphicon-user
|
||||
span {{ $t('invitedTo', {name: party.name}) }}
|
||||
div
|
||||
button.btn.btn-primary(@click.stop='accept(party, index, "party")') Accept
|
||||
button.btn.btn-primary(@click.stop='reject(party, index, "party")') Reject
|
||||
a.dropdown-item(v-if='user.flags.cardReceived', @click='go("/inventory/items")')
|
||||
span.glyphicon.glyphicon-envelope
|
||||
span {{ $t('cardReceived') }}
|
||||
a.dropdown-item(@click.stop='clearCards()')
|
||||
a.dropdown-item(v-for='(guild, index) in user.invitations.guilds')
|
||||
div
|
||||
span.glyphicon.glyphicon-user
|
||||
span {{ $t('invitedTo', {name: guild.name}) }}
|
||||
div
|
||||
button.btn.btn-primary(@click.stop='accept(guild, index, "guild")') Accept
|
||||
button.btn.btn-primary(@click.stop='reject(guild, index, "guild")') Reject
|
||||
a.dropdown-item(v-if='user.flags.classSelected && !user.preferences.disableClasses && user.stats.points',
|
||||
@click='go("/user/profile")')
|
||||
span.glyphicon.glyphicon-plus-sign
|
||||
span {{ $t('haveUnallocated', {points: user.stats.points}) }}
|
||||
a.dropdown-item(v-for='message in userNewMessages')
|
||||
span(@click='navigateToGroup(message.key)')
|
||||
span.glyphicon.glyphicon-comment
|
||||
span {{message.name}}
|
||||
span.clear-button(@click.stop='clearMessages(message.key)') Clear
|
||||
a.dropdown-item(v-for='notification in groupNotifications', :key='notification.id')
|
||||
span(:class="groupApprovalNotificationIcon(notification)")
|
||||
span {{notification.data.message}}
|
||||
span.clear-button(@click.stop='viewGroupApprovalNotification(notification)') Clear
|
||||
</template>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
.clear-button {
|
||||
margin-left: .5em;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import axios from 'axios';
|
||||
import isEmpty from 'lodash/isEmpty';
|
||||
import map from 'lodash/map';
|
||||
// import bTooltip from 'bootstrap-vue/lib/directives/tooltip';
|
||||
|
||||
import { mapState } from 'client/libs/store';
|
||||
import * as Analytics from 'client/libs/analytics';
|
||||
import quests from 'common/script/content/quests';
|
||||
import notificationsIcon from 'assets/svg/notifications.svg';
|
||||
import MenuDropdown from '../ui/customMenuDropdown';
|
||||
import MessageCount from './messageCount';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MenuDropdown,
|
||||
MessageCount,
|
||||
},
|
||||
directives: {
|
||||
// bTooltip,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
notifications: notificationsIcon,
|
||||
}),
|
||||
quests,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState({user: 'user.data'}),
|
||||
party () {
|
||||
return {name: ''};
|
||||
// return this.user.party;
|
||||
},
|
||||
userNewMessages () {
|
||||
// @TODO: For some reason data becomes corrupted. We should fix this on the server
|
||||
let userNewMessages = [];
|
||||
for (let key in this.user.newMessages) {
|
||||
let message = this.user.newMessages[key];
|
||||
if (message && message.name && message.value) {
|
||||
message.key = key;
|
||||
userNewMessages.push(message);
|
||||
}
|
||||
}
|
||||
return userNewMessages;
|
||||
},
|
||||
groupNotifications () {
|
||||
return this.$store.state.groupNotifications;
|
||||
},
|
||||
notificationsCount () {
|
||||
let count = 0;
|
||||
|
||||
if (this.user.invitations.parties) {
|
||||
count += this.user.invitations.parties.length;
|
||||
}
|
||||
|
||||
if (this.user.purchased.plan && this.user.purchased.plan.mysteryItems.length) {
|
||||
count++;
|
||||
}
|
||||
|
||||
if (this.user.invitations.guilds) {
|
||||
count += this.user.invitations.guilds.length;
|
||||
}
|
||||
|
||||
if (this.user.flags.classSelected && !this.user.preferences.disableClasses && this.user.stats.points) {
|
||||
count += this.user.stats.points > 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
if (this.userNewMessages) {
|
||||
count += Object.keys(this.userNewMessages).length;
|
||||
}
|
||||
|
||||
count += this.groupNotifications.length;
|
||||
|
||||
return count;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
// @TODO: I hate this function, we can do better with a hashmap
|
||||
selectNotificationValue (mysteryValue, invitationValue, cardValue,
|
||||
unallocatedValue, messageValue, noneValue, groupApprovalRequested, groupApproved) {
|
||||
let user = this.user;
|
||||
|
||||
if (user.purchased && user.purchased.plan && user.purchased.plan.mysteryItems && user.purchased.plan.mysteryItems.length) {
|
||||
return mysteryValue;
|
||||
} else if (user.invitations.parties && user.invitations.parties.length > 0 || user.invitations.guilds && user.invitations.guilds.length > 0) {
|
||||
return invitationValue;
|
||||
} else if (user.flags.cardReceived) {
|
||||
return cardValue;
|
||||
} else if (user.flags.classSelected && !(user.preferences && user.preferences.disableClasses) && user.stats.points) {
|
||||
return unallocatedValue;
|
||||
} else if (!isEmpty(user.newMessages)) {
|
||||
return messageValue;
|
||||
} else if (!isEmpty(this.groupNotifications)) {
|
||||
let groupNotificationTypes = map(this.groupNotifications, 'type');
|
||||
if (groupNotificationTypes.indexOf('GROUP_TASK_APPROVAL') !== -1) {
|
||||
return groupApprovalRequested;
|
||||
} else if (groupNotificationTypes.indexOf('GROUP_TASK_APPROVED') !== -1) {
|
||||
return groupApproved;
|
||||
}
|
||||
return noneValue;
|
||||
} else {
|
||||
return noneValue;
|
||||
}
|
||||
},
|
||||
hasQuestProgress () {
|
||||
let user = this.user;
|
||||
if (user.party.quest) {
|
||||
let userQuest = quests[user.party.quest.key];
|
||||
|
||||
if (!userQuest) {
|
||||
return false;
|
||||
}
|
||||
if (userQuest.boss && user.party.quest.progress.up > 0) {
|
||||
return true;
|
||||
}
|
||||
if (userQuest.collect && user.party.quest.progress.collectedItems > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
getQuestInfo () {
|
||||
let user = this.user;
|
||||
let questInfo = {};
|
||||
if (user.party.quest) {
|
||||
let userQuest = quests[user.party.quest.key];
|
||||
|
||||
questInfo.title = userQuest.text();
|
||||
|
||||
if (userQuest.boss) {
|
||||
questInfo.body = this.$t('questTaskDamage', { damage: user.party.quest.progress.up.toFixed(1) });
|
||||
} else if (userQuest.collect) {
|
||||
questInfo.body = this.$t('questTaskCollection', { items: user.party.quest.progress.collectedItems });
|
||||
}
|
||||
}
|
||||
return questInfo;
|
||||
},
|
||||
clearMessages (key) {
|
||||
this.$store.dispatch('chat:markChatSeen', {groupId: key});
|
||||
this.$delete(this.user.newMessages, key);
|
||||
},
|
||||
clearCards () {
|
||||
this.$store.dispatch('chat:clearCards');
|
||||
},
|
||||
iconClasses () {
|
||||
return this.selectNotificationValue(
|
||||
'glyphicon-gift',
|
||||
'glyphicon-user',
|
||||
'glyphicon-envelope',
|
||||
'glyphicon-plus-sign',
|
||||
'glyphicon-comment',
|
||||
'glyphicon-comment inactive',
|
||||
'glyphicon-question-sign',
|
||||
'glyphicon-ok-sign'
|
||||
);
|
||||
},
|
||||
hasNoNotifications () {
|
||||
return this.selectNotificationValue(false, false, false, false, false, true, false, false);
|
||||
},
|
||||
viewGroupApprovalNotification (notification) {
|
||||
this.$store.state.groupNotifications = this.groupNotifications.filter(groupNotif => {
|
||||
return groupNotif.id !== notification.id;
|
||||
});
|
||||
|
||||
axios.post('/api/v3/notifications/read', {
|
||||
notificationIds: [notification.id],
|
||||
});
|
||||
},
|
||||
groupApprovalNotificationIcon (notification) {
|
||||
if (notification.type === 'GROUP_TASK_APPROVAL') {
|
||||
return 'glyphicon glyphicon-question-sign';
|
||||
} else if (notification.type === 'GROUP_TASK_APPROVED') {
|
||||
return 'glyphicon glyphicon-ok-sign';
|
||||
}
|
||||
},
|
||||
go (path) {
|
||||
this.$router.push(path);
|
||||
},
|
||||
navigateToGroup (key) {
|
||||
if (key === this.party._id || key === this.user.party._id) {
|
||||
this.go('/party');
|
||||
return;
|
||||
}
|
||||
|
||||
this.$router.push({ name: 'guild', params: { groupId: key }});
|
||||
},
|
||||
async reject (group) {
|
||||
await this.$store.dispatch('guilds:rejectInvite', {groupId: group.id});
|
||||
// @TODO: User.sync();
|
||||
},
|
||||
async accept (group, index, type) {
|
||||
if (group.cancelledPlan && !confirm(this.$t('aboutToJoinCancelledGroupPlan'))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (type === 'party') {
|
||||
// @TODO: pretty sure mutability is wrong. Need to check React docs
|
||||
// @TODO mutation to store data should only happen through actions
|
||||
this.user.invitations.parties.splice(index, 1);
|
||||
|
||||
Analytics.updateUser({partyID: group.id});
|
||||
} else {
|
||||
this.user.invitations.guilds.splice(index, 1);
|
||||
}
|
||||
|
||||
if (type === 'party') {
|
||||
this.user.party._id = group.id;
|
||||
this.$router.push('/party');
|
||||
} else {
|
||||
this.user.guilds.push(group.id);
|
||||
this.$router.push(`/groups/guild/${group.id}`);
|
||||
}
|
||||
|
||||
// @TODO: check for party , type: 'myGuilds'
|
||||
await this.$store.dispatch('guilds:join', {guildId: group.id});
|
||||
},
|
||||
async questAccept (partyId) {
|
||||
let quest = await this.$store.dispatch('quests:sendAction', {groupId: partyId, action: 'quests/accept'});
|
||||
this.user.party.quest = quest;
|
||||
},
|
||||
async questReject (partyId) {
|
||||
let quest = await this.$store.dispatch('quests:sendAction', {groupId: partyId, action: 'quests/reject'});
|
||||
this.user.party.quest = quest;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
Reference in New Issue
Block a user