fix: Persist compose form state on accidental outside click (#13529)

This commit is contained in:
Sivin Varghese
2026-02-17 13:57:44 +05:30
committed by GitHub
parent cfe3061b5d
commit fb2f5e1d42
2 changed files with 38 additions and 7 deletions

View File

@@ -1,5 +1,5 @@
<script setup> <script setup>
import { ref, computed, onMounted, watch } from 'vue'; import { reactive, ref, computed, onMounted, watch } from 'vue';
import { useStore, useMapGetter } from 'dashboard/composables/store'; import { useStore, useMapGetter } from 'dashboard/composables/store';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useWindowSize } from '@vueuse/core'; import { useWindowSize } from '@vueuse/core';
@@ -59,6 +59,23 @@ const isFetchingInboxes = ref(false);
const isSearching = ref(false); const isSearching = ref(false);
const showComposeNewConversation = ref(false); const showComposeNewConversation = ref(false);
const formState = reactive({
message: '',
subject: '',
ccEmails: '',
bccEmails: '',
attachedFiles: [],
});
const clearFormState = () => {
Object.assign(formState, {
subject: '',
ccEmails: '',
bccEmails: '',
attachedFiles: [],
});
};
const contactById = useMapGetter('contacts/getContactById'); const contactById = useMapGetter('contacts/getContactById');
const contactsUiFlags = useMapGetter('contacts/getUIFlags'); const contactsUiFlags = useMapGetter('contacts/getUIFlags');
const currentUser = useMapGetter('getCurrentUser'); const currentUser = useMapGetter('getCurrentUser');
@@ -140,12 +157,14 @@ const handleSelectedContact = async ({ value, action, ...rest }) => {
const handleTargetInbox = inbox => { const handleTargetInbox = inbox => {
targetInbox.value = inbox; targetInbox.value = inbox;
if (!inbox) clearFormState();
resetContacts(); resetContacts();
}; };
const clearSelectedContact = () => { const clearSelectedContact = () => {
selectedContact.value = null; selectedContact.value = null;
targetInbox.value = null; targetInbox.value = null;
clearFormState();
}; };
const closeCompose = () => { const closeCompose = () => {
@@ -160,6 +179,12 @@ const closeCompose = () => {
emit('close'); emit('close');
}; };
const discardCompose = () => {
clearFormState();
formState.message = '';
closeCompose();
};
const createConversation = async ({ payload, isFromWhatsApp }) => { const createConversation = async ({ payload, isFromWhatsApp }) => {
try { try {
const data = await store.dispatch('contactConversations/create', { const data = await store.dispatch('contactConversations/create', {
@@ -171,7 +196,7 @@ const createConversation = async ({ payload, isFromWhatsApp }) => {
to: `/app/accounts/${data.account_id}/conversations/${data.id}`, to: `/app/accounts/${data.account_id}/conversations/${data.id}`,
message: t('COMPOSE_NEW_CONVERSATION.FORM.GO_TO_CONVERSATION'), message: t('COMPOSE_NEW_CONVERSATION.FORM.GO_TO_CONVERSATION'),
}; };
closeCompose(); discardCompose();
useAlert(t('COMPOSE_NEW_CONVERSATION.FORM.SUCCESS_MESSAGE'), action); useAlert(t('COMPOSE_NEW_CONVERSATION.FORM.SUCCESS_MESSAGE'), action);
return true; // Return success return true; // Return success
} catch (error) { } catch (error) {
@@ -193,7 +218,11 @@ watch(
(currentContact, previousContact) => { (currentContact, previousContact) => {
if (currentContact && props.contactId) { if (currentContact && props.contactId) {
// Reset on contact change // Reset on contact change
if (currentContact?.id !== previousContact?.id) clearSelectedContact(); if (currentContact?.id !== previousContact?.id) {
clearSelectedContact();
clearFormState();
formState.message = '';
}
// First process the contactable inboxes to get the right structure // First process the contactable inboxes to get the right structure
const processedInboxes = processContactableInboxes( const processedInboxes = processContactableInboxes(
@@ -265,6 +294,7 @@ useKeyboardEvents(keyboardEvents);
@click.self="onModalBackdropClick" @click.self="onModalBackdropClick"
> >
<ComposeNewConversationForm <ComposeNewConversationForm
:form-state="formState"
:class="[{ 'mt-2': !viewInModal }, composePopoverClass]" :class="[{ 'mt-2': !viewInModal }, composePopoverClass]"
:contacts="contacts" :contacts="contacts"
:contact-id="contactId" :contact-id="contactId"
@@ -285,7 +315,7 @@ useKeyboardEvents(keyboardEvents);
@update-target-inbox="handleTargetInbox" @update-target-inbox="handleTargetInbox"
@clear-selected-contact="clearSelectedContact" @clear-selected-contact="clearSelectedContact"
@create-conversation="createConversation" @create-conversation="createConversation"
@discard="closeCompose" @discard="discardCompose"
/> />
</div> </div>
</div> </div>

View File

@@ -1,5 +1,5 @@
<script setup> <script setup>
import { reactive, ref, computed } from 'vue'; import { ref, computed } from 'vue';
import { useVuelidate } from '@vuelidate/core'; import { useVuelidate } from '@vuelidate/core';
import { required, requiredIf } from '@vuelidate/validators'; import { required, requiredIf } from '@vuelidate/validators';
import { INBOX_TYPES } from 'dashboard/helper/inbox'; import { INBOX_TYPES } from 'dashboard/helper/inbox';
@@ -37,6 +37,7 @@ const props = defineProps({
contactsUiFlags: { type: Object, default: null }, contactsUiFlags: { type: Object, default: null },
messageSignature: { type: String, default: '' }, messageSignature: { type: String, default: '' },
sendWithSignature: { type: Boolean, default: false }, sendWithSignature: { type: Boolean, default: false },
formState: { type: Object, required: true },
}); });
const emit = defineEmits([ const emit = defineEmits([
@@ -57,13 +58,13 @@ const showBccEmailsDropdown = ref(false);
const isCreating = computed(() => props.contactConversationsUiFlags.isCreating); const isCreating = computed(() => props.contactConversationsUiFlags.isCreating);
const state = reactive({ const state = props.formState || {
message: '', message: '',
subject: '', subject: '',
ccEmails: '', ccEmails: '',
bccEmails: '', bccEmails: '',
attachedFiles: [], attachedFiles: [],
}); };
const inboxTypes = computed(() => ({ const inboxTypes = computed(() => ({
isEmail: props.targetInbox?.channelType === INBOX_TYPES.EMAIL, isEmail: props.targetInbox?.channelType === INBOX_TYPES.EMAIL,