Files
chatwoot/app/javascript/widget/components/ChatInputWrap.vue
Shivam Mishra 490fc4eaba fix: Remove the usage of asyncComponent in emoji picker (#10232)
This PR has the following fixes

1. preview of article inside the iframe, earlier this didn't work because the iframe didn't get the URL correctly. We fix that by passing the URL is a query instead
2. Emoji picker caused a weird redirect, this was only happening when the chunk was loaded async, this PR changes it to use regular loading instead
2024-10-04 08:10:27 -07:00

227 lines
5.3 KiB
Vue
Executable File

<script>
import { mapGetters } from 'vuex';
import ChatAttachmentButton from 'widget/components/ChatAttachment.vue';
import ChatSendButton from 'widget/components/ChatSendButton.vue';
import configMixin from '../mixins/configMixin';
import FluentIcon from 'shared/components/FluentIcon/Index.vue';
import ResizableTextArea from 'shared/components/ResizableTextArea.vue';
import { useDarkMode } from 'widget/composables/useDarkMode';
import EmojiInput from 'shared/components/emoji/EmojiInput.vue';
export default {
name: 'ChatInputWrap',
components: {
ChatAttachmentButton,
ChatSendButton,
EmojiInput,
FluentIcon,
ResizableTextArea,
},
mixins: [configMixin],
props: {
onSendMessage: {
type: Function,
default: () => {},
},
onSendAttachment: {
type: Function,
default: () => {},
},
},
setup() {
const { getThemeClass } = useDarkMode();
return { getThemeClass };
},
data() {
return {
userInput: '',
showEmojiPicker: false,
isFocused: false,
};
},
computed: {
...mapGetters({
widgetColor: 'appConfig/getWidgetColor',
isWidgetOpen: 'appConfig/getIsWidgetOpen',
}),
showAttachment() {
return this.hasAttachmentsEnabled && this.userInput.length === 0;
},
showSendButton() {
return this.userInput.length > 0;
},
inputColor() {
return `${this.getThemeClass('bg-white', 'dark:bg-slate-600')}
${this.getThemeClass('text-black-900', 'dark:text-slate-50')}`;
},
emojiIconColor() {
return this.showEmojiPicker
? `text-woot-500 ${this.getThemeClass(
'text-black-900',
'dark:text-slate-100'
)}`
: `${this.getThemeClass('text-black-900', 'dark:text-slate-100')}`;
},
},
watch: {
isWidgetOpen(isWidgetOpen) {
if (isWidgetOpen) {
this.focusInput();
}
},
},
unmounted() {
document.removeEventListener('keypress', this.handleEnterKeyPress);
},
mounted() {
document.addEventListener('keypress', this.handleEnterKeyPress);
if (this.isWidgetOpen) {
this.focusInput();
}
},
methods: {
onBlur() {
this.isFocused = false;
},
onFocus() {
this.isFocused = true;
},
handleButtonClick() {
if (this.userInput && this.userInput.trim()) {
this.onSendMessage(this.userInput);
}
this.userInput = '';
this.focusInput();
},
handleEnterKeyPress(e) {
if (e.keyCode === 13 && !e.shiftKey) {
e.preventDefault();
this.handleButtonClick();
}
},
toggleEmojiPicker() {
this.showEmojiPicker = !this.showEmojiPicker;
},
hideEmojiPicker(e) {
if (this.showEmojiPicker) {
e.stopPropagation();
this.toggleEmojiPicker();
}
},
emojiOnClick(emoji) {
this.userInput = `${this.userInput}${emoji} `;
},
onTypingOff() {
this.toggleTyping('off');
},
onTypingOn() {
this.toggleTyping('on');
},
toggleTyping(typingStatus) {
this.$store.dispatch('conversation/toggleUserTyping', { typingStatus });
},
focusInput() {
this.$refs.chatInput.focus();
},
},
};
</script>
<template>
<div
class="chat-message--input is-focused"
:class="getThemeClass('bg-white ', 'dark:bg-slate-600')"
@keydown.esc="hideEmojiPicker"
>
<ResizableTextArea
id="chat-input"
ref="chatInput"
v-model="userInput"
:rows="1"
:aria-label="$t('CHAT_PLACEHOLDER')"
:placeholder="$t('CHAT_PLACEHOLDER')"
class="form-input user-message-input is-focused"
:class="inputColor"
@typing-off="onTypingOff"
@typing-on="onTypingOn"
@focus="onFocus"
@blur="onBlur"
/>
<div class="button-wrap">
<ChatAttachmentButton
v-if="showAttachment"
:class="getThemeClass('text-black-900', 'dark:text-slate-100')"
:on-attach="onSendAttachment"
/>
<button
v-if="hasEmojiPickerEnabled"
class="flex items-center justify-center icon-button"
:aria-label="$t('EMOJI.ARIA_LABEL')"
@click="toggleEmojiPicker"
>
<FluentIcon icon="emoji" :class="emojiIconColor" />
</button>
<EmojiInput
v-if="showEmojiPicker"
v-on-clickaway="hideEmojiPicker"
:on-click="emojiOnClick"
@keydown.esc="hideEmojiPicker"
/>
<ChatSendButton
v-if="showSendButton"
:color="widgetColor"
@click="handleButtonClick"
/>
</div>
</div>
</template>
<style scoped lang="scss">
@import 'widget/assets/scss/variables.scss';
@import 'widget/assets/scss/mixins.scss';
.chat-message--input {
align-items: center;
display: flex;
padding: 0 $space-small 0 $space-slab;
border-radius: 7px;
&.is-focused {
box-shadow:
0 0 0 1px $color-woot,
0 0 2px 3px $color-primary-light;
}
}
.emoji-dialog {
right: 20px;
top: -302px;
max-width: 100%;
&::before {
right: $space-one;
}
}
.button-wrap {
display: flex;
align-items: center;
padding-left: $space-small;
}
.user-message-input {
border: 0;
height: $space-large;
min-height: $space-large;
max-height: 2.4 * $space-mega;
resize: none;
padding: $space-smaller 0;
margin-top: $space-small;
margin-bottom: $space-small;
}
</style>