diff --git a/app/javascript/dashboard/components-next/NewConversation/ComposeNewConversation.vue b/app/javascript/dashboard/components-next/NewConversation/ComposeNewConversation.vue
index b59dc3d2b..de2377d8b 100644
--- a/app/javascript/dashboard/components-next/NewConversation/ComposeNewConversation.vue
+++ b/app/javascript/dashboard/components-next/NewConversation/ComposeNewConversation.vue
@@ -85,6 +85,9 @@ const inboxTypes = computed(() => ({
isEmailOrWebWidget:
targetInbox.value?.channelType === INBOX_TYPES.EMAIL ||
targetInbox.value?.channelType === INBOX_TYPES.WEB,
+ isTwilioSMS:
+ targetInbox.value?.channelType === INBOX_TYPES.TWILIO &&
+ targetInbox.value?.medium === 'sms',
}));
const whatsappMessageTemplates = computed(() =>
@@ -102,7 +105,12 @@ const validationRules = computed(() => ({
subject: { required: requiredIf(inboxTypes.value.isEmail) },
}));
-const v$ = useVuelidate(validationRules, state);
+const v$ = useVuelidate(validationRules, {
+ selectedContact,
+ targetInbox,
+ message: computed(() => state.message),
+ subject: computed(() => state.subject),
+});
const validationStates = computed(() => ({
isContactInvalid:
@@ -222,6 +230,10 @@ const handleRemoveSignature = signature => {
state.message = removeSignature(state.message, signature);
};
+const handleAttachFile = files => {
+ state.attachedFiles = files;
+};
+
const clearForm = () => {
Object.assign(state, {
message: '',
@@ -300,76 +312,74 @@ watch(
diff --git a/app/javascript/dashboard/components-next/NewConversation/components/ActionButtons.vue b/app/javascript/dashboard/components-next/NewConversation/components/ActionButtons.vue
index d6874f552..39402f6a1 100644
--- a/app/javascript/dashboard/components-next/NewConversation/components/ActionButtons.vue
+++ b/app/javascript/dashboard/components-next/NewConversation/components/ActionButtons.vue
@@ -3,6 +3,9 @@ import { defineAsyncComponent, ref, computed } from 'vue';
import { useMapGetter } from 'dashboard/composables/store';
import { useI18n } from 'vue-i18n';
import { useUISettings } from 'dashboard/composables/useUISettings';
+import { useFileUpload } from 'dashboard/composables/useFileUpload';
+import { ALLOWED_FILE_TYPES } from 'shared/constants/messages';
+import FileUpload from 'vue-upload-component';
import Button from 'dashboard/components-next/button/Button.vue';
import WhatsAppOptions from './WhatsAppOptions.vue';
@@ -10,11 +13,15 @@ import WhatsAppOptions from './WhatsAppOptions.vue';
const props = defineProps({
isWhatsappInbox: {
type: Boolean,
- required: true,
+ default: false,
},
isEmailOrWebWidgetInbox: {
type: Boolean,
- required: true,
+ default: false,
+ },
+ isTwilioSmsInbox: {
+ type: Boolean,
+ default: false,
},
messageTemplates: {
type: Array,
@@ -22,7 +29,7 @@ const props = defineProps({
},
channelType: {
type: String,
- required: true,
+ default: '',
},
isLoading: {
type: Boolean,
@@ -41,11 +48,14 @@ const emit = defineEmits([
'insertEmoji',
'addSignature',
'removeSignature',
+ 'attachFile',
]);
const { t } = useI18n();
+const uploadAttachment = ref(null);
const isEmojiPickerOpen = ref(false);
+const attachedFiles = ref([]);
const EmojiInput = defineAsyncComponent(
() => import('shared/components/emoji/EmojiInput.vue')
@@ -83,6 +93,27 @@ const toggleMessageSignature = () => {
const onClickInsertEmoji = emoji => {
emit('insertEmoji', emoji);
};
+
+const { onFileUpload } = useFileUpload({
+ isATwilioSMSChannel: props.isTwilioSmsInbox,
+ attachFile: ({ blob, file }) => {
+ if (!file) return;
+
+ const reader = new FileReader();
+ reader.readAsDataURL(file.file);
+ reader.onloadend = () => {
+ const newFile = {
+ resource: blob || file,
+ isPrivate: false,
+ thumb: reader.result,
+ blobSignedId: blob?.signed_id,
+ };
+
+ attachedFiles.value = [...attachedFiles.value, newFile];
+ emit('attachFile', attachedFiles.value);
+ };
+ },
+});
@@ -113,13 +144,32 @@ const onClickInsertEmoji = emoji => {
:on-click="onClickInsertEmoji"
/>
-
+ ref="uploadAttachment"
+ input-id="composeNewConversationAttachment"
+ :size="4096 * 4096"
+ :accept="ALLOWED_FILE_TYPES"
+ multiple
+ :drop-directory="false"
+ :data="{
+ direct_upload_url: '/rails/active_storage/direct_uploads',
+ direct_upload: true,
+ }"
+ @input-file="onFileUpload"
+ >
+
+