feat: Update conversation side panel layout and styling (#12983)

This commit is contained in:
Sivin Varghese
2025-12-04 13:55:07 +05:30
committed by GitHub
parent 832d61c004
commit 604d4a9c30
68 changed files with 2336 additions and 2553 deletions
@@ -92,6 +92,7 @@ onMounted(() => {
:chat="currentChat"
:is-on-expanded-view="isOnExpandedLayout"
:show-back-button="isOnExpandedLayout && !isInboxView"
:class="{ 'border-b border-n-weak !pb-3': !dashboardApps.length }"
/>
<woot-tabs
v-if="dashboardApps.length && currentChat.id"
@@ -12,6 +12,7 @@ import { conversationListPageURL } from 'dashboard/helper/URLHelper';
import { snoozedReopenTime } from 'dashboard/helper/snoozeHelpers';
import { useInbox } from 'dashboard/composables/useInbox';
import { useI18n } from 'vue-i18n';
import { useUISettings } from 'dashboard/composables/useUISettings';
const props = defineProps({
chat: {
@@ -35,6 +36,15 @@ const conversationHeader = ref(null);
const { width } = useElementSize(conversationHeader);
const { isAWebWidgetInbox } = useInbox();
const { uiSettings } = useUISettings();
const isSidepanelOpen = computed(
() =>
uiSettings.value.is_contact_sidebar_open ||
uiSettings.value.is_copilot_panel_open ||
false
);
const currentChat = computed(() => store.getters.getSelectedChat);
const accountId = computed(() => store.getters.getCurrentAccountId);
@@ -91,20 +101,24 @@ const hasSlaPolicyId = computed(() => props.chat?.sla_policy_id);
ref="conversationHeader"
class="flex flex-col items-start gap-x-6 gap-y-2 w-full min-w-0 pt-3 pb-2 ltr:pl-4 rtl:pr-4 ltr:pr-1 rtl:pl-1"
:class="{
'md:flex-row md:items-center': isOnExpandedView,
'lg:flex-row lg:items-center': !isOnExpandedView,
'md:flex-row md:items-center': isOnExpandedView && !isSidepanelOpen,
'lg:flex-row lg:items-center': isOnExpandedView && isSidepanelOpen,
'lg:flex-row lg:items-center': !isOnExpandedView && !isSidepanelOpen,
'xl:flex-row xl:items-center': !isOnExpandedView && isSidepanelOpen,
}"
>
<div
class="flex items-center gap-2 min-w-0 w-full"
:class="{
'md:flex-1 md:basis-0': isOnExpandedView,
'lg:flex-1 lg:basis-0': !isOnExpandedView,
'md:flex-1 md:basis-0': isOnExpandedView && !isSidepanelOpen,
'lg:flex-1 lg:basis-0': isOnExpandedView && isSidepanelOpen,
'lg:flex-1 lg:basis-0': !isOnExpandedView && !isSidepanelOpen,
'xl:flex-1 xl:basis-0': !isOnExpandedView && isSidepanelOpen,
}"
>
<BackButton v-if="showBackButton" :back-url="backButtonUrl" />
<div class="flex items-center gap-1 min-w-0 flex-1">
<div class="flex items-center gap-1 min-w-0 ltr:mr-2 rtl:ml-2">
<span class="text-base font-medium text-n-slate-12 truncate min-w-0">
{{ currentContact.name }}
</span>
@@ -120,8 +134,14 @@ const hasSlaPolicyId = computed(() => props.chat?.sla_policy_id);
<div
class="flex items-center gap-2 min-w-0 w-full"
:class="{
'md:flex-1 md:basis-0 md:justify-end': isOnExpandedView,
'lg:flex-1 lg:basis-0 lg:justify-end': !isOnExpandedView,
'md:flex-1 md:basis-0 md:justify-end':
isOnExpandedView && !isSidepanelOpen,
'lg:flex-1 lg:basis-0 lg:justify-end':
isOnExpandedView && isSidepanelOpen,
'lg:flex-1 lg:basis-0 lg:justify-end':
!isOnExpandedView && !isSidepanelOpen,
'xl:flex-1 xl:basis-0 xl:justify-end':
!isOnExpandedView && isSidepanelOpen,
}"
>
<div v-if="isSnoozed" class="flex items-center gap-1 min-w-0 shrink">
@@ -42,7 +42,7 @@ const closeContactPanel = () => {
<template>
<div
v-on-click-outside="() => closeContactPanel()"
class="bg-n-surface-2 h-full overflow-hidden flex flex-col fixed top-0 z-40 w-full max-w-sm transition-transform duration-300 ease-in-out ltr:right-0 rtl:left-0 md:static md:w-[320px] md:min-w-[320px] ltr:border-l rtl:border-r border-n-weak 2xl:min-w-[360px] 2xl:w-[360px] shadow-lg md:shadow-none"
class="bg-n-surface-2 h-full overflow-hidden flex flex-col fixed top-0 z-40 w-full max-w-sm transition-transform duration-300 ease-in-out ltr:right-0 rtl:left-0 md:static ltr:border-l rtl:border-r border-n-weak md:min-w-[360px] md:w-[360px] shadow-lg md:shadow-none"
:class="[
{
'md:flex': activeTab === 0,
@@ -4,6 +4,7 @@ import { useFunctionGetter } from 'dashboard/composables/store';
import Spinner from 'dashboard/components-next/spinner/Spinner.vue';
import ShopifyAPI from '../../../api/integrations/shopify';
import ShopifyOrderItem from './ShopifyOrderItem.vue';
import SidePanelEmptyState from 'dashboard/routes/dashboard/conversation/SidePanelEmptyState.vue';
const props = defineProps({
contactId: {
@@ -47,7 +48,7 @@ watch(
</script>
<template>
<div class="px-4 py-2 text-n-slate-12">
<div class="py-2 px-3 text-n-slate-12">
<div v-if="!hasSearchableInfo" class="text-center text-n-slate-12">
{{ $t('CONVERSATION_SIDEBAR.SHOPIFY.NO_SHOPIFY_ORDERS') }}
</div>
@@ -57,8 +58,10 @@ watch(
<div v-else-if="error" class="text-center text-n-ruby-12">
{{ error }}
</div>
<div v-else-if="!orders.length" class="text-center text-n-slate-12">
{{ $t('CONVERSATION_SIDEBAR.SHOPIFY.NO_SHOPIFY_ORDERS') }}
<div v-else-if="!orders.length" class="mt-2">
<SidePanelEmptyState
:message="$t('CONVERSATION_SIDEBAR.SHOPIFY.NO_SHOPIFY_ORDERS')"
/>
</div>
<div v-else>
<ShopifyOrderItem
@@ -67,7 +67,7 @@ const handleCancel = () => {
};
onMounted(() => {
store.dispatch('teams/fetch');
store.dispatch('teams/get');
});
</script>
@@ -8,6 +8,7 @@ import CreateOrLinkIssue from './CreateOrLinkIssue.vue';
import LinearIssueItem from './LinearIssueItem.vue';
import NextButton from 'dashboard/components-next/button/Button.vue';
import Spinner from 'dashboard/components-next/spinner/Spinner.vue';
import SidePanelEmptyState from 'dashboard/routes/dashboard/conversation/SidePanelEmptyState.vue';
import { LINEAR_EVENTS } from 'dashboard/helper/AnalyticsHelper/events';
import { parseLinearAPIErrorResponse } from 'dashboard/store/utils/api';
@@ -86,10 +87,10 @@ onMounted(() => {
<template>
<div>
<div class="px-4 pt-3 pb-2">
<div class="pt-3 px-3 pb-2">
<NextButton
ghost
xs
sm
slate
icon="i-lucide-plus"
:label="$t('INTEGRATION_SETTINGS.LINEAR.ADD_OR_LINK_BUTTON')"
@click="openCreateModal"
@@ -100,17 +101,17 @@ onMounted(() => {
<Spinner />
</div>
<div v-else-if="!hasIssues" class="flex justify-center p-4">
<p class="text-sm text-n-slate-11">
{{ $t('INTEGRATION_SETTINGS.LINEAR.NO_LINKED_ISSUES') }}
</p>
<div v-else-if="!hasIssues" class="mt-2">
<SidePanelEmptyState
:message="$t('INTEGRATION_SETTINGS.LINEAR.NO_LINKED_ISSUES')"
/>
</div>
<div v-else class="max-h-[300px] overflow-y-auto">
<div v-else class="max-h-[300px] overflow-y-auto px-2">
<LinearIssueItem
v-for="linkedIssue in linkedIssues"
:key="linkedIssue.id"
class="px-4 pt-3 pb-4 border-b border-n-weak last:border-b-0"
class="px-1 pt-3 pb-4 border-b border-n-weak last:border-b-0"
:linked-issue="linkedIssue"
@unlink-issue="unlinkIssue"
/>