chore: Created file upload composable and use it in compose view
This commit is contained in:
+66
-56
@@ -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(
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="divide-y divide-n-strong absolute right-0 w-[670px] mt-2 overflow-visible transition-all duration-300 ease-in-out top-full justify-between flex flex-col bg-n-alpha-3 border border-n-strong shadow-sm backdrop-blur-[100px] rounded-xl"
|
||||
class="absolute right-0 w-[670px] mt-2 divide-y divide-n-strong overflow-visible transition-all duration-300 ease-in-out top-full justify-between flex flex-col bg-n-alpha-3 border border-n-strong shadow-sm backdrop-blur-[100px] rounded-xl"
|
||||
>
|
||||
<div class="flex flex-col divide-y divide-n-strong">
|
||||
<ContactSelector
|
||||
:contacts="contacts"
|
||||
:selected-contact="selectedContact"
|
||||
:show-contacts-dropdown="showContactsDropdown"
|
||||
:is-loading="isLoading"
|
||||
:is-creating-contact="isCreatingContact"
|
||||
:contact-id="contactId"
|
||||
:contactable-inboxes-list="contactableInboxesList"
|
||||
:show-inboxes-dropdown="showInboxesDropdown"
|
||||
:has-errors="validationStates.isContactInvalid"
|
||||
@search-contacts="handleContactSearch"
|
||||
@set-selected-contact="setSelectedContact"
|
||||
@clear-selected-contact="clearSelectedContact"
|
||||
@update-dropdown="handleDropdownUpdate"
|
||||
/>
|
||||
<ContactSelector
|
||||
:contacts="contacts"
|
||||
:selected-contact="selectedContact"
|
||||
:show-contacts-dropdown="showContactsDropdown"
|
||||
:is-loading="isLoading"
|
||||
:is-creating-contact="isCreatingContact"
|
||||
:contact-id="contactId"
|
||||
:contactable-inboxes-list="contactableInboxesList"
|
||||
:show-inboxes-dropdown="showInboxesDropdown"
|
||||
:has-errors="validationStates.isContactInvalid"
|
||||
@search-contacts="handleContactSearch"
|
||||
@set-selected-contact="setSelectedContact"
|
||||
@clear-selected-contact="clearSelectedContact"
|
||||
@update-dropdown="handleDropdownUpdate"
|
||||
/>
|
||||
|
||||
<InboxSelector
|
||||
:target-inbox="targetInbox"
|
||||
:selected-contact="selectedContact"
|
||||
:show-inboxes-dropdown="showInboxesDropdown"
|
||||
:contactable-inboxes-list="contactableInboxesList"
|
||||
:has-errors="validationStates.isInboxInvalid"
|
||||
@update-inbox="removeTargetInbox"
|
||||
@toggle-dropdown="showInboxesDropdown = $event"
|
||||
@handle-inbox-action="handleInboxAction"
|
||||
/>
|
||||
<InboxSelector
|
||||
:target-inbox="targetInbox"
|
||||
:selected-contact="selectedContact"
|
||||
:show-inboxes-dropdown="showInboxesDropdown"
|
||||
:contactable-inboxes-list="contactableInboxesList"
|
||||
:has-errors="validationStates.isInboxInvalid"
|
||||
@update-inbox="removeTargetInbox"
|
||||
@toggle-dropdown="showInboxesDropdown = $event"
|
||||
@handle-inbox-action="handleInboxAction"
|
||||
/>
|
||||
|
||||
<EmailOptions
|
||||
v-if="inboxTypes.isEmail"
|
||||
v-model:cc-emails="state.ccEmails"
|
||||
v-model:bcc-emails="state.bccEmails"
|
||||
v-model:subject="state.subject"
|
||||
:contacts="contacts"
|
||||
:show-cc-emails-dropdown="showCcEmailsDropdown"
|
||||
:show-bcc-emails-dropdown="showBccEmailsDropdown"
|
||||
:show-bcc-input="showBccInput"
|
||||
:is-loading="isLoading"
|
||||
:has-errors="validationStates.isSubjectInvalid"
|
||||
@search-cc-emails="searchCcEmails"
|
||||
@search-bcc-emails="searchBccEmails"
|
||||
@toggle-bcc="toggleBccInput"
|
||||
@update-dropdown="handleDropdownUpdate"
|
||||
/>
|
||||
<EmailOptions
|
||||
v-if="inboxTypes.isEmail"
|
||||
v-model:cc-emails="state.ccEmails"
|
||||
v-model:bcc-emails="state.bccEmails"
|
||||
v-model:subject="state.subject"
|
||||
:contacts="contacts"
|
||||
:show-cc-emails-dropdown="showCcEmailsDropdown"
|
||||
:show-bcc-emails-dropdown="showBccEmailsDropdown"
|
||||
:show-bcc-input="showBccInput"
|
||||
:is-loading="isLoading"
|
||||
:has-errors="validationStates.isSubjectInvalid"
|
||||
@search-cc-emails="searchCcEmails"
|
||||
@search-bcc-emails="searchBccEmails"
|
||||
@toggle-bcc="toggleBccInput"
|
||||
@update-dropdown="handleDropdownUpdate"
|
||||
/>
|
||||
|
||||
<MessageEditor
|
||||
v-if="!inboxTypes.isWhatsapp"
|
||||
v-model="state.message"
|
||||
:is-email-or-web-widget-inbox="inboxTypes.isEmailOrWebWidget"
|
||||
:has-errors="validationStates.isMessageInvalid"
|
||||
/>
|
||||
</div>
|
||||
<MessageEditor
|
||||
v-if="!inboxTypes.isWhatsapp"
|
||||
v-model="state.message"
|
||||
:is-email-or-web-widget-inbox="inboxTypes.isEmailOrWebWidget"
|
||||
:has-errors="validationStates.isMessageInvalid"
|
||||
/>
|
||||
|
||||
<ActionButtons
|
||||
:is-whatsapp-inbox="inboxTypes.isWhatsapp"
|
||||
:is-email-or-web-widget-inbox="inboxTypes.isEmailOrWebWidget"
|
||||
:is-twilio-inbox="inboxTypes.isTwilio"
|
||||
:is-api-inbox="inboxTypes.isApi"
|
||||
:is-twilio-sms-inbox="inboxTypes.isTwilioSMS"
|
||||
:message-templates="whatsappMessageTemplates"
|
||||
:channel-type="inboxChannelType"
|
||||
:is-loading="isCreating"
|
||||
:disable-send-button="isCreating"
|
||||
@discard="$emit('discard')"
|
||||
@send-message="handleSendMessage"
|
||||
@send-whatsapp-message="handleSendWhatsappMessage"
|
||||
@insert-emoji="onClickInsertEmoji"
|
||||
@add-signature="handleAddSignature"
|
||||
@remove-signature="handleRemoveSignature"
|
||||
@attach-file="handleAttachFile"
|
||||
@discard="$emit('discard')"
|
||||
@send-message="handleSendMessage"
|
||||
@send-whatsapp-message="handleSendWhatsappMessage"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
+59
-9
@@ -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);
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -113,13 +144,32 @@ const onClickInsertEmoji = emoji => {
|
||||
:on-click="onClickInsertEmoji"
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
<FileUpload
|
||||
v-if="isEmailOrWebWidgetInbox"
|
||||
icon="i-lucide-plus"
|
||||
color="slate"
|
||||
size="sm"
|
||||
class="!w-10"
|
||||
/>
|
||||
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"
|
||||
>
|
||||
<Button
|
||||
icon="i-lucide-plus"
|
||||
color="slate"
|
||||
size="sm"
|
||||
class="!w-10 relative"
|
||||
>
|
||||
<span
|
||||
v-if="attachedFiles.length > 0"
|
||||
class="absolute top-0 right-0 rounded-full size-2.5 bg-n-brand"
|
||||
/>
|
||||
</Button>
|
||||
</FileUpload>
|
||||
<Button
|
||||
v-if="isEmailOrWebWidgetInbox"
|
||||
icon="i-lucide-type"
|
||||
|
||||
Reference in New Issue
Block a user