Revert "feat: Ability to send attachment in new conversation (#7698)" (#7903)

This commit is contained in:
Pranav Raj S
2023-09-12 08:27:49 -07:00
committed by GitHub
parent 272f920811
commit 71e9566854
14 changed files with 113 additions and 490 deletions

View File

@@ -152,10 +152,6 @@
&.is-image { &.is-image {
@apply rounded-lg; @apply rounded-lg;
.message__mail-head {
@apply px-4 py-2;
}
} }
} }

View File

@@ -4,6 +4,10 @@
@apply flex items-center justify-center bg-modal dark:bg-modal z-[9990] h-full left-0 fixed top-0 w-full; @apply flex items-center justify-center bg-modal dark:bg-modal z-[9990] h-full left-0 fixed top-0 w-full;
} }
.modal--close {
@apply absolute right-2 rtl:right-[unset] rtl:left-2 top-2;
}
.page-top-bar { .page-top-bar {
@apply px-8 pt-9 pb-0; @apply px-8 pt-9 pb-0;

View File

@@ -12,7 +12,7 @@
color-scheme="secondary" color-scheme="secondary"
icon="dismiss" icon="dismiss"
variant="clear" variant="clear"
class="absolute ltr:right-2 rtl:left-2 top-2 z-10" class="modal--close"
@click="close" @click="close"
/> />
<slot /> <slot />

View File

@@ -1,9 +1,11 @@
<template> <template>
<div class="preview-item__wrap flex overflow-auto max-h-[12.5rem]"> <div
class="preview-item__wrap flex flex-col overflow-auto mt-4 max-h-[12.5rem]"
>
<div <div
v-for="(attachment, index) in attachments" v-for="(attachment, index) in attachments"
:key="attachment.id" :key="attachment.id"
class="preview-item flex items-center p-1 bg-slate-50 dark:bg-slate-800 gap-1 rounded-md w-[15rem] mb-1" class="preview-item flex p-1 bg-slate-50 dark:bg-slate-800 rounded-md w-[15rem] mb-1"
> >
<div class="max-w-[4rem] flex-shrink-0 w-6 flex items-center"> <div class="max-w-[4rem] flex-shrink-0 w-6 flex items-center">
<img <img
@@ -15,7 +17,7 @@
📄 📄
</span> </span>
</div> </div>
<div class="max-w-[60%] min-w-[50%] overflow-hidden text-ellipsis"> <div class="max-w-[60%] min-w-[50%] overflow-hidden text-ellipsis ml-2">
<span <span
class="h-4 overflow-hidden text-sm font-medium text-ellipsis whitespace-nowrap" class="h-4 overflow-hidden text-sm font-medium text-ellipsis whitespace-nowrap"
> >

View File

@@ -14,11 +14,10 @@
<file-upload <file-upload
ref="upload" ref="upload"
v-tooltip.top-end="$t('CONVERSATION.REPLYBOX.TIP_ATTACH_ICON')" v-tooltip.top-end="$t('CONVERSATION.REPLYBOX.TIP_ATTACH_ICON')"
input-id="conversationAttachment"
:size="4096 * 4096" :size="4096 * 4096"
:accept="allowedFileTypes" :accept="allowedFileTypes"
:multiple="enableMultipleFileUpload" :multiple="enableMultipleFileUpload"
:drop="enableDragAndDrop" :drop="true"
:drop-directory="false" :drop-directory="false"
:data="{ :data="{
direct_upload_url: '/rails/active_storage/direct_uploads', direct_upload_url: '/rails/active_storage/direct_uploads',
@@ -101,9 +100,9 @@
<transition name="modal-fade"> <transition name="modal-fade">
<div <div
v-show="$refs.upload && $refs.upload.dropActive" v-show="$refs.upload && $refs.upload.dropActive"
class="flex items-center justify-center gap-2 fixed left-0 right-0 top-0 bottom-0 w-full h-full z-20 text-slate-600 dark:text-slate-200 bg-white_transparent dark:bg-black_transparent flex-col" class="modal-mask"
> >
<fluent-icon icon="cloud-backup" size="40" /> <fluent-icon icon="cloud-backup" />
<h4 class="page-sub-title text-slate-600 dark:text-slate-200"> <h4 class="page-sub-title text-slate-600 dark:text-slate-200">
{{ $t('CONVERSATION.REPLYBOX.DRAG_DROP') }} {{ $t('CONVERSATION.REPLYBOX.DRAG_DROP') }}
</h4> </h4>
@@ -229,10 +228,6 @@ export default {
type: String, type: String,
default: '', default: '',
}, },
newConversationModalActive: {
type: Boolean,
default: false,
},
}, },
computed: { computed: {
...mapGetters({ ...mapGetters({
@@ -279,9 +274,6 @@ export default {
} }
return ALLOWED_FILE_TYPES; return ALLOWED_FILE_TYPES;
}, },
enableDragAndDrop() {
return !this.newConversationModalActive;
},
audioRecorderPlayStopIcon() { audioRecorderPlayStopIcon() {
switch (this.recordingAudioState) { switch (this.recordingAudioState) {
// playing paused recording stopped inactive destroyed // playing paused recording stopped inactive destroyed
@@ -354,4 +346,12 @@ export default {
@apply dark:bg-slate-800 bg-slate-100; @apply dark:bg-slate-800 bg-slate-100;
} }
} }
.modal-mask {
@apply text-slate-600 dark:text-slate-200 bg-white_transparent dark:bg-black_transparent flex-col;
}
.icon {
@apply text-[5rem];
}
</style> </style>

View File

@@ -81,7 +81,6 @@
</div> </div>
<div v-if="hasAttachments" class="attachment-preview-box" @paste="onPaste"> <div v-if="hasAttachments" class="attachment-preview-box" @paste="onPaste">
<attachment-preview <attachment-preview
class="mt-4 flex-col"
:attachments="attachedFiles" :attachments="attachedFiles"
:remove-attachment="removeAttachment" :remove-attachment="removeAttachment"
/> />
@@ -125,7 +124,6 @@
:toggle-audio-recorder="toggleAudioRecorder" :toggle-audio-recorder="toggleAudioRecorder"
:toggle-emoji-picker="toggleEmojiPicker" :toggle-emoji-picker="toggleEmojiPicker"
:message="message" :message="message"
:new-conversation-modal-active="newConversationModalActive"
@selectWhatsappTemplate="openWhatsappTemplateModal" @selectWhatsappTemplate="openWhatsappTemplateModal"
@toggle-editor="toggleRichContentEditor" @toggle-editor="toggleRichContentEditor"
@replace-text="replaceText" @replace-text="replaceText"
@@ -162,7 +160,12 @@ import { REPLY_EDITOR_MODES } from 'dashboard/components/widgets/WootWriter/cons
import WootMessageEditor from 'dashboard/components/widgets/WootWriter/Editor'; import WootMessageEditor from 'dashboard/components/widgets/WootWriter/Editor';
import WootAudioRecorder from 'dashboard/components/widgets/WootWriter/AudioRecorder'; import WootAudioRecorder from 'dashboard/components/widgets/WootWriter/AudioRecorder';
import messageFormatterMixin from 'shared/mixins/messageFormatterMixin'; import messageFormatterMixin from 'shared/mixins/messageFormatterMixin';
import { AUDIO_FORMATS } from 'shared/constants/messages'; import { checkFileSizeLimit } from 'shared/helpers/FileHelper';
import {
MAXIMUM_FILE_UPLOAD_SIZE,
MAXIMUM_FILE_UPLOAD_SIZE_TWILIO_SMS_CHANNEL,
AUDIO_FORMATS,
} from 'shared/constants/messages';
import { BUS_EVENTS } from 'shared/constants/busEvents'; import { BUS_EVENTS } from 'shared/constants/busEvents';
import { import {
getMessageVariables, getMessageVariables,
@@ -174,13 +177,13 @@ import { buildHotKeys } from 'shared/helpers/KeyboardHelpers';
import { MESSAGE_MAX_LENGTH } from 'shared/helpers/MessageTypeHelper'; import { MESSAGE_MAX_LENGTH } from 'shared/helpers/MessageTypeHelper';
import inboxMixin from 'shared/mixins/inboxMixin'; import inboxMixin from 'shared/mixins/inboxMixin';
import uiSettingsMixin from 'dashboard/mixins/uiSettings'; import uiSettingsMixin from 'dashboard/mixins/uiSettings';
import { DirectUpload } from 'activestorage';
import { frontendURL } from '../../../helper/URLHelper'; import { frontendURL } from '../../../helper/URLHelper';
import { trimContent, debounce } from '@chatwoot/utils'; import { trimContent, debounce } from '@chatwoot/utils';
import wootConstants from 'dashboard/constants/globals'; import wootConstants from 'dashboard/constants/globals';
import { isEditorHotKeyEnabled } from 'dashboard/mixins/uiSettings'; import { isEditorHotKeyEnabled } from 'dashboard/mixins/uiSettings';
import { CONVERSATION_EVENTS } from '../../../helper/AnalyticsHelper/events'; import { CONVERSATION_EVENTS } from '../../../helper/AnalyticsHelper/events';
import rtlMixin from 'shared/mixins/rtlMixin'; import rtlMixin from 'shared/mixins/rtlMixin';
import fileUploadMixin from 'dashboard/mixins/fileUploadMixin';
const EmojiInput = () => import('shared/components/emoji/EmojiInput'); const EmojiInput = () => import('shared/components/emoji/EmojiInput');
@@ -205,7 +208,6 @@ export default {
alertMixin, alertMixin,
messageFormatterMixin, messageFormatterMixin,
rtlMixin, rtlMixin,
fileUploadMixin,
], ],
props: { props: {
selectedTweet: { selectedTweet: {
@@ -245,7 +247,6 @@ export default {
showUserMentions: false, showUserMentions: false,
showCannedMenu: false, showCannedMenu: false,
showVariablesMenu: false, showVariablesMenu: false,
newConversationModalActive: false,
}; };
}, },
computed: { computed: {
@@ -570,25 +571,11 @@ export default {
500, 500,
true true
); );
// A hacky fix to solve the drag and drop
// Is showing on top of new conversation modal drag and drop
// TODO need to find a better solution
bus.$on(
BUS_EVENTS.NEW_CONVERSATION_MODAL,
this.onNewConversationModalActive
);
}, },
destroyed() { destroyed() {
document.removeEventListener('paste', this.onPaste); document.removeEventListener('paste', this.onPaste);
document.removeEventListener('keydown', this.handleKeyEvents); document.removeEventListener('keydown', this.handleKeyEvents);
}, },
beforeDestroy() {
bus.$off(
BUS_EVENTS.NEW_CONVERSATION_MODAL,
this.onNewConversationModalActive
);
},
methods: { methods: {
toggleRichContentEditor() { toggleRichContentEditor() {
this.updateUISettings({ this.updateUISettings({
@@ -917,6 +904,67 @@ export default {
isPrivate, isPrivate,
}); });
}, },
onFileUpload(file) {
if (this.globalConfig.directUploadsEnabled) {
this.onDirectFileUpload(file);
} else {
this.onIndirectFileUpload(file);
}
},
onDirectFileUpload(file) {
const MAXIMUM_SUPPORTED_FILE_UPLOAD_SIZE = this.isATwilioSMSChannel
? MAXIMUM_FILE_UPLOAD_SIZE_TWILIO_SMS_CHANNEL
: MAXIMUM_FILE_UPLOAD_SIZE;
if (!file) {
return;
}
if (checkFileSizeLimit(file, MAXIMUM_SUPPORTED_FILE_UPLOAD_SIZE)) {
const upload = new DirectUpload(
file.file,
`/api/v1/accounts/${this.accountId}/conversations/${this.currentChat.id}/direct_uploads`,
{
directUploadWillCreateBlobWithXHR: xhr => {
xhr.setRequestHeader(
'api_access_token',
this.currentUser.access_token
);
},
}
);
upload.create((error, blob) => {
if (error) {
this.showAlert(error);
} else {
this.attachFile({ file, blob });
}
});
} else {
this.showAlert(
this.$t('CONVERSATION.FILE_SIZE_LIMIT', {
MAXIMUM_SUPPORTED_FILE_UPLOAD_SIZE,
})
);
}
},
onIndirectFileUpload(file) {
const MAXIMUM_SUPPORTED_FILE_UPLOAD_SIZE = this.isATwilioSMSChannel
? MAXIMUM_FILE_UPLOAD_SIZE_TWILIO_SMS_CHANNEL
: MAXIMUM_FILE_UPLOAD_SIZE;
if (!file) {
return;
}
if (checkFileSizeLimit(file, MAXIMUM_SUPPORTED_FILE_UPLOAD_SIZE)) {
this.attachFile({ file });
} else {
this.showAlert(
this.$t('CONVERSATION.FILE_SIZE_LIMIT', {
MAXIMUM_SUPPORTED_FILE_UPLOAD_SIZE,
})
);
}
},
attachFile({ blob, file }) { attachFile({ blob, file }) {
const reader = new FileReader(); const reader = new FileReader();
reader.readAsDataURL(file.file); reader.readAsDataURL(file.file);
@@ -1048,14 +1096,6 @@ export default {
this.bccEmails = bcc.join(', '); this.bccEmails = bcc.join(', ');
this.toEmails = to.join(', '); this.toEmails = to.join(', ');
}, },
onNewConversationModalActive(isActive) {
// Issue is if the new conversation modal is open and we drag and drop the file
// then the file is not getting attached to the new conversation modal
// and it is getting attached to the current conversation reply box
// so to fix this we are removing the drag and drop event listener from the current conversation reply box
// When new conversation modal is open
this.newConversationModalActive = isActive;
},
}, },
}; };
</script> </script>

View File

@@ -204,10 +204,6 @@
"PLACEHOLDER": "Write your message here", "PLACEHOLDER": "Write your message here",
"ERROR": "Message can't be empty" "ERROR": "Message can't be empty"
}, },
"ATTACHMENTS": {
"SELECT": "Choose files",
"HELP_TEXT": "Drag and drop files here or choose files to attach"
},
"SUBMIT": "Send message", "SUBMIT": "Send message",
"CANCEL": "Cancel", "CANCEL": "Cancel",
"SUCCESS_MESSAGE": "Message sent!", "SUCCESS_MESSAGE": "Message sent!",

View File

@@ -1,72 +0,0 @@
import {
MAXIMUM_FILE_UPLOAD_SIZE,
MAXIMUM_FILE_UPLOAD_SIZE_TWILIO_SMS_CHANNEL,
} from 'shared/constants/messages';
import { checkFileSizeLimit } from 'shared/helpers/FileHelper';
import { DirectUpload } from 'activestorage';
export default {
methods: {
onFileUpload(file) {
if (this.globalConfig.directUploadsEnabled) {
this.onDirectFileUpload(file);
} else {
this.onIndirectFileUpload(file);
}
},
onDirectFileUpload(file) {
const MAXIMUM_SUPPORTED_FILE_UPLOAD_SIZE = this.isATwilioSMSChannel
? MAXIMUM_FILE_UPLOAD_SIZE_TWILIO_SMS_CHANNEL
: MAXIMUM_FILE_UPLOAD_SIZE;
if (!file) {
return;
}
if (checkFileSizeLimit(file, MAXIMUM_SUPPORTED_FILE_UPLOAD_SIZE)) {
const upload = new DirectUpload(
file.file,
`/api/v1/accounts/${this.accountId}/conversations/${this.currentChat.id}/direct_uploads`,
{
directUploadWillCreateBlobWithXHR: xhr => {
xhr.setRequestHeader(
'api_access_token',
this.currentUser.access_token
);
},
}
);
upload.create((error, blob) => {
if (error) {
this.showAlert(error);
} else {
this.attachFile({ file, blob });
}
});
} else {
this.showAlert(
this.$t('CONVERSATION.FILE_SIZE_LIMIT', {
MAXIMUM_SUPPORTED_FILE_UPLOAD_SIZE,
})
);
}
},
onIndirectFileUpload(file) {
const MAXIMUM_SUPPORTED_FILE_UPLOAD_SIZE = this.isATwilioSMSChannel
? MAXIMUM_FILE_UPLOAD_SIZE_TWILIO_SMS_CHANNEL
: MAXIMUM_FILE_UPLOAD_SIZE;
if (!file) {
return;
}
if (checkFileSizeLimit(file, MAXIMUM_SUPPORTED_FILE_UPLOAD_SIZE)) {
this.attachFile({ file });
} else {
this.showAlert(
this.$t('CONVERSATION.FILE_SIZE_LIMIT', {
MAXIMUM_SUPPORTED_FILE_UPLOAD_SIZE,
})
);
}
},
},
};

View File

@@ -1,44 +0,0 @@
import fileUploadMixin from 'dashboard/mixins/fileUploadMixin';
import Vue from 'vue';
jest.mock('shared/helpers/FileHelper', () => ({
checkFileSizeLimit: jest.fn(),
}));
jest.mock('activestorage', () => ({
DirectUpload: jest.fn().mockImplementation(() => ({
create: jest.fn(),
})),
}));
describe('FileUploadMixin', () => {
let vm;
beforeEach(() => {
vm = new Vue(fileUploadMixin);
vm.isATwilioSMSChannel = false;
vm.globalConfig = {
directUploadsEnabled: true,
};
vm.accountId = 123;
vm.currentChat = {
id: 456,
};
vm.currentUser = {
access_token: 'token',
};
});
it('should call onDirectFileUpload when direct uploads are enabled', () => {
vm.onDirectFileUpload = jest.fn();
vm.onFileUpload({});
expect(vm.onDirectFileUpload).toHaveBeenCalledWith({});
});
it('should call onIndirectFileUpload when direct uploads are disabled', () => {
vm.globalConfig.directUploadsEnabled = false;
vm.onIndirectFileUpload = jest.fn();
vm.onFileUpload({});
expect(vm.onIndirectFileUpload).toHaveBeenCalledWith({});
});
});

View File

@@ -268,7 +268,6 @@ export default {
}, },
toggleConversationModal() { toggleConversationModal() {
this.showConversationModal = !this.showConversationModal; this.showConversationModal = !this.showConversationModal;
bus.$emit('newConversationModal', this.showConversationModal);
}, },
toggleDeleteModal() { toggleDeleteModal() {
this.showDeleteModal = !this.showDeleteModal; this.showDeleteModal = !this.showDeleteModal;

View File

@@ -11,10 +11,7 @@
<label> <label>
{{ $t('NEW_CONVERSATION.FORM.INBOX.LABEL') }} {{ $t('NEW_CONVERSATION.FORM.INBOX.LABEL') }}
</label> </label>
<div <div class="multiselect-wrap--small">
class="multiselect-wrap--small"
:class="{ 'has-multi-select-error': $v.targetInbox.$error }"
>
<multiselect <multiselect
v-model="targetInbox" v-model="targetInbox"
track-by="id" track-by="id"
@@ -91,13 +88,7 @@
</div> </div>
</div> </div>
<div class="w-full"> <div class="w-full">
<div <div class="w-full">
class="w-full"
:class="{
'flex flex-col-reverse': hasWhatsappTemplates,
'gap-3': hasWhatsappTemplates && !hasAttachments,
}"
>
<div class="relative"> <div class="relative">
<canned-response <canned-response
v-if="showCannedResponseMenu && hasSlashCommand" v-if="showCannedResponseMenu && hasSlashCommand"
@@ -148,52 +139,9 @@
{{ $t('NEW_CONVERSATION.FORM.MESSAGE.ERROR') }} {{ $t('NEW_CONVERSATION.FORM.MESSAGE.ERROR') }}
</span> </span>
</label> </label>
<div class="flex flex-col">
<file-upload
ref="uploadAttachment"
input-id="newConversationAttachment"
:size="4096 * 4096"
:accept="allowedFileTypes"
:multiple="true"
:drop="true"
:drop-directory="false"
:data="{
direct_upload_url: '/rails/active_storage/direct_uploads',
direct_upload: true,
}"
@input-file="onFileUpload"
>
<woot-button
class-names="button--upload"
icon="attach"
emoji="📎"
color-scheme="secondary"
variant="smooth"
size="small"
>
{{ $t('NEW_CONVERSATION.FORM.ATTACHMENTS.SELECT') }}
</woot-button>
<span
class="text-slate-500 ltr:ml-1 rtl:mr-1 font-medium text-xs dark:text-slate-400"
>
{{ $t('NEW_CONVERSATION.FORM.ATTACHMENTS.HELP_TEXT') }}
</span>
</file-upload>
<div
v-if="hasAttachments"
class="max-h-20 overflow-y-auto mb-4 mt-1.5"
>
<attachment-preview
class="[&>.preview-item]:dark:bg-slate-700 flex-row flex-wrap gap-x-3 gap-y-1"
:attachments="attachedFiles"
:remove-attachment="removeAttachment"
/>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
<div <div
v-if="!hasWhatsappTemplates" v-if="!hasWhatsappTemplates"
class="flex flex-row justify-end gap-2 py-2 px-0 w-full" class="flex flex-row justify-end gap-2 py-2 px-0 w-full"
@@ -205,18 +153,6 @@
{{ $t('NEW_CONVERSATION.FORM.SUBMIT') }} {{ $t('NEW_CONVERSATION.FORM.SUBMIT') }}
</woot-button> </woot-button>
</div> </div>
<transition name="modal-fade">
<div
v-show="$refs.uploadAttachment && $refs.uploadAttachment.dropActive"
class="flex top-0 bottom-0 z-30 gap-2 right-0 left-0 items-center justify-center flex-col absolute w-full h-full bg-white/80 dark:bg-slate-700/80"
>
<fluent-icon icon="cloud-backup" size="40" />
<h4 class="page-sub-title text-slate-600 dark:text-slate-200">
{{ $t('CONVERSATION.REPLYBOX.DRAG_DROP') }}
</h4>
</div>
</transition>
</form> </form>
</template> </template>
@@ -233,11 +169,6 @@ import { INBOX_TYPES } from 'shared/mixins/inboxMixin';
import { ExceptionWithMessage } from 'shared/helpers/CustomErrors'; import { ExceptionWithMessage } from 'shared/helpers/CustomErrors';
import { getInboxSource } from 'dashboard/helper/inbox'; import { getInboxSource } from 'dashboard/helper/inbox';
import { required, requiredIf } from 'vuelidate/lib/validators'; import { required, requiredIf } from 'vuelidate/lib/validators';
import inboxMixin from 'shared/mixins/inboxMixin';
import FileUpload from 'vue-upload-component';
import AttachmentPreview from 'dashboard/components/widgets/AttachmentsPreview';
import { ALLOWED_FILE_TYPES } from 'shared/constants/messages';
import fileUploadMixin from 'dashboard/mixins/fileUploadMixin';
export default { export default {
components: { components: {
@@ -247,10 +178,8 @@ export default {
CannedResponse, CannedResponse,
WhatsappTemplates, WhatsappTemplates,
InboxDropdownItem, InboxDropdownItem,
FileUpload,
AttachmentPreview,
}, },
mixins: [alertMixin, inboxMixin, fileUploadMixin], mixins: [alertMixin],
props: { props: {
contact: { contact: {
type: Object, type: Object,
@@ -272,7 +201,6 @@ export default {
ccEmails: '', ccEmails: '',
targetInbox: {}, targetInbox: {},
whatsappTemplateSelected: false, whatsappTemplateSelected: false,
attachedFiles: [],
}; };
}, },
validations: { validations: {
@@ -291,9 +219,8 @@ export default {
uiFlags: 'contacts/getUIFlags', uiFlags: 'contacts/getUIFlags',
conversationsUiFlags: 'contactConversations/getUIFlags', conversationsUiFlags: 'contactConversations/getUIFlags',
currentUser: 'getCurrentUser', currentUser: 'getCurrentUser',
globalConfig: 'globalConfig/get',
}), }),
newMessagePayload() { emailMessagePayload() {
const payload = { const payload = {
inboxId: this.targetInbox.id, inboxId: this.targetInbox.id,
sourceId: this.targetInbox.sourceId, sourceId: this.targetInbox.sourceId,
@@ -302,12 +229,6 @@ export default {
mailSubject: this.subject, mailSubject: this.subject,
assigneeId: this.currentUser.id, assigneeId: this.currentUser.id,
}; };
if (this.attachedFiles && this.attachedFiles.length) {
payload.files = [];
this.setAttachmentPayload(payload);
}
if (this.ccEmails) { if (this.ccEmails) {
payload.message.cc_emails = this.ccEmails; payload.message.cc_emails = this.ccEmails;
} }
@@ -363,15 +284,6 @@ export default {
hasWhatsappTemplates() { hasWhatsappTemplates() {
return !!this.selectedInbox.inbox?.message_templates; return !!this.selectedInbox.inbox?.message_templates;
}, },
hasAttachments() {
return this.attachedFiles.length;
},
inbox() {
return this.targetInbox;
},
allowedFileTypes() {
return ALLOWED_FILE_TYPES;
},
}, },
watch: { watch: {
message(value) { message(value) {
@@ -388,33 +300,6 @@ export default {
}, },
}, },
methods: { methods: {
setAttachmentPayload(payload) {
this.attachedFiles.forEach(attachment => {
if (this.globalConfig.directUploadsEnabled) {
payload.files.push(attachment.blobSignedId);
} else {
payload.files.push(attachment.resource.file);
}
});
},
attachFile({ blob, file }) {
const reader = new FileReader();
reader.readAsDataURL(file.file);
reader.onloadend = () => {
this.attachedFiles.push({
currentChatId: this.contact.id,
resource: blob || file,
isPrivate: this.isPrivate,
thumb: reader.result,
blobSignedId: blob ? blob.signed_id : undefined,
});
};
},
removeAttachment(itemIndex) {
this.attachedFiles = this.attachedFiles.filter(
(item, index) => itemIndex !== index
);
},
onCancel() { onCancel() {
this.$emit('cancel'); this.$emit('cancel');
}, },
@@ -435,10 +320,6 @@ export default {
message: { content, template_params: templateParams }, message: { content, template_params: templateParams },
assigneeId: this.currentUser.id, assigneeId: this.currentUser.id,
}; };
if (this.attachedFiles && this.attachedFiles.length) {
payload.files = [];
this.setAttachmentPayload(payload);
}
return payload; return payload;
}, },
onFormSubmit() { onFormSubmit() {
@@ -446,7 +327,7 @@ export default {
if (this.$v.$invalid) { if (this.$v.$invalid) {
return; return;
} }
this.createConversation(this.newMessagePayload); this.createConversation(this.emailMessagePayload);
}, },
async createConversation(payload) { async createConversation(payload) {
try { try {
@@ -508,18 +389,6 @@ export default {
} }
} }
.file-uploads {
@apply text-start;
}
.multiselect-wrap--small.has-multi-select-error {
::v-deep {
.multiselect__tags {
@apply border-red-500;
}
}
}
::v-deep { ::v-deep {
.mention--box { .mention--box {
@apply left-0 m-auto right-0 top-auto h-fit; @apply left-0 m-auto right-0 top-auto h-fit;

View File

@@ -3,34 +3,6 @@ import * as types from '../mutation-types';
import ContactAPI from '../../api/contacts'; import ContactAPI from '../../api/contacts';
import ConversationApi from '../../api/conversations'; import ConversationApi from '../../api/conversations';
export const createMessagePayload = (payload, message) => {
const { content, cc_emails, bcc_emails } = message;
payload.append('message[content]', content);
if (cc_emails) payload.append('message[cc_emails]', cc_emails);
if (bcc_emails) payload.append('message[bcc_emails]', bcc_emails);
};
export const createConversationPayload = ({ params, contactId, files }) => {
const { inboxId, message, sourceId, mailSubject, assigneeId } = params;
const payload = new FormData();
if (message) {
createMessagePayload(payload, message);
}
if (files && files.length > 0) {
files.forEach(file => payload.append('message[attachments][]', file));
}
payload.append('inbox_id', inboxId);
payload.append('contact_id', contactId);
payload.append('source_id', sourceId);
payload.append('additional_attributes[mail_subject]', mailSubject);
payload.append('assignee_id', assigneeId);
return payload;
};
const state = { const state = {
records: {}, records: {},
uiFlags: { uiFlags: {
@@ -52,17 +24,29 @@ export const actions = {
commit(types.default.SET_CONTACT_CONVERSATIONS_UI_FLAG, { commit(types.default.SET_CONTACT_CONVERSATIONS_UI_FLAG, {
isCreating: true, isCreating: true,
}); });
const { contactId, files } = params; const {
inboxId,
message,
contactId,
sourceId,
mailSubject,
assigneeId,
} = params;
try { try {
const payload = createConversationPayload({ params, contactId, files }); const { data } = await ConversationApi.create({
inbox_id: inboxId,
const { data } = await ConversationApi.create(payload); contact_id: contactId,
source_id: sourceId,
additional_attributes: {
mail_subject: mailSubject,
},
message,
assignee_id: assigneeId,
});
commit(types.default.ADD_CONTACT_CONVERSATION, { commit(types.default.ADD_CONTACT_CONVERSATION, {
id: contactId, id: contactId,
data, data,
}); });
return data; return data;
} catch (error) { } catch (error) {
throw new Error(error); throw new Error(error);

View File

@@ -1,9 +1,5 @@
import axios from 'axios'; import axios from 'axios';
import { import { actions } from '../../contactConversations';
actions,
createMessagePayload,
createConversationPayload,
} from '../../contactConversations';
import * as types from '../../../mutation-types'; import * as types from '../../../mutation-types';
import conversationList from './fixtures'; import conversationList from './fixtures';
@@ -53,35 +49,6 @@ describe('#actions', () => {
contactId: 4, contactId: 4,
sourceId: 5, sourceId: 5,
mailSubject: 'Mail Subject', mailSubject: 'Mail Subject',
assigneeId: 6,
files: [],
}
);
expect(commit.mock.calls).toEqual([
[types.default.SET_CONTACT_CONVERSATIONS_UI_FLAG, { isCreating: true }],
[
types.default.ADD_CONTACT_CONVERSATION,
{ id: 4, data: conversationList[0] },
],
[
types.default.SET_CONTACT_CONVERSATIONS_UI_FLAG,
{ isCreating: false },
],
]);
});
it('sends correct actions with files if API is success', async () => {
axios.post.mockResolvedValue({ data: conversationList[0] });
await actions.create(
{ commit },
{
inboxId: 1,
message: { content: 'hi' },
contactId: 4,
sourceId: 5,
assigneeId: 6,
mailSubject: 'Mail Subject',
files: [new File([], 'file1')],
} }
); );
expect(commit.mock.calls).toEqual([ expect(commit.mock.calls).toEqual([
@@ -107,7 +74,6 @@ describe('#actions', () => {
inboxId: 1, inboxId: 1,
message: { content: 'hi' }, message: { content: 'hi' },
contactId: 4, contactId: 4,
assigneeId: 6,
sourceId: 5, sourceId: 5,
mailSubject: 'Mail Subject', mailSubject: 'Mail Subject',
} }
@@ -121,121 +87,5 @@ describe('#actions', () => {
], ],
]); ]);
}); });
it('sends correct actions with files if API is error', async () => {
axios.post.mockRejectedValue({ message: 'Incorrect header' });
await expect(
actions.create(
{ commit },
{
inboxId: 1,
message: { content: 'hi' },
contactId: 4,
assigneeId: 6,
sourceId: 5,
mailSubject: 'Mail Subject',
files: [new File([], 'file1')],
}
)
).rejects.toThrow(Error);
expect(commit.mock.calls).toEqual([
[types.default.SET_CONTACT_CONVERSATIONS_UI_FLAG, { isCreating: true }],
[
types.default.SET_CONTACT_CONVERSATIONS_UI_FLAG,
{ isCreating: false },
],
]);
});
});
});
describe('createMessagePayload', () => {
it('creates message payload with cc and bcc emails', () => {
const payload = new FormData();
const message = {
content: 'Test message content',
cc_emails: 'cc@example.com',
bcc_emails: 'bcc@example.com',
};
createMessagePayload(payload, message);
expect(payload.get('message[content]')).toBe(message.content);
expect(payload.get('message[cc_emails]')).toBe(message.cc_emails);
expect(payload.get('message[bcc_emails]')).toBe(message.bcc_emails);
});
it('creates message payload without cc and bcc emails', () => {
const payload = new FormData();
const message = {
content: 'Test message content',
};
createMessagePayload(payload, message);
expect(payload.get('message[content]')).toBe(message.content);
expect(payload.get('message[cc_emails]')).toBeNull();
expect(payload.get('message[bcc_emails]')).toBeNull();
});
});
describe('createConversationPayload', () => {
it('creates conversation payload with message and attachments', () => {
const options = {
params: {
inboxId: '1',
message: {
content: 'Test message content',
},
sourceId: '12',
mailSubject: 'Test Subject',
assigneeId: '123',
},
contactId: '23',
files: ['file1.pdf', 'file2.jpg'],
};
const payload = createConversationPayload(options);
expect(payload.get('message[content]')).toBe(
options.params.message.content
);
expect(payload.get('inbox_id')).toBe(options.params.inboxId);
expect(payload.get('contact_id')).toBe(options.contactId);
expect(payload.get('source_id')).toBe(options.params.sourceId);
expect(payload.get('additional_attributes[mail_subject]')).toBe(
options.params.mailSubject
);
expect(payload.get('assignee_id')).toBe(options.params.assigneeId);
expect(payload.getAll('message[attachments][]')).toEqual(options.files);
});
it('creates conversation payload with message and without attachments', () => {
const options = {
params: {
inboxId: '1',
message: {
content: 'Test message content',
},
sourceId: '12',
mailSubject: 'Test Subject',
assigneeId: '123',
},
contactId: '23',
};
const payload = createConversationPayload(options);
expect(payload.get('message[content]')).toBe(
options.params.message.content
);
expect(payload.get('inbox_id')).toBe(options.params.inboxId);
expect(payload.get('contact_id')).toBe(options.contactId);
expect(payload.get('source_id')).toBe(options.params.sourceId);
expect(payload.get('additional_attributes[mail_subject]')).toBe(
options.params.mailSubject
);
expect(payload.get('assignee_id')).toBe(options.params.assigneeId);
expect(payload.getAll('message[attachments][]')).toEqual([]);
}); });
}); });

View File

@@ -10,5 +10,4 @@ export const BUS_EVENTS = {
ON_MESSAGE_LIST_SCROLL: 'ON_MESSAGE_LIST_SCROLL', ON_MESSAGE_LIST_SCROLL: 'ON_MESSAGE_LIST_SCROLL',
WEBSOCKET_DISCONNECT: 'WEBSOCKET_DISCONNECT', WEBSOCKET_DISCONNECT: 'WEBSOCKET_DISCONNECT',
SHOW_TOAST: 'newToastMessage', SHOW_TOAST: 'newToastMessage',
NEW_CONVERSATION_MODAL: 'newConversationModal',
}; };