chore: Review fixes

This commit is contained in:
iamsivin
2026-02-22 22:18:56 +05:30
parent c85598fe8b
commit 5ef4e2fd88
4 changed files with 120 additions and 143 deletions
@@ -1,11 +1,13 @@
<script setup>
import { computed, useTemplateRef } from 'vue';
import { getLastMessage } from 'dashboard/helper/conversationHelper';
import CardMetaSection from './CardMetaSection.vue';
import Icon from 'dashboard/components-next/Icon/Icon.vue';
import TimeAgo from 'dashboard/components/ui/TimeAgo.vue';
import InboxName from 'dashboard/components-next/Conversation/InboxName.vue';
import CardAvatar from './CardAvatar.vue';
import CardHeader from './CardHeader.vue';
import CardContent from './CardContent.vue';
import CardLabels from './CardLabels.vue';
import CardPriorityIcon from './CardPriorityIcon.vue';
import SLACardLabel from 'dashboard/components-next/Conversation/Sla/SLACardLabel.vue';
const props = defineProps({
@@ -20,7 +22,6 @@ const props = defineProps({
showInboxName: { type: Boolean, default: false },
hideThumbnail: { type: Boolean, default: false },
enableSelection: { type: Boolean, default: true },
isInboxView: { type: Boolean, default: false },
});
const emit = defineEmits(['selectConversation', 'click', 'contextmenu']);
@@ -28,10 +29,6 @@ const emit = defineEmits(['selectConversation', 'click', 'contextmenu']);
const slaCardLabel = useTemplateRef('slaCardLabel');
const lastMessageInChat = computed(() => getLastMessage(props.chat));
const showLabelsSection = computed(() => props.chat.labels?.length > 0);
const showExpandedPreview = computed(
() => props.compact && !showLabelsSection.value
);
const voiceCallData = computed(() => ({
status: props.chat.additional_attributes?.call_status,
@@ -39,11 +36,23 @@ const voiceCallData = computed(() => ({
}));
const unreadCount = computed(() => props.chat?.unread_count);
const hasUnread = computed(() => unreadCount.value > 0);
const hasSlaPolicyId = computed(
() => props.chat?.sla_policy_id || slaCardLabel.value?.hasSlaThreshold
);
const showLabelsSection = computed(
() => props.chat.labels?.length > 0 || hasSlaPolicyId.value
);
const showMetaSection = computed(
() =>
props.showInboxName ||
(props.showAssignee && props.assignee?.name) ||
props.chat.priority
);
const onSelectConversation = checked => {
emit('selectConversation', checked);
};
@@ -51,85 +60,95 @@ const onSelectConversation = checked => {
<template>
<div
class="relative flex items-start flex-grow-0 flex-shrink-0 w-auto max-w-full cursor-pointer group transition-colors duration-150"
class="relative flex items-start max-w-full cursor-pointer group transition-colors duration-150 hover:bg-n-alpha-1 dark:hover:bg-n-alpha-3"
:class="{
'active animate-card-select bg-n-alpha-1 dark:bg-n-alpha-3': isActiveChat,
'selected bg-n-slate-2 dark:bg-n-slate-3': selected,
'px-0 py-3': compact,
'px-2 pt-2.5 pb-3 hover:bg-n-alpha-1 rounded-lg': !compact,
'active animate-card-select bg-n-background border-n-weak': isActiveChat,
'bg-n-slate-2': selected,
'px-0': compact,
'px-2 rounded-lg': !compact,
}"
@click="$emit('click', $event)"
@contextmenu="$emit('contextmenu', $event)"
>
<div class="min-w-0 w-full">
<CardMetaSection
v-if="!isInboxView"
:chat="chat"
:inbox="inbox"
:show-inbox-name="showInboxName"
:show-assignee="showAssignee"
:assignee="assignee"
<div class="relative">
<CardAvatar
v-if="!compact && !hideThumbnail"
:contact="currentContact"
:selected="selected"
:enable-selection="enableSelection"
:hide-thumbnail="hideThumbnail"
:class="showMetaSection ? 'mt-8' : 'mt-4'"
@select-conversation="onSelectConversation"
/>
</div>
<div
class="px-0 py-3 border-b group-hover:border-transparent flex-1 border-n-slate-3 min-w-0"
>
<div
class="grid gap-2.5 items-start"
v-if="showMetaSection"
class="flex items-center min-w-0 gap-1"
:class="{
'mt-0.5 grid-cols-1': compact,
'grid-cols-[auto,1fr]': !compact,
'ltr:ml-2 rtl:mr-2': !compact,
'mx-2': compact,
}"
>
<CardAvatar
v-if="!compact"
:contact="currentContact"
:selected="selected"
:enable-selection="enableSelection"
:hide-thumbnail="hideThumbnail"
class="mt-0.5"
@select-conversation="onSelectConversation"
/>
<div class="min-w-0 flex flex-col gap-1.5">
<div class="min-w-0 flex flex-col gap-px">
<CardHeader
v-if="!compact"
:contact-name="currentContact.name"
:timestamp="chat.timestamp"
:created-at="chat.created_at"
/>
<CardContent
:last-message="lastMessageInChat"
:voice-call-status="voiceCallData.status"
:voice-call-direction="voiceCallData.direction"
:unread-count="unreadCount"
:show-expanded-preview="showExpandedPreview"
/>
</div>
<CardLabels
v-if="showLabelsSection || isInboxView"
:labels="chat.labels"
<InboxName v-if="showInboxName" :inbox="inbox" class="flex-1 min-w-0" />
<div
class="flex items-center gap-2 flex-shrink-0 h-4"
:class="{
'flex-1 justify-between': !showInboxName,
}"
>
<span
v-if="showAssignee && assignee.name"
class="text-n-slate-11 text-label-small px-0 inline-flex items-center truncate gap-0.5 max-w-36"
>
<template #before>
<CardMetaSection
v-if="isInboxView"
:chat="chat"
:inbox="inbox"
:show-assignee="showAssignee"
:assignee="assignee"
:is-labels-empty="chat.labels.length === 0"
inline
/>
<SLACardLabel
v-else-if="hasSlaPolicyId"
ref="slaCardLabel"
data-before-slot
:chat="chat"
/>
</template>
</CardLabels>
<Icon icon="i-lucide-user-round" class="text-n-slate-11 size-3" />
{{ assignee.name }}
</span>
<CardPriorityIcon
v-if="chat.priority"
:priority="chat.priority"
class="flex-shrink-0"
/>
</div>
</div>
<div class="inline-flex items-center justify-between w-full">
<h4
class="text-heading-3 mx-2 capitalize pt-0.5 truncate flex-1 min-w-0 text-n-slate-12"
:class="hasUnread ? 'font-semibold' : ''"
>
{{ currentContact.name }}
</h4>
<span class="text-label-small text-n-slate-11">
<TimeAgo
:last-activity-timestamp="chat.timestamp"
:created-at-timestamp="chat.created_at"
/>
</span>
</div>
<div class="mx-2 leading-6 h-6 min-w-0">
<CardContent
:last-message="lastMessageInChat"
:voice-call-status="voiceCallData.status"
:voice-call-direction="voiceCallData.direction"
:unread-count="unreadCount"
/>
</div>
<CardLabels
v-if="showLabelsSection"
:labels="chat.labels"
class="mt-0.5 mx-2"
>
<template v-if="hasSlaPolicyId" #before>
<SLACardLabel ref="slaCardLabel" :chat="chat" data-before-slot />
</template>
</CardLabels>
</div>
</div>
</template>
@@ -6,8 +6,8 @@ import { frontendURL, conversationUrl } from 'dashboard/helper/URLHelper';
import ContextMenu from 'dashboard/components/ui/ContextMenu.vue';
import ConversationContextMenu from 'dashboard/components/widgets/conversation/contextMenu/Index.vue';
import ConversationCardExpanded from './ConversationCardExpanded.vue';
// import ConversationCardCompact from './ConversationCardCompact.vue';
import ConversationCard from 'dashboard/components/widgets/conversation/ConversationCard.vue';
import ConversationCardCompact from './ConversationCardCompact.vue';
// import ConversationCard from 'dashboard/components/widgets/conversation/ConversationCard.vue';
const props = defineProps({
activeLabel: { type: String, default: '' },
@@ -197,53 +197,6 @@ const deleteConversation = () => {
/>
<!-- Compact: All other cases (mobile OR isExpandedLayout=false) - Using older ConversationCard -->
<ConversationCard
v-else
:active-label="activeLabel"
:team-id="teamId"
:folders-id="foldersId"
:chat="chat"
:conversation-type="conversationType"
:selected="selected"
:show-assignee="showAssignee"
:hide-thumbnail="hideThumbnail"
:compact="compact"
:enable-context-menu="enableContextMenu"
:allowed-context-menu-options="allowedContextMenuOptions"
@select-conversation="
(chatId, inboxId) => emit('selectConversation', chatId, inboxId)
"
@de-select-conversation="
(chatId, inboxId) => emit('deSelectConversation', chatId, inboxId)
"
@assign-agent="
(agent, conversationIds) => emit('assignAgent', agent, conversationIds)
"
@assign-label="
(labels, conversationIds) => emit('assignLabel', labels, conversationIds)
"
@remove-label="
(labels, conversationIds) => emit('removeLabel', labels, conversationIds)
"
@assign-team="
(team, conversationId) => emit('assignTeam', team, conversationId)
"
@mark-as-unread="conversationId => emit('markAsUnread', conversationId)"
@mark-as-read="conversationId => emit('markAsRead', conversationId)"
@assign-priority="
(priority, conversationId) =>
emit('assignPriority', priority, conversationId)
"
@update-conversation-status="
(conversationId, status, snoozedUntil) =>
emit('updateConversationStatus', conversationId, status, snoozedUntil)
"
@delete-conversation="
conversationId => emit('deleteConversation', conversationId)
"
@context-menu-toggle="state => emit('contextMenuToggle', state)"
/>
<!-- New ConversationCardCompact
<ConversationCardCompact
v-else
:chat="chat"
@@ -262,7 +215,6 @@ const deleteConversation = () => {
@click="onCardClick"
@contextmenu="openContextMenu"
/>
-->
<ContextMenu
v-if="showContextMenu"
@@ -143,10 +143,10 @@ async function assignPriority(priority, conversationId = null) {
async function markAsUnread(conversationId) {
try {
emit('redirectToList');
await store.dispatch('markMessagesUnread', {
id: conversationId,
});
emit('redirectToList');
} catch (error) {
// Ignore error
}
@@ -2,7 +2,7 @@
import { provide, useTemplateRef, shallowRef, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useStore } from 'vuex';
import { useRouter } from 'vue-router';
import { useRouter, useRoute } from 'vue-router';
import { Virtualizer } from 'virtua/vue';
import { useInfiniteScroll, useBreakpoints } from '@vueuse/core';
import { useKeyboardEvents } from 'dashboard/composables/useKeyboardEvents';
@@ -13,6 +13,11 @@ import Icon from 'dashboard/components-next/icon/Icon.vue';
import Dialog from 'dashboard/components-next/dialog/Dialog.vue';
import ConversationResolveAttributesModal from 'dashboard/components-next/ConversationWorkflow/ConversationResolveAttributesModal.vue';
import wootConstants from 'dashboard/constants/globals';
import {
isOnMentionsView,
isOnUnattendedView,
} from 'dashboard/store/modules/conversations/helpers/actionHelpers';
import { conversationListPageURL } from 'dashboard/helper/URLHelper';
const props = defineProps({
items: { type: Array, default: () => [] },
@@ -31,6 +36,7 @@ const emit = defineEmits(['loadMore']);
const { t } = useI18n();
const store = useStore();
const router = useRouter();
const route = useRoute();
const parentRef = useTemplateRef('parentRef');
const virtualizerRef = shallowRef(null);
@@ -112,27 +118,27 @@ function handleDeleteConversation(conversationId) {
}
function redirectToConversationList() {
const accountId = store.getters.getCurrentAccountId;
const conversationType = props.conversationType || '';
const inboxId = store.getters.getSelectedInbox?.id;
const {
params: { accountId, inbox_id: inboxId, label, teamId },
name,
} = route;
let path = `/app/accounts/${accountId}/conversations`;
if (conversationType === 'mention') {
path = `/app/accounts/${accountId}/mentions/conversations`;
} else if (conversationType === 'unattended') {
path = `/app/accounts/${accountId}/unattended/conversations`;
} else if (props.foldersId) {
path = `/app/accounts/${accountId}/custom_view/${props.foldersId}`;
} else if (props.teamId) {
path = `/app/accounts/${accountId}/team/${props.teamId}`;
} else if (props.label) {
path = `/app/accounts/${accountId}/label/${props.label}`;
} else if (inboxId) {
path = `/app/accounts/${accountId}/inbox/${inboxId}`;
let conversationType = '';
if (isOnMentionsView({ route: { name } })) {
conversationType = 'mention';
} else if (isOnUnattendedView({ route: { name } })) {
conversationType = 'unattended';
}
router.push(path);
router.push(
conversationListPageURL({
accountId,
conversationType: conversationType,
customViewId: props.foldersId,
inboxId,
label,
teamId,
})
);
}
async function deleteConversation() {