Resolve "Add status message from within user menu"
This commit is contained in:
parent
18777ec78d
commit
4edcb02f94
19 changed files with 736 additions and 138 deletions
|
@ -22,6 +22,7 @@ const Api = {
|
||||||
dockerfilePath: '/api/:version/templates/dockerfiles/:key',
|
dockerfilePath: '/api/:version/templates/dockerfiles/:key',
|
||||||
issuableTemplatePath: '/:namespace_path/:project_path/templates/:type/:key',
|
issuableTemplatePath: '/:namespace_path/:project_path/templates/:type/:key',
|
||||||
usersPath: '/api/:version/users.json',
|
usersPath: '/api/:version/users.json',
|
||||||
|
userStatusPath: '/api/:version/user/status',
|
||||||
commitPath: '/api/:version/projects/:id/repository/commits',
|
commitPath: '/api/:version/projects/:id/repository/commits',
|
||||||
commitPipelinesPath: '/:project_id/commit/:sha/pipelines',
|
commitPipelinesPath: '/:project_id/commit/:sha/pipelines',
|
||||||
branchSinglePath: '/api/:version/projects/:id/repository/branches/:branch',
|
branchSinglePath: '/api/:version/projects/:id/repository/branches/:branch',
|
||||||
|
@ -266,6 +267,15 @@ const Api = {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
postUserStatus({ emoji, message }) {
|
||||||
|
const url = Api.buildUrl(this.userStatusPath);
|
||||||
|
|
||||||
|
return axios.put(url, {
|
||||||
|
emoji,
|
||||||
|
message,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
templates(key, params = {}) {
|
templates(key, params = {}) {
|
||||||
const url = Api.buildUrl(this.templatesPath).replace(':key', key);
|
const url = Api.buildUrl(this.templatesPath).replace(':key', key);
|
||||||
|
|
||||||
|
|
|
@ -42,10 +42,11 @@ export class AwardsHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
bindEvents() {
|
bindEvents() {
|
||||||
|
const $parentEl = this.targetContainerEl ? $(this.targetContainerEl) : $(document);
|
||||||
// If the user shows intent let's pre-build the menu
|
// If the user shows intent let's pre-build the menu
|
||||||
this.registerEventListener(
|
this.registerEventListener(
|
||||||
'one',
|
'one',
|
||||||
$(document),
|
$parentEl,
|
||||||
'mouseenter focus',
|
'mouseenter focus',
|
||||||
this.toggleButtonSelector,
|
this.toggleButtonSelector,
|
||||||
'mouseenter focus',
|
'mouseenter focus',
|
||||||
|
@ -58,7 +59,7 @@ export class AwardsHandler {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
this.registerEventListener('on', $(document), 'click', this.toggleButtonSelector, e => {
|
this.registerEventListener('on', $parentEl, 'click', this.toggleButtonSelector, e => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.showEmojiMenu($(e.currentTarget));
|
this.showEmojiMenu($(e.currentTarget));
|
||||||
|
@ -76,7 +77,7 @@ export class AwardsHandler {
|
||||||
});
|
});
|
||||||
|
|
||||||
const emojiButtonSelector = `.js-awards-block .js-emoji-btn, .${this.menuClass} .js-emoji-btn`;
|
const emojiButtonSelector = `.js-awards-block .js-emoji-btn, .${this.menuClass} .js-emoji-btn`;
|
||||||
this.registerEventListener('on', $(document), 'click', emojiButtonSelector, e => {
|
this.registerEventListener('on', $parentEl, 'click', emojiButtonSelector, e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const $target = $(e.currentTarget);
|
const $target = $(e.currentTarget);
|
||||||
const $glEmojiElement = $target.find('gl-emoji');
|
const $glEmojiElement = $target.find('gl-emoji');
|
||||||
|
@ -168,7 +169,8 @@ export class AwardsHandler {
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
document.body.insertAdjacentHTML('beforeend', emojiMenuMarkup);
|
const targetEl = this.targetContainerEl ? this.targetContainerEl : document.body;
|
||||||
|
targetEl.insertAdjacentHTML('beforeend', emojiMenuMarkup);
|
||||||
|
|
||||||
this.addRemainingEmojiMenuCategories();
|
this.addRemainingEmojiMenuCategories();
|
||||||
this.setupSearch();
|
this.setupSearch();
|
||||||
|
@ -250,6 +252,12 @@ export class AwardsHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
positionMenu($menu, $addBtn) {
|
positionMenu($menu, $addBtn) {
|
||||||
|
if (this.targetContainerEl) {
|
||||||
|
return $menu.css({
|
||||||
|
top: `${$addBtn.outerHeight()}px`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const position = $addBtn.data('position');
|
const position = $addBtn.data('position');
|
||||||
// The menu could potentially be off-screen or in a hidden overflow element
|
// The menu could potentially be off-screen or in a hidden overflow element
|
||||||
// So we position the element absolute in the body
|
// So we position the element absolute in the body
|
||||||
|
@ -424,9 +432,7 @@ export class AwardsHandler {
|
||||||
users = origTitle.trim().split(FROM_SENTENCE_REGEX);
|
users = origTitle.trim().split(FROM_SENTENCE_REGEX);
|
||||||
}
|
}
|
||||||
users.unshift('You');
|
users.unshift('You');
|
||||||
return awardBlock
|
return awardBlock.attr('title', this.toSentence(users)).tooltip('_fixTitle');
|
||||||
.attr('title', this.toSentence(users))
|
|
||||||
.tooltip('_fixTitle');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
createAwardButtonForVotesBlock(votesBlock, emojiName) {
|
createAwardButtonForVotesBlock(votesBlock, emojiName) {
|
||||||
|
@ -609,13 +615,11 @@ export class AwardsHandler {
|
||||||
let awardsHandlerPromise = null;
|
let awardsHandlerPromise = null;
|
||||||
export default function loadAwardsHandler(reload = false) {
|
export default function loadAwardsHandler(reload = false) {
|
||||||
if (!awardsHandlerPromise || reload) {
|
if (!awardsHandlerPromise || reload) {
|
||||||
awardsHandlerPromise = import(/* webpackChunkName: 'emoji' */ './emoji').then(
|
awardsHandlerPromise = import(/* webpackChunkName: 'emoji' */ './emoji').then(Emoji => {
|
||||||
Emoji => {
|
const awardsHandler = new AwardsHandler(Emoji);
|
||||||
const awardsHandler = new AwardsHandler(Emoji);
|
awardsHandler.bindEvents();
|
||||||
awardsHandler.bindEvents();
|
return awardsHandler;
|
||||||
return awardsHandler;
|
});
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return awardsHandlerPromise;
|
return awardsHandlerPromise;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
|
import Vue from 'vue';
|
||||||
|
import Translate from '~/vue_shared/translate';
|
||||||
import { highCountTrim } from '~/lib/utils/text_utility';
|
import { highCountTrim } from '~/lib/utils/text_utility';
|
||||||
|
import SetStatusModalTrigger from './set_status_modal/set_status_modal_trigger.vue';
|
||||||
|
import SetStatusModalWrapper from './set_status_modal/set_status_modal_wrapper.vue';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates todo counter when todos are toggled.
|
* Updates todo counter when todos are toggled.
|
||||||
|
@ -17,3 +21,54 @@ export default function initTodoToggle() {
|
||||||
$todoPendingCount.toggleClass('hidden', parsedCount === 0);
|
$todoPendingCount.toggleClass('hidden', parsedCount === 0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const setStatusModalTriggerEl = document.querySelector('.js-set-status-modal-trigger');
|
||||||
|
const setStatusModalWrapperEl = document.querySelector('.js-set-status-modal-wrapper');
|
||||||
|
|
||||||
|
if (setStatusModalTriggerEl || setStatusModalWrapperEl) {
|
||||||
|
Vue.use(Translate);
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-new
|
||||||
|
new Vue({
|
||||||
|
el: setStatusModalTriggerEl,
|
||||||
|
data() {
|
||||||
|
const { hasStatus } = this.$options.el.dataset;
|
||||||
|
|
||||||
|
return {
|
||||||
|
hasStatus: hasStatus === 'true',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
render(createElement) {
|
||||||
|
return createElement(SetStatusModalTrigger, {
|
||||||
|
props: {
|
||||||
|
hasStatus: this.hasStatus,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-new
|
||||||
|
new Vue({
|
||||||
|
el: setStatusModalWrapperEl,
|
||||||
|
data() {
|
||||||
|
const { currentEmoji, currentMessage } = this.$options.el.dataset;
|
||||||
|
|
||||||
|
return {
|
||||||
|
currentEmoji,
|
||||||
|
currentMessage,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
render(createElement) {
|
||||||
|
const { currentEmoji, currentMessage } = this;
|
||||||
|
|
||||||
|
return createElement(SetStatusModalWrapper, {
|
||||||
|
props: {
|
||||||
|
currentEmoji,
|
||||||
|
currentMessage,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
|
@ -11,7 +11,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
const statusEmojiField = document.getElementById('js-status-emoji-field');
|
const statusEmojiField = document.getElementById('js-status-emoji-field');
|
||||||
const statusMessageField = document.getElementById('js-status-message-field');
|
const statusMessageField = document.getElementById('js-status-message-field');
|
||||||
|
|
||||||
const toggleNoEmojiPlaceholder = (isVisible) => {
|
const toggleNoEmojiPlaceholder = isVisible => {
|
||||||
const placeholderElement = document.getElementById('js-no-emoji-placeholder');
|
const placeholderElement = document.getElementById('js-no-emoji-placeholder');
|
||||||
placeholderElement.classList.toggle('hidden', !isVisible);
|
placeholderElement.classList.toggle('hidden', !isVisible);
|
||||||
};
|
};
|
||||||
|
@ -69,5 +69,5 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(() => createFlash('Failed to load emoji list!'));
|
.catch(() => createFlash('Failed to load emoji list.'));
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { AwardsHandler } from '~/awards_handler';
|
||||||
|
|
||||||
|
class EmojiMenuInModal extends AwardsHandler {
|
||||||
|
constructor(emoji, toggleButtonSelector, menuClass, selectEmojiCallback, targetContainerEl) {
|
||||||
|
super(emoji);
|
||||||
|
|
||||||
|
this.selectEmojiCallback = selectEmojiCallback;
|
||||||
|
this.toggleButtonSelector = toggleButtonSelector;
|
||||||
|
this.menuClass = menuClass;
|
||||||
|
this.targetContainerEl = targetContainerEl;
|
||||||
|
|
||||||
|
this.bindEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
postEmoji($emojiButton, awardUrl, selectedEmoji, callback) {
|
||||||
|
this.selectEmojiCallback(selectedEmoji, this.emoji.glEmojiTag(selectedEmoji));
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default EmojiMenuInModal;
|
3
app/assets/javascripts/set_status_modal/event_hub.js
Normal file
3
app/assets/javascripts/set_status_modal/event_hub.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
import Vue from 'vue';
|
||||||
|
|
||||||
|
export default new Vue();
|
|
@ -0,0 +1,33 @@
|
||||||
|
<script>
|
||||||
|
import { s__ } from '~/locale';
|
||||||
|
import eventHub from './event_hub';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
hasStatus: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
buttonText() {
|
||||||
|
return this.hasStatus ? s__('SetStatusModal|Edit status') : s__('SetStatusModal|Set status');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
openModal() {
|
||||||
|
eventHub.$emit('openModal');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn menu-item"
|
||||||
|
@click="openModal"
|
||||||
|
>
|
||||||
|
{{ buttonText }}
|
||||||
|
</button>
|
||||||
|
</template>
|
|
@ -0,0 +1,241 @@
|
||||||
|
<script>
|
||||||
|
import $ from 'jquery';
|
||||||
|
import createFlash from '~/flash';
|
||||||
|
import Icon from '~/vue_shared/components/icon.vue';
|
||||||
|
import GfmAutoComplete from '~/gfm_auto_complete';
|
||||||
|
import { __, s__ } from '~/locale';
|
||||||
|
import Api from '~/api';
|
||||||
|
import eventHub from './event_hub';
|
||||||
|
import EmojiMenuInModal from './emoji_menu_in_modal';
|
||||||
|
|
||||||
|
const emojiMenuClass = 'js-modal-status-emoji-menu';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
Icon,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
currentEmoji: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
currentMessage: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
defaultEmojiTag: '',
|
||||||
|
emoji: this.currentEmoji,
|
||||||
|
emojiMenu: null,
|
||||||
|
emojiTag: '',
|
||||||
|
isEmojiMenuVisible: false,
|
||||||
|
message: this.currentMessage,
|
||||||
|
modalId: 'set-user-status-modal',
|
||||||
|
noEmoji: true,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
isDirty() {
|
||||||
|
return this.message.length || this.emoji.length;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
eventHub.$on('openModal', this.openModal);
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
this.emojiMenu.destroy();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
openModal() {
|
||||||
|
this.$root.$emit('bv::show::modal', this.modalId);
|
||||||
|
},
|
||||||
|
closeModal() {
|
||||||
|
this.$root.$emit('bv::hide::modal', this.modalId);
|
||||||
|
},
|
||||||
|
setupEmojiListAndAutocomplete() {
|
||||||
|
const toggleEmojiMenuButtonSelector = '#set-user-status-modal .js-toggle-emoji-menu';
|
||||||
|
const emojiAutocomplete = new GfmAutoComplete();
|
||||||
|
emojiAutocomplete.setup($(this.$refs.statusMessageField), { emojis: true });
|
||||||
|
|
||||||
|
import(/* webpackChunkName: 'emoji' */ '~/emoji')
|
||||||
|
.then(Emoji => {
|
||||||
|
if (this.emoji) {
|
||||||
|
this.emojiTag = Emoji.glEmojiTag(this.emoji);
|
||||||
|
}
|
||||||
|
this.noEmoji = this.emoji === '';
|
||||||
|
this.defaultEmojiTag = Emoji.glEmojiTag('speech_balloon');
|
||||||
|
|
||||||
|
this.emojiMenu = new EmojiMenuInModal(
|
||||||
|
Emoji,
|
||||||
|
toggleEmojiMenuButtonSelector,
|
||||||
|
emojiMenuClass,
|
||||||
|
this.setEmoji,
|
||||||
|
this.$refs.userStatusForm,
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.catch(() => createFlash(__('Failed to load emoji list.')));
|
||||||
|
},
|
||||||
|
showEmojiMenu() {
|
||||||
|
this.isEmojiMenuVisible = true;
|
||||||
|
this.emojiMenu.showEmojiMenu($(this.$refs.toggleEmojiMenuButton));
|
||||||
|
},
|
||||||
|
hideEmojiMenu() {
|
||||||
|
if (!this.isEmojiMenuVisible) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isEmojiMenuVisible = false;
|
||||||
|
this.emojiMenu.hideMenuElement($(`.${emojiMenuClass}`));
|
||||||
|
},
|
||||||
|
setDefaultEmoji() {
|
||||||
|
const { emojiTag } = this;
|
||||||
|
const hasStatusMessage = this.message;
|
||||||
|
if (hasStatusMessage && emojiTag) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasStatusMessage) {
|
||||||
|
this.noEmoji = false;
|
||||||
|
this.emojiTag = this.defaultEmojiTag;
|
||||||
|
} else if (emojiTag === this.defaultEmojiTag) {
|
||||||
|
this.noEmoji = true;
|
||||||
|
this.clearEmoji();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setEmoji(emoji, emojiTag) {
|
||||||
|
this.emoji = emoji;
|
||||||
|
this.noEmoji = false;
|
||||||
|
this.clearEmoji();
|
||||||
|
this.emojiTag = emojiTag;
|
||||||
|
},
|
||||||
|
clearEmoji() {
|
||||||
|
if (this.emojiTag) {
|
||||||
|
this.emojiTag = '';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
clearStatusInputs() {
|
||||||
|
this.emoji = '';
|
||||||
|
this.message = '';
|
||||||
|
this.noEmoji = true;
|
||||||
|
this.clearEmoji();
|
||||||
|
this.hideEmojiMenu();
|
||||||
|
},
|
||||||
|
removeStatus() {
|
||||||
|
this.clearStatusInputs();
|
||||||
|
this.setStatus();
|
||||||
|
},
|
||||||
|
setStatus() {
|
||||||
|
const { emoji, message } = this;
|
||||||
|
|
||||||
|
Api.postUserStatus({
|
||||||
|
emoji,
|
||||||
|
message,
|
||||||
|
})
|
||||||
|
.then(this.onUpdateSuccess)
|
||||||
|
.catch(this.onUpdateFail);
|
||||||
|
},
|
||||||
|
onUpdateSuccess() {
|
||||||
|
this.closeModal();
|
||||||
|
window.location.reload();
|
||||||
|
},
|
||||||
|
onUpdateFail() {
|
||||||
|
createFlash(
|
||||||
|
s__("SetStatusModal|Sorry, we weren't able to set your status. Please try again later."),
|
||||||
|
);
|
||||||
|
|
||||||
|
this.closeModal();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<gl-ui-modal
|
||||||
|
:title="s__('SetStatusModal|Set a status')"
|
||||||
|
:modal-id="modalId"
|
||||||
|
:ok-title="s__('SetStatusModal|Set status')"
|
||||||
|
:cancel-title="s__('SetStatusModal|Remove status')"
|
||||||
|
ok-variant="success"
|
||||||
|
class="set-user-status-modal"
|
||||||
|
@shown="setupEmojiListAndAutocomplete"
|
||||||
|
@hide="hideEmojiMenu"
|
||||||
|
@ok="setStatus"
|
||||||
|
@cancel="removeStatus"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
v-model="emoji"
|
||||||
|
class="js-status-emoji-field"
|
||||||
|
type="hidden"
|
||||||
|
name="user[status][emoji]"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
ref="userStatusForm"
|
||||||
|
class="form-group position-relative m-0"
|
||||||
|
>
|
||||||
|
<div class="input-group">
|
||||||
|
<span class="input-group-btn">
|
||||||
|
<button
|
||||||
|
ref="toggleEmojiMenuButton"
|
||||||
|
v-gl-tooltip.bottom
|
||||||
|
:title="s__('SetStatusModal|Add status emoji')"
|
||||||
|
:aria-label="s__('SetStatusModal|Add status emoji')"
|
||||||
|
name="button"
|
||||||
|
type="button"
|
||||||
|
class="js-toggle-emoji-menu emoji-menu-toggle-button btn"
|
||||||
|
@click="showEmojiMenu"
|
||||||
|
>
|
||||||
|
<span v-html="emojiTag"></span>
|
||||||
|
<span
|
||||||
|
v-show="noEmoji"
|
||||||
|
class="js-no-emoji-placeholder no-emoji-placeholder position-relative"
|
||||||
|
>
|
||||||
|
<icon
|
||||||
|
name="emoji_slightly_smiling_face"
|
||||||
|
css-classes="award-control-icon-neutral"
|
||||||
|
/>
|
||||||
|
<icon
|
||||||
|
name="emoji_smiley"
|
||||||
|
css-classes="award-control-icon-positive"
|
||||||
|
/>
|
||||||
|
<icon
|
||||||
|
name="emoji_smile"
|
||||||
|
css-classes="award-control-icon-super-positive"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
<input
|
||||||
|
ref="statusMessageField"
|
||||||
|
v-model="message"
|
||||||
|
:placeholder="s__('SetStatusModal|What\'s your status?')"
|
||||||
|
type="text"
|
||||||
|
class="form-control form-control input-lg js-status-message-field"
|
||||||
|
name="user[status][message]"
|
||||||
|
@keyup="setDefaultEmoji"
|
||||||
|
@keyup.enter.prevent
|
||||||
|
@click="hideEmojiMenu"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
v-show="isDirty"
|
||||||
|
class="input-group-btn"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
v-gl-tooltip.bottom
|
||||||
|
:title="s__('SetStatusModal|Clear status')"
|
||||||
|
:aria-label="s__('SetStatusModal|Clear status')"
|
||||||
|
name="button"
|
||||||
|
type="button"
|
||||||
|
class="js-clear-user-status-button clear-user-status btn"
|
||||||
|
@click="clearStatusInputs()"
|
||||||
|
>
|
||||||
|
<icon name="close" />
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</gl-ui-modal>
|
||||||
|
</template>
|
|
@ -529,9 +529,10 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-user {
|
.header-user {
|
||||||
.dropdown-menu {
|
&.show .dropdown-menu {
|
||||||
width: auto;
|
width: auto;
|
||||||
min-width: unset;
|
min-width: unset;
|
||||||
|
max-height: 323px;
|
||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
color: $gl-text-color;
|
color: $gl-text-color;
|
||||||
left: auto;
|
left: auto;
|
||||||
|
@ -542,6 +543,18 @@
|
||||||
.user-name {
|
.user-name {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.user-status-emoji {
|
||||||
|
margin-right: 0;
|
||||||
|
display: block;
|
||||||
|
vertical-align: text-top;
|
||||||
|
max-width: 148px;
|
||||||
|
font-size: 12px;
|
||||||
|
|
||||||
|
gl-emoji {
|
||||||
|
font-size: $gl-font-size;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
|
@ -573,3 +586,24 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.set-user-status-modal {
|
||||||
|
.modal-body {
|
||||||
|
min-height: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-lg {
|
||||||
|
max-width: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-emoji-placeholder,
|
||||||
|
.clear-user-status {
|
||||||
|
svg {
|
||||||
|
fill: $gl-text-color-secondary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.emoji-menu-toggle-button {
|
||||||
|
@include emoji-menu-toggle-button;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -266,3 +266,59 @@
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@mixin emoji-menu-toggle-button {
|
||||||
|
line-height: 1;
|
||||||
|
padding: 0;
|
||||||
|
min-width: 16px;
|
||||||
|
color: $gray-darkest;
|
||||||
|
fill: $gray-darkest;
|
||||||
|
|
||||||
|
.fa {
|
||||||
|
position: relative;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
@include btn-svg;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.award-control-icon-positive,
|
||||||
|
.award-control-icon-super-positive {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&.is-active {
|
||||||
|
.danger-highlight {
|
||||||
|
color: $red-500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-highlight {
|
||||||
|
color: $blue-600;
|
||||||
|
fill: $blue-600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.award-control-icon-neutral {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.award-control-icon-positive {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-active {
|
||||||
|
.award-control-icon-positive {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.award-control-icon-super-positive {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -314,7 +314,8 @@ $diff-jagged-border-gradient-color: darken($white-normal, 8%);
|
||||||
$monospace-font: 'Menlo', 'DejaVu Sans Mono', 'Liberation Mono', 'Consolas', 'Ubuntu Mono',
|
$monospace-font: 'Menlo', 'DejaVu Sans Mono', 'Liberation Mono', 'Consolas', 'Ubuntu Mono',
|
||||||
'Courier New', 'andale mono', 'lucida console', monospace;
|
'Courier New', 'andale mono', 'lucida console', monospace;
|
||||||
$regular-font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell,
|
$regular-font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell,
|
||||||
'Helvetica Neue', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
'Helvetica Neue', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
|
||||||
|
'Noto Color Emoji';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Dropdowns
|
* Dropdowns
|
||||||
|
@ -634,5 +635,4 @@ Modals
|
||||||
*/
|
*/
|
||||||
$modal-body-height: 134px;
|
$modal-body-height: 134px;
|
||||||
|
|
||||||
|
|
||||||
$priority-label-empty-state-width: 114px;
|
$priority-label-empty-state-width: 114px;
|
||||||
|
|
|
@ -519,59 +519,7 @@ ul.notes {
|
||||||
}
|
}
|
||||||
|
|
||||||
.note-action-button {
|
.note-action-button {
|
||||||
line-height: 1;
|
@include emoji-menu-toggle-button;
|
||||||
padding: 0;
|
|
||||||
min-width: 16px;
|
|
||||||
color: $gray-darkest;
|
|
||||||
fill: $gray-darkest;
|
|
||||||
|
|
||||||
.fa {
|
|
||||||
position: relative;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
svg {
|
|
||||||
@include btn-svg;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.award-control-icon-positive,
|
|
||||||
.award-control-icon-super-positive {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&.is-active {
|
|
||||||
.danger-highlight {
|
|
||||||
color: $red-500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.link-highlight {
|
|
||||||
color: $blue-600;
|
|
||||||
fill: $blue-600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.award-control-icon-neutral {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.award-control-icon-positive {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.is-active {
|
|
||||||
.award-control-icon-positive {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.award-control-icon-super-positive {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.discussion-toggle-button {
|
.discussion-toggle-button {
|
||||||
|
|
|
@ -81,14 +81,14 @@
|
||||||
// Middle dot divider between each element in a list of items.
|
// Middle dot divider between each element in a list of items.
|
||||||
.middle-dot-divider {
|
.middle-dot-divider {
|
||||||
&::after {
|
&::after {
|
||||||
content: "\00B7"; // Middle Dot
|
content: '\00B7'; // Middle Dot
|
||||||
padding: 0 6px;
|
padding: 0 6px;
|
||||||
font-weight: $gl-font-weight-bold;
|
font-weight: $gl-font-weight-bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:last-child {
|
&:last-child {
|
||||||
&::after {
|
&::after {
|
||||||
content: "";
|
content: '';
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -191,7 +191,6 @@
|
||||||
@include media-breakpoint-down(xs) {
|
@include media-breakpoint-down(xs) {
|
||||||
width: auto;
|
width: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.profile-crop-image-container {
|
.profile-crop-image-container {
|
||||||
|
@ -215,7 +214,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.user-profile {
|
.user-profile {
|
||||||
.cover-controls a {
|
.cover-controls a {
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
|
@ -418,7 +416,7 @@ table.u2f-registrations {
|
||||||
}
|
}
|
||||||
|
|
||||||
&.unverified {
|
&.unverified {
|
||||||
@include status-color($gray-dark, color("gray"), $common-gray-dark);
|
@include status-color($gray-dark, color('gray'), $common-gray-dark);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -431,7 +429,7 @@ table.u2f-registrations {
|
||||||
}
|
}
|
||||||
|
|
||||||
.emoji-menu-toggle-button {
|
.emoji-menu-toggle-button {
|
||||||
@extend .note-action-button;
|
@include emoji-menu-toggle-button;
|
||||||
|
|
||||||
.no-emoji-placeholder {
|
.no-emoji-placeholder {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
|
@ -5,7 +5,14 @@
|
||||||
.user-name.bold
|
.user-name.bold
|
||||||
= current_user.name
|
= current_user.name
|
||||||
= current_user.to_reference
|
= current_user.to_reference
|
||||||
|
- if current_user.status
|
||||||
|
.user-status-emoji.str-truncated.has-tooltip{ title: current_user.status.message_html, data: { html: 'true', placement: 'bottom' } }
|
||||||
|
= emoji_icon current_user.status.emoji
|
||||||
|
= current_user.status.message_html.html_safe
|
||||||
%li.divider
|
%li.divider
|
||||||
|
- if can?(current_user, :update_user_status, current_user)
|
||||||
|
%li
|
||||||
|
.js-set-status-modal-trigger{ data: { has_status: current_user.status.present? ? 'true' : 'false' } }
|
||||||
- if current_user_menu?(:profile)
|
- if current_user_menu?(:profile)
|
||||||
%li
|
%li
|
||||||
= link_to s_("CurrentUser|Profile"), current_user, class: 'profile-link', data: { user: current_user.username }
|
= link_to s_("CurrentUser|Profile"), current_user, class: 'profile-link', data: { user: current_user.username }
|
||||||
|
|
|
@ -74,3 +74,6 @@
|
||||||
%span.sr-only= _('Toggle navigation')
|
%span.sr-only= _('Toggle navigation')
|
||||||
= sprite_icon('ellipsis_h', size: 12, css_class: 'more-icon js-navbar-toggle-right')
|
= sprite_icon('ellipsis_h', size: 12, css_class: 'more-icon js-navbar-toggle-right')
|
||||||
= sprite_icon('close', size: 12, css_class: 'close-icon js-navbar-toggle-left')
|
= sprite_icon('close', size: 12, css_class: 'close-icon js-navbar-toggle-left')
|
||||||
|
|
||||||
|
- if can?(current_user, :update_user_status, current_user)
|
||||||
|
.js-set-status-modal-wrapper{ data: { current_emoji: current_user.status.present? ? current_user.status.emoji : '', current_message: current_user.status.present? ? current_user.status.message : '' } }
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Set user status from within user menu
|
||||||
|
merge_request: 21643
|
||||||
|
author:
|
||||||
|
type: added
|
|
@ -115,6 +115,13 @@ Please be aware that your status is publicly visible even if your [profile is pr
|
||||||
|
|
||||||
To set your current status:
|
To set your current status:
|
||||||
|
|
||||||
|
1. Open the user menu in the top-right corner of the navigation bar.
|
||||||
|
1. Hit **Set status**, or **Edit status** if you have already set a status.
|
||||||
|
1. Set the emoji and/or status message to your liking.
|
||||||
|
1. Hit **Set status**. Alternatively, you can also hit **Remove status** to remove your user status entirely.
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
1. Navigate to your personal [profile settings](#profile-settings).
|
1. Navigate to your personal [profile settings](#profile-settings).
|
||||||
1. In the text field below `Your status`, enter your status message.
|
1. In the text field below `Your status`, enter your status message.
|
||||||
1. Select an emoji from the dropdown if you like.
|
1. Select an emoji from the dropdown if you like.
|
||||||
|
|
|
@ -2722,6 +2722,9 @@ msgstr ""
|
||||||
msgid "Failed to check related branches."
|
msgid "Failed to check related branches."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Failed to load emoji list."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Failed to remove issue from board, please try again."
|
msgid "Failed to remove issue from board, please try again."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -5445,6 +5448,30 @@ msgstr ""
|
||||||
msgid "SetPasswordToCloneLink|set a password"
|
msgid "SetPasswordToCloneLink|set a password"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "SetStatusModal|Add status emoji"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "SetStatusModal|Clear status"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "SetStatusModal|Edit status"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "SetStatusModal|Remove status"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "SetStatusModal|Set a status"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "SetStatusModal|Set status"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "SetStatusModal|Sorry, we weren't able to set your status. Please try again later."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "SetStatusModal|What's your status?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Settings"
|
msgid "Settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
@ -61,83 +61,229 @@ describe 'User edit profile' do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'user status', :js do
|
context 'user status', :js do
|
||||||
def select_emoji(emoji_name)
|
def select_emoji(emoji_name, is_modal = false)
|
||||||
|
emoji_menu_class = is_modal ? '.js-modal-status-emoji-menu' : '.js-status-emoji-menu'
|
||||||
toggle_button = find('.js-toggle-emoji-menu')
|
toggle_button = find('.js-toggle-emoji-menu')
|
||||||
toggle_button.click
|
toggle_button.click
|
||||||
emoji_button = find(%Q{.js-status-emoji-menu .js-emoji-btn gl-emoji[data-name="#{emoji_name}"]})
|
emoji_button = find(%Q{#{emoji_menu_class} .js-emoji-btn gl-emoji[data-name="#{emoji_name}"]})
|
||||||
emoji_button.click
|
emoji_button.click
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'shows the user status form' do
|
context 'profile edit form' do
|
||||||
visit(profile_path)
|
it 'shows the user status form' do
|
||||||
|
visit(profile_path)
|
||||||
|
|
||||||
expect(page).to have_content('Current status')
|
expect(page).to have_content('Current status')
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'adds emoji to user status' do
|
it 'adds emoji to user status' do
|
||||||
emoji = 'biohazard'
|
emoji = 'biohazard'
|
||||||
visit(profile_path)
|
visit(profile_path)
|
||||||
select_emoji(emoji)
|
select_emoji(emoji)
|
||||||
submit_settings
|
submit_settings
|
||||||
|
|
||||||
visit user_path(user)
|
visit user_path(user)
|
||||||
within('.cover-status') do
|
within('.cover-status') do
|
||||||
expect(page).to have_emoji(emoji)
|
expect(page).to have_emoji(emoji)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'adds message to user status' do
|
||||||
|
message = 'I have something to say'
|
||||||
|
visit(profile_path)
|
||||||
|
fill_in 'js-status-message-field', with: message
|
||||||
|
submit_settings
|
||||||
|
|
||||||
|
visit user_path(user)
|
||||||
|
within('.cover-status') do
|
||||||
|
expect(page).to have_emoji('speech_balloon')
|
||||||
|
expect(page).to have_content message
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'adds message and emoji to user status' do
|
||||||
|
emoji = 'tanabata_tree'
|
||||||
|
message = 'Playing outside'
|
||||||
|
visit(profile_path)
|
||||||
|
select_emoji(emoji)
|
||||||
|
fill_in 'js-status-message-field', with: message
|
||||||
|
submit_settings
|
||||||
|
|
||||||
|
visit user_path(user)
|
||||||
|
within('.cover-status') do
|
||||||
|
expect(page).to have_emoji(emoji)
|
||||||
|
expect(page).to have_content message
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'clears the user status' do
|
||||||
|
user_status = create(:user_status, user: user, message: 'Eating bread', emoji: 'stuffed_flatbread')
|
||||||
|
|
||||||
|
visit user_path(user)
|
||||||
|
within('.cover-status') do
|
||||||
|
expect(page).to have_emoji(user_status.emoji)
|
||||||
|
expect(page).to have_content user_status.message
|
||||||
|
end
|
||||||
|
|
||||||
|
visit(profile_path)
|
||||||
|
click_button 'js-clear-user-status-button'
|
||||||
|
submit_settings
|
||||||
|
|
||||||
|
visit user_path(user)
|
||||||
|
expect(page).not_to have_selector '.cover-status'
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'displays a default emoji if only message is entered' do
|
||||||
|
message = 'a status without emoji'
|
||||||
|
visit(profile_path)
|
||||||
|
fill_in 'js-status-message-field', with: message
|
||||||
|
|
||||||
|
within('.js-toggle-emoji-menu') do
|
||||||
|
expect(page).to have_emoji('speech_balloon')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'adds message to user status' do
|
context 'user menu' do
|
||||||
message = 'I have something to say'
|
def open_user_status_modal
|
||||||
visit(profile_path)
|
find('.header-user-dropdown-toggle').click
|
||||||
fill_in 'js-status-message-field', with: message
|
|
||||||
submit_settings
|
|
||||||
|
|
||||||
visit user_path(user)
|
page.within ".header-user" do
|
||||||
within('.cover-status') do
|
click_button 'Set status'
|
||||||
expect(page).to have_emoji('speech_balloon')
|
end
|
||||||
expect(page).to have_content message
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'adds message and emoji to user status' do
|
|
||||||
emoji = 'tanabata_tree'
|
|
||||||
message = 'Playing outside'
|
|
||||||
visit(profile_path)
|
|
||||||
select_emoji(emoji)
|
|
||||||
fill_in 'js-status-message-field', with: message
|
|
||||||
submit_settings
|
|
||||||
|
|
||||||
visit user_path(user)
|
|
||||||
within('.cover-status') do
|
|
||||||
expect(page).to have_emoji(emoji)
|
|
||||||
expect(page).to have_content message
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'clears the user status' do
|
|
||||||
user_status = create(:user_status, user: user, message: 'Eating bread', emoji: 'stuffed_flatbread')
|
|
||||||
|
|
||||||
visit user_path(user)
|
|
||||||
within('.cover-status') do
|
|
||||||
expect(page).to have_emoji(user_status.emoji)
|
|
||||||
expect(page).to have_content user_status.message
|
|
||||||
end
|
end
|
||||||
|
|
||||||
visit(profile_path)
|
def set_user_status_in_modal
|
||||||
click_button 'js-clear-user-status-button'
|
page.within "#set-user-status-modal" do
|
||||||
submit_settings
|
click_button 'Set status'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
visit user_path(user)
|
before do
|
||||||
expect(page).not_to have_selector '.cover-status'
|
visit root_path(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'displays a default emoji if only message is entered' do
|
it 'shows the "Set status" menu item in the user menu' do
|
||||||
message = 'a status without emoji'
|
find('.header-user-dropdown-toggle').click
|
||||||
visit(profile_path)
|
|
||||||
fill_in 'js-status-message-field', with: message
|
|
||||||
|
|
||||||
within('.js-toggle-emoji-menu') do
|
page.within ".header-user" do
|
||||||
expect(page).to have_emoji('speech_balloon')
|
expect(page).to have_content('Set status')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'shows the "Edit status" menu item in the user menu' do
|
||||||
|
user_status = create(:user_status, user: user, message: 'Eating bread', emoji: 'stuffed_flatbread')
|
||||||
|
visit root_path(user)
|
||||||
|
|
||||||
|
find('.header-user-dropdown-toggle').click
|
||||||
|
|
||||||
|
page.within ".header-user" do
|
||||||
|
expect(page).to have_emoji(user_status.emoji)
|
||||||
|
expect(page).to have_content user_status.message
|
||||||
|
expect(page).to have_content('Edit status')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'shows user status modal' do
|
||||||
|
open_user_status_modal
|
||||||
|
|
||||||
|
expect(page.find('#set-user-status-modal')).to be_visible
|
||||||
|
expect(page).to have_content('Set a status')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'adds emoji to user status' do
|
||||||
|
emoji = 'biohazard'
|
||||||
|
open_user_status_modal
|
||||||
|
select_emoji(emoji, true)
|
||||||
|
set_user_status_in_modal
|
||||||
|
|
||||||
|
visit user_path(user)
|
||||||
|
within('.cover-status') do
|
||||||
|
expect(page).to have_emoji(emoji)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'adds message to user status' do
|
||||||
|
message = 'I have something to say'
|
||||||
|
open_user_status_modal
|
||||||
|
find('.js-status-message-field').native.send_keys(message)
|
||||||
|
set_user_status_in_modal
|
||||||
|
|
||||||
|
visit user_path(user)
|
||||||
|
within('.cover-status') do
|
||||||
|
expect(page).to have_emoji('speech_balloon')
|
||||||
|
expect(page).to have_content message
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'adds message and emoji to user status' do
|
||||||
|
emoji = 'tanabata_tree'
|
||||||
|
message = 'Playing outside'
|
||||||
|
open_user_status_modal
|
||||||
|
select_emoji(emoji, true)
|
||||||
|
find('.js-status-message-field').native.send_keys(message)
|
||||||
|
set_user_status_in_modal
|
||||||
|
|
||||||
|
visit user_path(user)
|
||||||
|
within('.cover-status') do
|
||||||
|
expect(page).to have_emoji(emoji)
|
||||||
|
expect(page).to have_content message
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'clears the user status with the "X" button' do
|
||||||
|
user_status = create(:user_status, user: user, message: 'Eating bread', emoji: 'stuffed_flatbread')
|
||||||
|
|
||||||
|
visit user_path(user)
|
||||||
|
within('.cover-status') do
|
||||||
|
expect(page).to have_emoji(user_status.emoji)
|
||||||
|
expect(page).to have_content user_status.message
|
||||||
|
end
|
||||||
|
|
||||||
|
find('.header-user-dropdown-toggle').click
|
||||||
|
|
||||||
|
page.within ".header-user" do
|
||||||
|
click_button 'Edit status'
|
||||||
|
end
|
||||||
|
|
||||||
|
find('.js-clear-user-status-button').click
|
||||||
|
set_user_status_in_modal
|
||||||
|
|
||||||
|
visit user_path(user)
|
||||||
|
expect(page).not_to have_selector '.cover-status'
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'clears the user status with the "Remove status" button' do
|
||||||
|
user_status = create(:user_status, user: user, message: 'Eating bread', emoji: 'stuffed_flatbread')
|
||||||
|
|
||||||
|
visit user_path(user)
|
||||||
|
within('.cover-status') do
|
||||||
|
expect(page).to have_emoji(user_status.emoji)
|
||||||
|
expect(page).to have_content user_status.message
|
||||||
|
end
|
||||||
|
|
||||||
|
find('.header-user-dropdown-toggle').click
|
||||||
|
|
||||||
|
page.within ".header-user" do
|
||||||
|
click_button 'Edit status'
|
||||||
|
end
|
||||||
|
|
||||||
|
page.within "#set-user-status-modal" do
|
||||||
|
click_button 'Remove status'
|
||||||
|
end
|
||||||
|
|
||||||
|
visit user_path(user)
|
||||||
|
expect(page).not_to have_selector '.cover-status'
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'displays a default emoji if only message is entered' do
|
||||||
|
message = 'a status without emoji'
|
||||||
|
open_user_status_modal
|
||||||
|
find('.js-status-message-field').native.send_keys(message)
|
||||||
|
|
||||||
|
within('.js-toggle-emoji-menu') do
|
||||||
|
expect(page).to have_emoji('speech_balloon')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue