feat: Update conversation messages screen UI (#12975)
This commit is contained in:
@@ -1,9 +1,12 @@
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
<script setup>
|
||||
import { computed, watch, onMounted, onBeforeMount } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useStore } from 'vuex';
|
||||
import { onBeforeRouteLeave } from 'vue-router';
|
||||
import { useMapGetter } from 'dashboard/composables/store';
|
||||
import { useUISettings } from 'dashboard/composables/useUISettings';
|
||||
import { useAccount } from 'dashboard/composables/useAccount';
|
||||
import ChatList from '../../../components/ChatList.vue';
|
||||
import ConversationBox from '../../../components/widgets/conversation/ConversationBox.vue';
|
||||
import ChatList from 'dashboard/components/ChatList.vue';
|
||||
import ConversationBox from 'dashboard/components/widgets/conversation/ConversationBox.vue';
|
||||
import wootConstants from 'dashboard/constants/globals';
|
||||
import { BUS_EVENTS } from 'shared/constants/busEvents';
|
||||
import CmdBarConversationSnooze from 'dashboard/routes/dashboard/commands/CmdBarConversationSnooze.vue';
|
||||
@@ -11,187 +14,144 @@ import { emitter } from 'shared/helpers/mitt';
|
||||
import SidepanelSwitch from 'dashboard/components-next/Conversation/SidepanelSwitch.vue';
|
||||
import ConversationSidebar from 'dashboard/components/widgets/conversation/ConversationSidebar.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ChatList,
|
||||
ConversationBox,
|
||||
CmdBarConversationSnooze,
|
||||
SidepanelSwitch,
|
||||
ConversationSidebar,
|
||||
const props = defineProps({
|
||||
inboxId: {
|
||||
type: [String, Number],
|
||||
default: 0,
|
||||
},
|
||||
beforeRouteLeave(to, from, next) {
|
||||
// Clear selected state if navigating away from a conversation to a route without a conversationId to prevent stale data issues
|
||||
// and resolves timing issues during navigation with conversation view and other screens
|
||||
if (this.conversationId) {
|
||||
this.$store.dispatch('clearSelectedState');
|
||||
}
|
||||
next(); // Continue with navigation
|
||||
conversationId: {
|
||||
type: [String, Number],
|
||||
default: 0,
|
||||
},
|
||||
props: {
|
||||
inboxId: {
|
||||
type: [String, Number],
|
||||
default: 0,
|
||||
},
|
||||
conversationId: {
|
||||
type: [String, Number],
|
||||
default: 0,
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
teamId: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
conversationType: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
foldersId: {
|
||||
type: [String, Number],
|
||||
default: 0,
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
setup() {
|
||||
const { uiSettings, updateUISettings } = useUISettings();
|
||||
const { accountId } = useAccount();
|
||||
teamId: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
conversationType: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
foldersId: {
|
||||
type: [String, Number],
|
||||
default: 0,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
uiSettings,
|
||||
updateUISettings,
|
||||
accountId,
|
||||
};
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showSearchModal: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
chatList: 'getAllConversations',
|
||||
currentChat: 'getSelectedChat',
|
||||
}),
|
||||
showConversationList() {
|
||||
return this.isOnExpandedLayout ? !this.conversationId : true;
|
||||
},
|
||||
showMessageView() {
|
||||
return this.conversationId ? true : !this.isOnExpandedLayout;
|
||||
},
|
||||
isOnExpandedLayout() {
|
||||
const {
|
||||
LAYOUT_TYPES: { CONDENSED },
|
||||
} = wootConstants;
|
||||
const { conversation_display_type: conversationDisplayType = CONDENSED } =
|
||||
this.uiSettings;
|
||||
return conversationDisplayType !== CONDENSED;
|
||||
},
|
||||
const route = useRoute();
|
||||
const store = useStore();
|
||||
const { uiSettings } = useUISettings();
|
||||
|
||||
shouldShowSidebar() {
|
||||
if (!this.currentChat.id) {
|
||||
return false;
|
||||
}
|
||||
const chatList = useMapGetter('getAllConversations');
|
||||
const currentChat = useMapGetter('getSelectedChat');
|
||||
|
||||
const { is_contact_sidebar_open: isContactSidebarOpen } = this.uiSettings;
|
||||
return isContactSidebarOpen;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
conversationId() {
|
||||
this.fetchConversationIfUnavailable();
|
||||
},
|
||||
},
|
||||
const isOnExpandedLayout = computed(() => {
|
||||
const {
|
||||
LAYOUT_TYPES: { CONDENSED },
|
||||
} = wootConstants;
|
||||
const { conversation_display_type: conversationDisplayType = CONDENSED } =
|
||||
uiSettings.value;
|
||||
return conversationDisplayType !== CONDENSED;
|
||||
});
|
||||
|
||||
created() {
|
||||
// Clear selected state early if no conversation is selected
|
||||
// This prevents child components from accessing stale data
|
||||
// and resolves timing issues during navigation
|
||||
// with conversation view and other screens
|
||||
if (!this.conversationId) {
|
||||
this.$store.dispatch('clearSelectedState');
|
||||
}
|
||||
},
|
||||
const showConversationList = computed(() =>
|
||||
isOnExpandedLayout.value ? !props.conversationId : true
|
||||
);
|
||||
|
||||
mounted() {
|
||||
this.$store.dispatch('agents/get');
|
||||
this.$store.dispatch('portals/index');
|
||||
this.initialize();
|
||||
this.$watch('$store.state.route', () => this.initialize());
|
||||
this.$watch('chatList.length', () => {
|
||||
this.setActiveChat();
|
||||
});
|
||||
},
|
||||
const showMessageView = computed(() =>
|
||||
props.conversationId ? true : !isOnExpandedLayout.value
|
||||
);
|
||||
|
||||
methods: {
|
||||
onConversationLoad() {
|
||||
this.fetchConversationIfUnavailable();
|
||||
},
|
||||
initialize() {
|
||||
this.$store.dispatch('setActiveInbox', this.inboxId);
|
||||
this.setActiveChat();
|
||||
},
|
||||
toggleConversationLayout() {
|
||||
const { LAYOUT_TYPES } = wootConstants;
|
||||
const {
|
||||
conversation_display_type:
|
||||
conversationDisplayType = LAYOUT_TYPES.CONDENSED,
|
||||
} = this.uiSettings;
|
||||
const newViewType =
|
||||
conversationDisplayType === LAYOUT_TYPES.CONDENSED
|
||||
? LAYOUT_TYPES.EXPANDED
|
||||
: LAYOUT_TYPES.CONDENSED;
|
||||
this.updateUISettings({
|
||||
conversation_display_type: newViewType,
|
||||
previously_used_conversation_display_type: newViewType,
|
||||
});
|
||||
},
|
||||
fetchConversationIfUnavailable() {
|
||||
if (!this.conversationId) {
|
||||
return;
|
||||
}
|
||||
const chat = this.findConversation();
|
||||
if (!chat) {
|
||||
this.$store.dispatch('getConversation', this.conversationId);
|
||||
}
|
||||
},
|
||||
findConversation() {
|
||||
const conversationId = parseInt(this.conversationId, 10);
|
||||
const [chat] = this.chatList.filter(c => c.id === conversationId);
|
||||
return chat;
|
||||
},
|
||||
setActiveChat() {
|
||||
if (this.conversationId) {
|
||||
const selectedConversation = this.findConversation();
|
||||
// If conversation doesn't exist or selected conversation is same as the active
|
||||
// conversation, don't set active conversation.
|
||||
if (
|
||||
!selectedConversation ||
|
||||
selectedConversation.id === this.currentChat.id
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const { messageId } = this.$route.query;
|
||||
this.$store
|
||||
.dispatch('setActiveChat', {
|
||||
data: selectedConversation,
|
||||
after: messageId,
|
||||
})
|
||||
.then(() => {
|
||||
emitter.emit(BUS_EVENTS.SCROLL_TO_MESSAGE, { messageId });
|
||||
});
|
||||
} else {
|
||||
this.$store.dispatch('clearSelectedState');
|
||||
}
|
||||
},
|
||||
onSearch() {
|
||||
this.showSearchModal = true;
|
||||
},
|
||||
closeSearch() {
|
||||
this.showSearchModal = false;
|
||||
},
|
||||
},
|
||||
const shouldShowSidebar = computed(() => {
|
||||
if (!currentChat.value.id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const { is_contact_sidebar_open: isContactSidebarOpen } = uiSettings.value;
|
||||
return isContactSidebarOpen;
|
||||
});
|
||||
|
||||
const findConversation = () => {
|
||||
const conversationId = parseInt(props.conversationId, 10);
|
||||
const [chat] = chatList.value.filter(c => c.id === conversationId);
|
||||
return chat;
|
||||
};
|
||||
|
||||
const fetchConversationIfUnavailable = () => {
|
||||
if (!props.conversationId) {
|
||||
return;
|
||||
}
|
||||
const chat = findConversation();
|
||||
if (!chat) {
|
||||
store.dispatch('getConversation', props.conversationId);
|
||||
}
|
||||
};
|
||||
|
||||
const setActiveChat = () => {
|
||||
if (props.conversationId) {
|
||||
const selectedConversation = findConversation();
|
||||
// If conversation doesn't exist or selected conversation is same as the active
|
||||
// conversation, don't set active conversation.
|
||||
if (
|
||||
!selectedConversation ||
|
||||
selectedConversation.id === currentChat.value.id
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const { messageId } = route.query;
|
||||
store
|
||||
.dispatch('setActiveChat', {
|
||||
data: selectedConversation,
|
||||
after: messageId,
|
||||
})
|
||||
.then(() => {
|
||||
emitter.emit(BUS_EVENTS.SCROLL_TO_MESSAGE, { messageId });
|
||||
});
|
||||
} else {
|
||||
store.dispatch('clearSelectedState');
|
||||
}
|
||||
};
|
||||
|
||||
const initialize = () => {
|
||||
store.dispatch('setActiveInbox', props.inboxId);
|
||||
setActiveChat();
|
||||
};
|
||||
|
||||
const onConversationLoad = () => {
|
||||
fetchConversationIfUnavailable();
|
||||
};
|
||||
|
||||
onBeforeRouteLeave((to, from, next) => {
|
||||
// Clear selected state if navigating away from a conversation to a route without a conversationId to prevent stale data issues
|
||||
// and resolves timing issues during navigation with conversation view and other screens
|
||||
if (props.conversationId) {
|
||||
store.dispatch('clearSelectedState');
|
||||
}
|
||||
next(); // Continue with navigation
|
||||
});
|
||||
|
||||
watch(() => props.conversationId, fetchConversationIfUnavailable);
|
||||
watch(() => store.state.route, initialize);
|
||||
watch(() => chatList.value.length, setActiveChat);
|
||||
|
||||
onBeforeMount(() => {
|
||||
// Clear selected state early if no conversation is selected
|
||||
// This prevents child components from accessing stale data
|
||||
// and resolves timing issues during navigation
|
||||
// with conversation view and other screens
|
||||
if (!props.conversationId) {
|
||||
store.dispatch('clearSelectedState');
|
||||
}
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
store.dispatch('agents/get');
|
||||
store.dispatch('portals/index');
|
||||
initialize();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
Reference in New Issue
Block a user