debian-mirror-gitlab/app/assets/javascripts/notes/components/note_awards_list.vue

212 lines
6.3 KiB
Vue
Raw Normal View History

2018-03-17 18:26:18 +05:30
<script>
2018-05-09 12:01:36 +05:30
import { mapActions, mapGetters } from 'vuex';
2018-12-13 13:39:08 +05:30
import Icon from '~/vue_shared/components/icon.vue';
2018-05-09 12:01:36 +05:30
import Flash from '../../flash';
import { glEmojiTag } from '../../emoji';
2019-01-03 12:48:30 +05:30
import tooltip from '../../vue_shared/directives/tooltip';
2018-05-09 12:01:36 +05:30
export default {
2018-12-13 13:39:08 +05:30
components: {
Icon,
},
2018-05-09 12:01:36 +05:30
directives: {
2019-01-03 12:48:30 +05:30
tooltip,
2018-05-09 12:01:36 +05:30
},
props: {
awards: {
type: Array,
required: true,
2018-03-17 18:26:18 +05:30
},
2018-05-09 12:01:36 +05:30
toggleAwardPath: {
type: String,
required: true,
2018-03-17 18:26:18 +05:30
},
2018-05-09 12:01:36 +05:30
noteAuthorId: {
type: Number,
required: true,
2018-03-17 18:26:18 +05:30
},
2018-05-09 12:01:36 +05:30
noteId: {
2018-11-20 20:47:30 +05:30
type: String,
2018-05-09 12:01:36 +05:30
required: true,
2018-03-17 18:26:18 +05:30
},
2018-05-09 12:01:36 +05:30
canAwardEmoji: {
type: Boolean,
required: true,
},
},
computed: {
...mapGetters(['getUserData']),
// `this.awards` is an array with emojis but they are not grouped by emoji name. See below.
// [ { name: foo, user: user1 }, { name: bar, user: user1 }, { name: foo, user: user2 } ]
// This method will group emojis by their name as an Object. See below.
// {
// foo: [ { name: foo, user: user1 }, { name: foo, user: user2 } ],
// bar: [ { name: bar, user: user1 } ]
// }
// We need to do this otherwise we will render the same emoji over and over again.
groupedAwards() {
const awards = this.awards.reduce((acc, award) => {
if (Object.prototype.hasOwnProperty.call(acc, award.name)) {
acc[award.name].push(award);
} else {
Object.assign(acc, { [award.name]: [award] });
2018-03-17 18:26:18 +05:30
}
2018-05-09 12:01:36 +05:30
return acc;
}, {});
const orderedAwards = {};
const { thumbsdown, thumbsup } = awards;
// Always show thumbsup and thumbsdown first
if (thumbsup) {
orderedAwards.thumbsup = thumbsup;
delete awards.thumbsup;
}
if (thumbsdown) {
orderedAwards.thumbsdown = thumbsdown;
delete awards.thumbsdown;
}
return Object.assign({}, orderedAwards, awards);
},
isAuthoredByMe() {
return this.noteAuthorId === this.getUserData.id;
},
},
methods: {
...mapActions(['toggleAwardRequest']),
getAwardHTML(name) {
return glEmojiTag(name);
},
2018-11-20 20:47:30 +05:30
getAwardClassBindings(awardList) {
2018-05-09 12:01:36 +05:30
return {
active: this.hasReactionByCurrentUser(awardList),
2018-11-20 20:47:30 +05:30
disabled: !this.canInteractWithEmoji(),
2018-05-09 12:01:36 +05:30
};
},
2018-11-20 20:47:30 +05:30
canInteractWithEmoji() {
return this.getUserData.id;
2018-05-09 12:01:36 +05:30
},
hasReactionByCurrentUser(awardList) {
2018-11-20 20:47:30 +05:30
return awardList.filter(award => award.user.id === this.getUserData.id).length;
2018-05-09 12:01:36 +05:30
},
awardTitle(awardsList) {
2018-12-13 13:39:08 +05:30
const hasReactionByCurrentUser = this.hasReactionByCurrentUser(awardsList);
2018-05-09 12:01:36 +05:30
const TOOLTIP_NAME_COUNT = hasReactionByCurrentUser ? 9 : 10;
let awardList = awardsList;
// Filter myself from list if I am awarded.
if (hasReactionByCurrentUser) {
2018-12-13 13:39:08 +05:30
awardList = awardList.filter(award => award.user.id !== this.getUserData.id);
2018-05-09 12:01:36 +05:30
}
// Get only 9-10 usernames to show in tooltip text.
2018-12-13 13:39:08 +05:30
const namesToShow = awardList.slice(0, TOOLTIP_NAME_COUNT).map(award => award.user.name);
2018-05-09 12:01:36 +05:30
// Get the remaining list to use in `and x more` text.
2018-12-13 13:39:08 +05:30
const remainingAwardList = awardList.slice(TOOLTIP_NAME_COUNT, awardList.length);
2018-05-09 12:01:36 +05:30
2018-12-13 13:39:08 +05:30
// Add myself to the beginning of the list so title will start with You.
2018-05-09 12:01:36 +05:30
if (hasReactionByCurrentUser) {
namesToShow.unshift('You');
}
let title = '';
// We have 10+ awarded user, join them with comma and add `and x more`.
if (remainingAwardList.length) {
2018-12-13 13:39:08 +05:30
title = `${namesToShow.join(', ')}, and ${remainingAwardList.length} more.`;
2018-05-09 12:01:36 +05:30
} else if (namesToShow.length > 1) {
// Join all names with comma but not the last one, it will be added with and text.
title = namesToShow.slice(0, namesToShow.length - 1).join(', ');
// If we have more than 2 users we need an extra comma before and text.
title += namesToShow.length > 2 ? ',' : '';
title += ` and ${namesToShow.slice(-1)}`; // Append and text
} else {
// We have only 2 users so join them with and.
title = namesToShow.join(' and ');
}
return title;
},
handleAward(awardName) {
if (!this.canAwardEmoji) {
return;
}
let parsedName;
// 100 and 1234 emoji are a number. Callback for v-for click sends it as a string
switch (awardName) {
case '100':
parsedName = 100;
break;
case '1234':
parsedName = 1234;
break;
default:
parsedName = awardName;
break;
}
const data = {
endpoint: this.toggleAwardPath,
noteId: this.noteId,
awardName: parsedName,
};
2018-12-13 13:39:08 +05:30
this.toggleAwardRequest(data).catch(() => Flash('Something went wrong on our end.'));
2018-03-17 18:26:18 +05:30
},
2018-05-09 12:01:36 +05:30
},
};
2018-03-17 18:26:18 +05:30
</script>
<template>
<div class="note-awards">
<div class="awards js-awards-block">
<button
v-for="(awardList, awardName, index) in groupedAwards"
:key="index"
2019-01-03 12:48:30 +05:30
v-tooltip
2018-11-20 20:47:30 +05:30
:class="getAwardClassBindings(awardList)"
2018-03-17 18:26:18 +05:30
:title="awardTitle(awardList)"
class="btn award-control"
2019-01-03 12:48:30 +05:30
data-boundary="viewport"
data-placement="bottom"
2018-11-08 19:23:39 +05:30
type="button"
2019-01-03 12:48:30 +05:30
@click="handleAward(awardName)">
2018-03-17 18:26:18 +05:30
<span v-html="getAwardHTML(awardName)"></span>
2019-01-03 12:48:30 +05:30
<span class="award-control-text js-counter">
{{ awardList.length }}
</span>
2018-03-17 18:26:18 +05:30
</button>
2019-01-03 12:48:30 +05:30
<div
v-if="canAwardEmoji"
class="award-menu-holder">
2018-03-17 18:26:18 +05:30
<button
2019-01-03 12:48:30 +05:30
v-tooltip
2018-03-17 18:26:18 +05:30
:class="{ 'js-user-authored': isAuthoredByMe }"
class="award-control btn js-add-award"
title="Add reaction"
aria-label="Add reaction"
2018-11-08 19:23:39 +05:30
data-boundary="viewport"
2018-03-17 18:26:18 +05:30
data-placement="bottom"
2019-01-03 12:48:30 +05:30
type="button">
2018-12-13 13:39:08 +05:30
<span class="award-control-icon award-control-icon-neutral">
<icon name="emoji_slightly_smiling_face" />
2018-03-17 18:26:18 +05:30
</span>
2018-12-13 13:39:08 +05:30
<span class="award-control-icon award-control-icon-positive">
<icon name="emoji_smiley" />
2018-03-17 18:26:18 +05:30
</span>
2018-12-13 13:39:08 +05:30
<span class="award-control-icon award-control-icon-super-positive">
<icon name="emoji_smiley" />
2018-03-17 18:26:18 +05:30
</span>
<i
aria-hidden="true"
2019-01-03 12:48:30 +05:30
class="fa fa-spinner fa-spin award-control-icon award-control-icon-loading"></i>
2018-03-17 18:26:18 +05:30
</button>
</div>
</div>
</div>
</template>