chore: update conversation sidebar interactions (#13988)

This commit is contained in:
Sivin Varghese
2026-04-20 13:08:19 +05:30
committed by GitHub
parent 6cbddbdb67
commit 787fcc4a95
13 changed files with 747 additions and 306 deletions
@@ -12,19 +12,12 @@ import Avatar from 'next/avatar/Avatar.vue';
import SocialIcons from './SocialIcons.vue';
import EditContact from './EditContact.vue';
import ContactMergeModal from 'dashboard/modules/contact/ContactMergeModal.vue';
import ContactDeleteModal from 'dashboard/modules/contact/ContactDeleteModal.vue';
import ComposeConversation from 'dashboard/components-next/NewConversation/ComposeConversation.vue';
import { BUS_EVENTS } from 'shared/constants/busEvents';
import NextButton from 'dashboard/components-next/button/Button.vue';
import VoiceCallButton from 'dashboard/components-next/Contacts/VoiceCallButton.vue';
import InlineInput from 'dashboard/components-next/inline-input/InlineInput.vue';
import {
isAConversationRoute,
isAInboxViewRoute,
getConversationDashboardRoute,
} from '../../../../helper/routeHelpers';
import { emitter } from 'shared/helpers/mitt';
export default {
components: {
NextButton,
@@ -34,6 +27,7 @@ export default {
ComposeConversation,
SocialIcons,
ContactMergeModal,
ContactDeleteModal,
VoiceCallButton,
InlineInput,
},
@@ -57,7 +51,6 @@ export default {
data() {
return {
showEditModal: false,
showDeleteModal: false,
isEditingName: false,
editName: '',
};
@@ -99,10 +92,6 @@ export default {
telegram,
};
},
// Delete Modal
confirmDeleteMessage() {
return ` ${this.contact.name}?`;
},
},
watch: {
'contact.id': {
@@ -117,28 +106,6 @@ export default {
toggleEditModal() {
this.showEditModal = !this.showEditModal;
},
openComposeConversationModal(toggleFn) {
toggleFn();
// Flag to prevent triggering drag n drop,
// When compose modal is active
emitter.emit(BUS_EVENTS.NEW_CONVERSATION_MODAL, true);
},
closeComposeConversationModal() {
// Flag to enable drag n drop,
// When compose modal is closed
emitter.emit(BUS_EVENTS.NEW_CONVERSATION_MODAL, false);
},
toggleDeleteModal() {
this.showDeleteModal = !this.showDeleteModal;
},
confirmDeletion() {
this.deleteContact(this.contact);
this.closeDelete();
},
closeDelete() {
this.showDeleteModal = false;
this.showEditModal = false;
},
findCountryFlag(countryCode, cityAndCountry) {
try {
if (!countryCode) {
@@ -151,36 +118,6 @@ export default {
return '';
}
},
async deleteContact({ id }) {
try {
await this.$store.dispatch('contacts/delete', id);
this.$emit('panelClose');
useAlert(this.$t('DELETE_CONTACT.API.SUCCESS_MESSAGE'));
if (isAConversationRoute(this.$route.name)) {
this.$router.push({
name: getConversationDashboardRoute(this.$route.name),
});
} else if (isAInboxViewRoute(this.$route.name)) {
this.$router.push({
name: 'inbox_view',
});
} else if (this.$route.name !== 'contacts_dashboard') {
this.$router.push({
name: 'contacts_dashboard',
});
}
} catch (error) {
useAlert(
error.message
? error.message
: this.$t('DELETE_CONTACT.API.ERROR_MESSAGE')
);
}
},
openMergeModal() {
this.$refs.mergeModal?.open();
},
startEditingName() {
this.editName = this.contact.name || '';
this.isEditingName = true;
@@ -354,19 +291,14 @@ export default {
</div>
</div>
<div class="flex items-center w-full mt-0.5 gap-2">
<ComposeConversation
:contact-id="String(contact.id)"
is-modal
@close="closeComposeConversationModal"
>
<template #trigger="{ toggle }">
<ComposeConversation :contact-id="String(contact.id)">
<template #trigger>
<NextButton
v-tooltip.top-end="$t('CONTACT_PANEL.NEW_MESSAGE')"
icon="i-ph-chat-circle-dots"
slate
faded
sm
@click="openComposeConversationModal(toggle)"
/>
</template>
</ComposeConversation>
@@ -387,45 +319,41 @@ export default {
sm
@click="toggleEditModal"
/>
<NextButton
v-tooltip.top-end="$t('CONTACT_PANEL.MERGE_CONTACT')"
icon="i-ph-arrows-merge"
slate
faded
sm
:disabled="uiFlags.isMerging"
@click="openMergeModal"
/>
<NextButton
<ContactMergeModal :primary-contact="contact">
<template #trigger>
<NextButton
v-tooltip.top-end="$t('CONTACT_PANEL.MERGE_CONTACT')"
icon="i-ph-arrows-merge"
slate
faded
sm
:disabled="uiFlags.isMerging"
/>
</template>
</ContactMergeModal>
<ContactDeleteModal
v-if="isAdmin"
v-tooltip.top-end="$t('DELETE_CONTACT.BUTTON_LABEL')"
icon="i-ph-trash"
slate
faded
sm
ruby
:disabled="uiFlags.isDeleting"
@click="toggleDeleteModal"
/>
:contact="contact"
@deleted="$emit('panelClose')"
>
<template #trigger>
<NextButton
v-tooltip.top-end="$t('DELETE_CONTACT.BUTTON_LABEL')"
icon="i-ph-trash"
slate
faded
sm
ruby
:disabled="uiFlags.isDeleting"
/>
</template>
</ContactDeleteModal>
</div>
<EditContact
v-if="showEditModal"
:show="showEditModal"
:contact="contact"
@cancel="toggleEditModal"
/>
<ContactMergeModal ref="mergeModal" :primary-contact="contact" />
</div>
<woot-delete-modal
v-if="showDeleteModal"
v-model:show="showDeleteModal"
:on-close="closeDelete"
:on-confirm="confirmDeletion"
:title="$t('DELETE_CONTACT.CONFIRM.TITLE')"
:message="$t('DELETE_CONTACT.CONFIRM.MESSAGE')"
:message-value="confirmDeleteMessage"
:confirm-text="$t('DELETE_CONTACT.CONFIRM.YES')"
:reject-text="$t('DELETE_CONTACT.CONFIRM.NO')"
/>
</div>
</template>
@@ -1,74 +1,70 @@
<script>
import { mapGetters } from 'vuex';
<script setup>
import { useStore } from 'dashboard/composables/store';
import { useMapGetter } from 'dashboard/composables/store';
import { useKeyboardEvents } from 'dashboard/composables/useKeyboardEvents';
import ContactForm from './ContactForm.vue';
import Button from 'dashboard/components-next/button/Button.vue';
export default {
components: {
ContactForm,
},
props: {
show: {
type: Boolean,
default: false,
},
contact: {
type: Object,
default: () => ({}),
},
},
emits: ['cancel', 'update:show'],
computed: {
...mapGetters({
uiFlags: 'contacts/getUIFlags',
}),
localShow: {
get() {
return this.show;
},
set(value) {
this.$emit('update:show', value);
},
},
},
const props = defineProps({
show: { type: Boolean, default: false },
contact: { type: Object, default: () => ({}) },
});
methods: {
onCancel() {
this.$emit('cancel');
},
onSuccess() {
this.$emit('cancel');
},
async onSubmit(contactItem) {
await this.$store.dispatch('contacts/update', contactItem);
await this.$store.dispatch(
'contacts/fetchContactableInbox',
this.contact.id
);
},
},
const emit = defineEmits(['cancel']);
const store = useStore();
const uiFlags = useMapGetter('contacts/getUIFlags');
const onCancel = () => emit('cancel');
const onSubmit = async contactItem => {
await store.dispatch('contacts/update', contactItem);
await store.dispatch('contacts/fetchContactableInbox', props.contact.id);
};
// Restore Escape-to-close behavior that was provided by woot-modal before
// this drawer was reimplemented as a plain fixed panel.
useKeyboardEvents({
Escape: {
action: () => {
if (props.show) onCancel();
},
allowOnFocusedInput: true,
},
});
</script>
<template>
<woot-modal
v-model:show="localShow"
:on-close="onCancel"
modal-type="right-aligned"
<transition
enter-active-class="transition duration-200 ease-out"
enter-from-class="ltr:translate-x-full rtl:-translate-x-full opacity-0"
leave-active-class="transition duration-150 ease-in"
leave-to-class="ltr:translate-x-[30%] rtl:-translate-x-[30%] opacity-0"
>
<div class="flex flex-col h-auto overflow-auto">
<woot-modal-header
:header-title="`${$t('EDIT_CONTACT.TITLE')} - ${
contact.name || contact.email
}`"
:header-content="$t('EDIT_CONTACT.DESC')"
/>
<div
v-if="show"
class="fixed inset-y-0 ltr:right-0 rtl:left-0 z-50 flex flex-col w-[30rem] max-w-full h-full bg-n-surface-2 ltr:border-l rtl:border-r border-n-weak shadow-lg overflow-auto"
>
<div class="flex items-center justify-between px-8 pt-8 pb-2">
<div>
<h2 class="text-lg font-medium text-n-slate-12 mb-1">
{{
`${$t('EDIT_CONTACT.TITLE')} - ${contact.name || contact.email}`
}}
</h2>
<p class="text-sm text-n-slate-11 mb-0">
{{ $t('EDIT_CONTACT.DESC') }}
</p>
</div>
<Button icon="i-lucide-x" slate ghost sm @click="onCancel" />
</div>
<ContactForm
:contact="contact"
:in-progress="uiFlags.isUpdating"
:on-submit="onSubmit"
@success="onSuccess"
@success="onCancel"
@cancel="onCancel"
/>
</div>
</woot-modal>
</transition>
</template>