Feature: Support file type messages on widget and dashboard (#659)
- Adds support for file upload Co-authored-by: Pranav Raj Sreepuram <pranavrajs@gmail.com> Co-authored-by: Sojan <sojan@pepalo.com>
This commit is contained in:
committed by
GitHub
parent
0afa5c297f
commit
7fcd2d0e85
@@ -17,8 +17,13 @@
|
||||
:message-type="messageType"
|
||||
:message="message.content"
|
||||
/>
|
||||
<div v-if="hasImage" class="chat-bubble has-attachment agent">
|
||||
<div v-if="hasAttachment" class="chat-bubble has-attachment agent">
|
||||
<file-bubble
|
||||
v-if="message.attachment && message.attachment.file_type !== 'image'"
|
||||
:url="message.attachment.data_url"
|
||||
/>
|
||||
<image-bubble
|
||||
v-else
|
||||
:url="message.attachment.data_url"
|
||||
:thumb="message.attachment.thumb_url"
|
||||
:readable-time="readableTime"
|
||||
@@ -35,6 +40,7 @@
|
||||
import AgentMessageBubble from 'widget/components/AgentMessageBubble';
|
||||
import timeMixin from 'dashboard/mixins/time';
|
||||
import ImageBubble from 'widget/components/ImageBubble';
|
||||
import FileBubble from 'widget/components/FileBubble';
|
||||
import Thumbnail from 'dashboard/components/widgets/Thumbnail';
|
||||
import { MESSAGE_TYPE } from 'widget/helpers/constants';
|
||||
|
||||
@@ -44,6 +50,7 @@ export default {
|
||||
AgentMessageBubble,
|
||||
Thumbnail,
|
||||
ImageBubble,
|
||||
FileBubble,
|
||||
},
|
||||
mixins: [timeMixin],
|
||||
props: {
|
||||
@@ -53,10 +60,8 @@ export default {
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
hasImage() {
|
||||
const { attachment = {} } = this.message;
|
||||
const { file_type: fileType } = attachment;
|
||||
return fileType === 'image';
|
||||
hasAttachment() {
|
||||
return !!this.message.attachment;
|
||||
},
|
||||
showTextBubble() {
|
||||
const { message } = this;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<file-upload accept="image/*" @input-file="onFileUpload">
|
||||
<file-upload :size="4096 * 2048" @input-file="onFileUpload">
|
||||
<span class="attachment-button ">
|
||||
<i v-if="!isUploading.image"></i>
|
||||
<spinner v-if="isUploading" size="small" />
|
||||
@@ -23,12 +23,15 @@ export default {
|
||||
return { isUploading: false };
|
||||
},
|
||||
methods: {
|
||||
getFileType(fileType) {
|
||||
return fileType.includes('image') ? 'image' : 'file';
|
||||
},
|
||||
async onFileUpload(file) {
|
||||
this.isUploading = true;
|
||||
try {
|
||||
const thumbUrl = window.URL.createObjectURL(file.file);
|
||||
await this.onAttach({
|
||||
file_type: file.type,
|
||||
fileType: this.getFileType(file.type),
|
||||
file: file.file,
|
||||
thumbUrl,
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="chat-message--input">
|
||||
<chat-attchment-button :on-attach="onSendAttachment" />
|
||||
<chat-attachment-button :on-attach="onSendAttachment" />
|
||||
<ChatInputArea v-model="userInput" :placeholder="placeholder" />
|
||||
<ChatSendButton
|
||||
:on-click="handleButtonClick"
|
||||
@@ -13,13 +13,13 @@
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import ChatSendButton from 'widget/components/ChatSendButton.vue';
|
||||
import ChatAttchmentButton from 'widget/components/ChatAttachment.vue';
|
||||
import ChatAttachmentButton from 'widget/components/ChatAttachment.vue';
|
||||
import ChatInputArea from 'widget/components/ChatInputArea.vue';
|
||||
|
||||
export default {
|
||||
name: 'ChatInputWrap',
|
||||
components: {
|
||||
ChatAttchmentButton,
|
||||
ChatAttachmentButton,
|
||||
ChatSendButton,
|
||||
ChatInputArea,
|
||||
},
|
||||
@@ -44,6 +44,13 @@ export default {
|
||||
userInput: '',
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapGetters({
|
||||
widgetColor: 'appConfig/getWidgetColor',
|
||||
}),
|
||||
},
|
||||
|
||||
destroyed() {
|
||||
document.removeEventListener('keypress', this.handleEnterKeyPress);
|
||||
},
|
||||
@@ -51,11 +58,6 @@ export default {
|
||||
document.addEventListener('keypress', this.handleEnterKeyPress);
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapGetters({
|
||||
widgetColor: 'appConfig/getWidgetColor',
|
||||
}),
|
||||
},
|
||||
methods: {
|
||||
handleButtonClick() {
|
||||
if (this.userInput && this.userInput.trim()) {
|
||||
|
||||
93
app/javascript/widget/components/FileBubble.vue
Normal file
93
app/javascript/widget/components/FileBubble.vue
Normal file
@@ -0,0 +1,93 @@
|
||||
<template>
|
||||
<div class="file message-text__wrap" @click="openLink">
|
||||
<div class="icon-wrap">
|
||||
<i class="ion-document-text"></i>
|
||||
</div>
|
||||
<div class="meta">
|
||||
<div class="title">
|
||||
{{ title }}
|
||||
</div>
|
||||
<div class="link-wrap">
|
||||
<a
|
||||
class="download"
|
||||
rel="noreferrer noopener nofollow"
|
||||
target="_blank"
|
||||
:href="url"
|
||||
>
|
||||
{{ $t('COMPONENTS.FILE_BUBBLE.DOWNLOAD') }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
url: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
isInProgress: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
title() {
|
||||
return this.isInProgress
|
||||
? this.$t('COMPONENTS.FILE_BUBBLE.UPLOADING')
|
||||
: decodeURI(this.fileName);
|
||||
},
|
||||
fileName() {
|
||||
const filename = this.url.substring(this.url.lastIndexOf('/') + 1);
|
||||
return filename;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
openLink() {
|
||||
const win = window.open(this.url, '_blank');
|
||||
win.focus();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~widget/assets/scss/variables.scss';
|
||||
|
||||
.file {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
padding: $space-one $space-slab;
|
||||
cursor: pointer;
|
||||
|
||||
.icon-wrap {
|
||||
font-size: $font-size-bigger;
|
||||
color: $color-woot;
|
||||
line-height: 1;
|
||||
margin-left: $space-smaller;
|
||||
margin-right: $space-small;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-weight: $font-weight-medium;
|
||||
font-size: $font-size-small;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.download {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-size: $font-size-small;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.link-wrap {
|
||||
line-height: 1;
|
||||
}
|
||||
.meta {
|
||||
padding-right: $space-smaller;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,5 +1,10 @@
|
||||
<template>
|
||||
<a :href="url" target="_blank" class="image">
|
||||
<a
|
||||
:href="url"
|
||||
target="_blank"
|
||||
rel="noreferrer noopener nofollow"
|
||||
class="image"
|
||||
>
|
||||
<div class="wrap">
|
||||
<img :src="thumb" alt="Picture message" />
|
||||
<span class="time">{{ readableTime }}</span>
|
||||
|
||||
@@ -6,8 +6,14 @@
|
||||
:message="message.content"
|
||||
:status="message.status"
|
||||
/>
|
||||
<div v-if="hasImage" class="chat-bubble has-attachment user">
|
||||
<div v-if="hasAttachment" class="chat-bubble has-attachment user">
|
||||
<file-bubble
|
||||
v-if="message.attachment && message.attachment.file_type !== 'image'"
|
||||
:url="message.attachment.data_url"
|
||||
:is-in-progress="isInProgress"
|
||||
/>
|
||||
<image-bubble
|
||||
v-else
|
||||
:url="message.attachment.data_url"
|
||||
:thumb="message.attachment.thumb_url"
|
||||
:readable-time="readableTime"
|
||||
@@ -20,6 +26,7 @@
|
||||
<script>
|
||||
import UserMessageBubble from 'widget/components/UserMessageBubble';
|
||||
import ImageBubble from 'widget/components/ImageBubble';
|
||||
import FileBubble from 'widget/components/FileBubble';
|
||||
import timeMixin from 'dashboard/mixins/time';
|
||||
|
||||
export default {
|
||||
@@ -27,6 +34,7 @@ export default {
|
||||
components: {
|
||||
UserMessageBubble,
|
||||
ImageBubble,
|
||||
FileBubble,
|
||||
},
|
||||
mixins: [timeMixin],
|
||||
props: {
|
||||
@@ -40,11 +48,8 @@ export default {
|
||||
const { status = '' } = this.message;
|
||||
return status === 'in_progress';
|
||||
},
|
||||
hasImage() {
|
||||
const { attachment = {} } = this.message;
|
||||
const { file_type: fileType } = attachment;
|
||||
|
||||
return fileType === 'image';
|
||||
hasAttachment() {
|
||||
return !!this.message.attachment;
|
||||
},
|
||||
showTextBubble() {
|
||||
const { message } = this;
|
||||
@@ -94,5 +99,14 @@ export default {
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
.user.has-attachment {
|
||||
.icon-wrap {
|
||||
color: $color-white;
|
||||
}
|
||||
|
||||
.download {
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -45,7 +45,6 @@ export default {
|
||||
display: inline-block;
|
||||
font-size: $font-size-default;
|
||||
line-height: 1.5;
|
||||
max-width: 80%;
|
||||
padding: $space-small $space-normal;
|
||||
text-align: left;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user