feat: Use vue-router on widget route management (#3415)
* feat: Add vue-router to widget Co-authored-by: Pranav <pranav@chatwoot.com> * Move to dynamic imports * Move to routerMixin * Fix popup button display * Remove unnecessary import * router -> route * Fix open state * Fix issues * Remove used CSS * Fix specs * Fix specs * Fix widgetColor specs * Fix mutation specs * Fixes broken lint errors * Fixes issues with widget flow Co-authored-by: Nithin <nithin@chatwoot.com> Co-authored-by: Nithin David <1277421+nithindavid@users.noreply.github.com> Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
This commit is contained in:
parent
991a42c417
commit
9c31d7c672
38 changed files with 617 additions and 725 deletions
|
@ -1,30 +1,31 @@
|
|||
<template>
|
||||
<div>
|
||||
<footer v-if="!hideReplyBox" class="footer">
|
||||
<ChatInputWrap
|
||||
:on-send-message="handleSendMessage"
|
||||
:on-send-attachment="handleSendAttachment"
|
||||
/>
|
||||
</footer>
|
||||
<div v-else>
|
||||
<custom-button
|
||||
class="font-medium"
|
||||
block
|
||||
:bg-color="widgetColor"
|
||||
:text-color="textColor"
|
||||
@click="startNewConversation"
|
||||
>
|
||||
{{ $t('START_NEW_CONVERSATION') }}
|
||||
</custom-button>
|
||||
<custom-button
|
||||
v-if="showEmailTranscriptButton"
|
||||
type="clear"
|
||||
class="font-normal"
|
||||
@click="sendTranscript"
|
||||
>
|
||||
{{ $t('EMAIL_TRANSCRIPT.BUTTON_TEXT') }}
|
||||
</custom-button>
|
||||
</div>
|
||||
<footer
|
||||
v-if="!hideReplyBox"
|
||||
class="shadow-sm rounded-lg bg-white mb-1 z-50 relative"
|
||||
>
|
||||
<chat-input-wrap
|
||||
:on-send-message="handleSendMessage"
|
||||
:on-send-attachment="handleSendAttachment"
|
||||
/>
|
||||
</footer>
|
||||
<div v-else>
|
||||
<custom-button
|
||||
class="font-medium"
|
||||
block
|
||||
:bg-color="widgetColor"
|
||||
:text-color="textColor"
|
||||
@click="startNewConversation"
|
||||
>
|
||||
{{ $t('START_NEW_CONVERSATION') }}
|
||||
</custom-button>
|
||||
<custom-button
|
||||
v-if="showEmailTranscriptButton"
|
||||
type="clear"
|
||||
class="font-normal"
|
||||
@click="sendTranscript"
|
||||
>
|
||||
{{ $t('EMAIL_TRANSCRIPT.BUTTON_TEXT') }}
|
||||
</custom-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -115,19 +116,8 @@ export default {
|
|||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped lang="scss">
|
||||
@import '~widget/assets/scss/variables.scss';
|
||||
@import '~widget/assets/scss/mixins.scss';
|
||||
|
||||
.footer {
|
||||
background: $color-white;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
border-radius: 7px;
|
||||
@include shadow-big;
|
||||
}
|
||||
|
||||
.branding {
|
||||
align-items: center;
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
<template>
|
||||
<header class="header-collapsed">
|
||||
<div class="header-branding">
|
||||
<header class="flex justify-between p-5 w-full">
|
||||
<div class="flex items-center">
|
||||
<button v-if="showBackButton" @click="onBackButtonClick">
|
||||
<fluent-icon icon="chevron-left" size="24" />
|
||||
</button>
|
||||
<img
|
||||
v-if="avatarUrl"
|
||||
class="inbox--avatar mr-3"
|
||||
class="h-8 w-8 rounded-full mr-3"
|
||||
:src="avatarUrl"
|
||||
alt="avatar"
|
||||
/>
|
||||
|
@ -12,14 +15,13 @@
|
|||
<span class="mr-1" v-html="title" />
|
||||
<div
|
||||
:class="
|
||||
`status-view--badge rounded-full leading-4 ${
|
||||
isOnline ? 'bg-green-500' : 'hidden'
|
||||
}`
|
||||
`h-2 w-2 rounded-full leading-4
|
||||
${isOnline ? 'bg-green-500' : 'hidden'}`
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
<div class="text-xs mt-1 text-black-700">
|
||||
{{ replyWaitMeessage }}
|
||||
{{ replyWaitMessage }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -29,15 +31,19 @@
|
|||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import HeaderActions from './HeaderActions';
|
||||
|
||||
import availabilityMixin from 'widget/mixins/availability';
|
||||
import FluentIcon from 'shared/components/FluentIcon/Index.vue';
|
||||
import HeaderActions from './HeaderActions';
|
||||
import routerMixin from 'widget/mixins/routerMixin';
|
||||
|
||||
export default {
|
||||
name: 'ChatHeader',
|
||||
components: {
|
||||
FluentIcon,
|
||||
HeaderActions,
|
||||
},
|
||||
mixins: [availabilityMixin],
|
||||
mixins: [availabilityMixin, routerMixin],
|
||||
props: {
|
||||
avatarUrl: {
|
||||
type: String,
|
||||
|
@ -51,15 +57,17 @@ export default {
|
|||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
showBackButton: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
availableAgents: {
|
||||
type: Array,
|
||||
default: () => {},
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
widgetColor: 'appConfig/getWidgetColor',
|
||||
}),
|
||||
...mapGetters({ widgetColor: 'appConfig/getWidgetColor' }),
|
||||
isOnline() {
|
||||
const { workingHoursEnabled } = this.channelConfig;
|
||||
const anyAgentOnline = this.availableAgents.length > 0;
|
||||
|
@ -69,47 +77,16 @@ export default {
|
|||
}
|
||||
return anyAgentOnline;
|
||||
},
|
||||
replyWaitMeessage() {
|
||||
replyWaitMessage() {
|
||||
return this.isOnline
|
||||
? this.replyTimeStatus
|
||||
: this.$t('TEAM_AVAILABILITY.OFFLINE');
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onBackButtonClick() {
|
||||
this.replaceRoute('home');
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '~widget/assets/scss/variables.scss';
|
||||
@import '~widget/assets/scss/mixins.scss';
|
||||
|
||||
.header-collapsed {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: $space-two $space-medium;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
|
||||
.header-branding {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
img {
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
font-weight: $font-weight-medium;
|
||||
}
|
||||
|
||||
.inbox--avatar {
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
.status-view--badge {
|
||||
height: $space-small;
|
||||
width: $space-small;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
<template>
|
||||
<header class="header-expanded bg-white py-8 px-6 relative box-border w-full">
|
||||
<header class="header-expanded bg-white py-6 px-5 relative box-border w-full">
|
||||
<div
|
||||
class="flex items-start"
|
||||
:class="[avatarUrl ? 'justify-between' : 'justify-end']"
|
||||
>
|
||||
<img v-if="avatarUrl" class="logo" :src="avatarUrl" />
|
||||
<img v-if="avatarUrl" class="h-12 rounded-full" :src="avatarUrl" />
|
||||
<header-actions :show-popout-button="showPopoutButton" />
|
||||
</div>
|
||||
<h2
|
||||
class="text-slate-900 mt-6 text-4xl mb-3 font-normal"
|
||||
class="text-slate-900 mt-5 text-3xl mb-3 font-normal"
|
||||
v-html="introHeading"
|
||||
/>
|
||||
<p class="text-lg text-black-700 leading-normal" v-html="introBody" />
|
||||
|
@ -48,17 +48,3 @@ export default {
|
|||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '~widget/assets/scss/mixins.scss';
|
||||
|
||||
$logo-size: 56px;
|
||||
|
||||
.header-expanded {
|
||||
.logo {
|
||||
width: $logo-size;
|
||||
height: $logo-size;
|
||||
border-radius: $logo-size;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -90,6 +90,7 @@ export default {
|
|||
computed: {
|
||||
...mapGetters({
|
||||
widgetColor: 'appConfig/getWidgetColor',
|
||||
isWidgetOpen: 'appConfig/getIsWidgetOpen',
|
||||
}),
|
||||
showAttachment() {
|
||||
return this.hasAttachmentsEnabled && this.userInput.length === 0;
|
||||
|
@ -97,13 +98,10 @@ export default {
|
|||
showSendButton() {
|
||||
return this.userInput.length > 0;
|
||||
},
|
||||
isOpen() {
|
||||
return this.$store.state.events.isOpen;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
isOpen(isOpen) {
|
||||
if (isOpen) {
|
||||
isWidgetOpen(isWidgetOpen) {
|
||||
if (isWidgetOpen) {
|
||||
this.focusInput();
|
||||
}
|
||||
},
|
||||
|
@ -113,7 +111,7 @@ export default {
|
|||
},
|
||||
mounted() {
|
||||
document.addEventListener('keypress', this.handleEnterKeyPress);
|
||||
if (this.isOpen) {
|
||||
if (this.isWidgetOpen) {
|
||||
this.focusInput();
|
||||
}
|
||||
},
|
||||
|
|
|
@ -67,9 +67,7 @@ export default {
|
|||
},
|
||||
closeWindow() {
|
||||
if (IFrameHelper.isIFrame()) {
|
||||
IFrameHelper.sendMessage({
|
||||
event: 'toggleBubble',
|
||||
});
|
||||
IFrameHelper.sendMessage({ event: 'closeWindow' });
|
||||
} else if (RNHelper.isRNWebView) {
|
||||
RNHelper.sendMessage({ type: 'close-widget' });
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
"
|
||||
/>
|
||||
<form-text-area
|
||||
v-if="!activeCampaignExist"
|
||||
v-if="!hasActiveCampaign"
|
||||
v-model="message"
|
||||
class="my-5"
|
||||
:label="$t('PRE_CHAT_FORM.FIELDS.MESSAGE.LABEL')"
|
||||
|
@ -63,7 +63,7 @@ import { mapGetters } from 'vuex';
|
|||
import { getContrastingTextColor } from '@chatwoot/utils';
|
||||
import { required, minLength, email } from 'vuelidate/lib/validators';
|
||||
import { isEmptyObject } from 'widget/helpers/utils';
|
||||
|
||||
import routerMixin from 'widget/mixins/routerMixin';
|
||||
export default {
|
||||
components: {
|
||||
FormInput,
|
||||
|
@ -71,6 +71,7 @@ export default {
|
|||
CustomButton,
|
||||
Spinner,
|
||||
},
|
||||
mixins: [routerMixin],
|
||||
props: {
|
||||
options: {
|
||||
type: Object,
|
||||
|
@ -95,7 +96,7 @@ export default {
|
|||
},
|
||||
};
|
||||
// For campaign, message field is not required
|
||||
if (this.activeCampaignExist) {
|
||||
if (this.hasActiveCampaign) {
|
||||
return identityValidations;
|
||||
}
|
||||
if (this.options.requireEmail) {
|
||||
|
@ -122,14 +123,14 @@ export default {
|
|||
textColor() {
|
||||
return getContrastingTextColor(this.widgetColor);
|
||||
},
|
||||
activeCampaignExist() {
|
||||
hasActiveCampaign() {
|
||||
return !isEmptyObject(this.activeCampaign);
|
||||
},
|
||||
shouldShowHeaderMessage() {
|
||||
return this.activeCampaignExist || this.options.preChatMessage;
|
||||
return this.hasActiveCampaign || this.options.preChatMessage;
|
||||
},
|
||||
headerMessage() {
|
||||
if (this.activeCampaignExist) {
|
||||
if (this.hasActiveCampaign) {
|
||||
return this.$t('PRE_CHAT_FORM.CAMPAIGN_HEADER');
|
||||
}
|
||||
return this.options.preChatMessage;
|
||||
|
@ -141,22 +142,12 @@ export default {
|
|||
if (this.$v.$invalid) {
|
||||
return;
|
||||
}
|
||||
// Check any active campaign exist or not
|
||||
if (this.activeCampaignExist) {
|
||||
bus.$emit('execute-campaign', this.activeCampaign.id);
|
||||
this.$store.dispatch('contacts/update', {
|
||||
user: {
|
||||
email: this.emailAddress,
|
||||
name: this.fullName,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
this.$store.dispatch('conversation/createConversation', {
|
||||
fullName: this.fullName,
|
||||
emailAddress: this.emailAddress,
|
||||
message: this.message,
|
||||
});
|
||||
}
|
||||
this.$emit('submit', {
|
||||
fullName: this.fullName,
|
||||
emailAddress: this.emailAddress,
|
||||
message: this.message,
|
||||
activeCampaignId: this.activeCampaign.id,
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="px-4">
|
||||
<div class="px-5">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="text-black-700">
|
||||
<div class="text-base leading-5 font-medium mb-1">
|
||||
|
@ -22,7 +22,9 @@
|
|||
:text-color="textColor"
|
||||
@click="startConversation"
|
||||
>
|
||||
{{ $t('START_CONVERSATION') }}
|
||||
{{
|
||||
hasConversation ? $t('CONTINUE_CONVERSATION') : $t('START_CONVERSATION')
|
||||
}}
|
||||
</custom-button>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -47,6 +49,10 @@ export default {
|
|||
type: Array,
|
||||
default: () => {},
|
||||
},
|
||||
hasConversation: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({ widgetColor: 'appConfig/getWidgetColor' }),
|
||||
|
|
|
@ -21,6 +21,10 @@ import messageFormatterMixin from 'shared/mixins/messageFormatterMixin';
|
|||
import Thumbnail from 'dashboard/components/widgets/Thumbnail';
|
||||
import configMixin from '../mixins/configMixin';
|
||||
import { isEmptyObject } from 'widget/helpers/utils';
|
||||
import {
|
||||
ON_CAMPAIGN_MESSAGE_CLICK,
|
||||
ON_UNREAD_MESSAGE_CLICK,
|
||||
} from '../constants/widgetBusEvents';
|
||||
export default {
|
||||
name: 'UnreadMessage',
|
||||
components: { Thumbnail },
|
||||
|
@ -82,9 +86,9 @@ export default {
|
|||
},
|
||||
onClickMessage() {
|
||||
if (this.campaignId) {
|
||||
bus.$emit('on-campaign-view-clicked', this.campaignId);
|
||||
bus.$emit(ON_CAMPAIGN_MESSAGE_CLICK, this.campaignId);
|
||||
} else {
|
||||
bus.$emit('on-unread-view-clicked');
|
||||
bus.$emit(ON_UNREAD_MESSAGE_CLICK);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
|
143
app/javascript/widget/components/UnreadMessageList.vue
Normal file
143
app/javascript/widget/components/UnreadMessageList.vue
Normal file
|
@ -0,0 +1,143 @@
|
|||
<template>
|
||||
<div class="unread-wrap">
|
||||
<div class="close-unread-wrap">
|
||||
<button class="button small close-unread-button" @click="closeFullView">
|
||||
<span class="flex items-center">
|
||||
<fluent-icon class="mr-1" icon="dismiss" size="12" />
|
||||
{{ $t('UNREAD_VIEW.CLOSE_MESSAGES_BUTTON') }}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="unread-messages">
|
||||
<unread-message
|
||||
v-for="(message, index) in messages"
|
||||
:key="message.id"
|
||||
:message-type="message.messageType"
|
||||
:message-id="message.id"
|
||||
:show-sender="!index"
|
||||
:sender="message.sender"
|
||||
:message="getMessageContent(message)"
|
||||
:campaign-id="message.campaignId"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="open-read-view-wrap">
|
||||
<button
|
||||
v-if="unreadMessageCount"
|
||||
class="button clear-button"
|
||||
@click="openConversationView"
|
||||
>
|
||||
<span class="flex items-center">
|
||||
<fluent-icon class="mr-2" size="16" icon="arrow-right" />
|
||||
{{ $t('UNREAD_VIEW.VIEW_MESSAGES_BUTTON') }}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { IFrameHelper } from 'widget/helpers/utils';
|
||||
import { mapGetters } from 'vuex';
|
||||
import configMixin from '../mixins/configMixin';
|
||||
import { ON_UNREAD_MESSAGE_CLICK } from '../constants/widgetBusEvents';
|
||||
import FluentIcon from 'shared/components/FluentIcon/Index.vue';
|
||||
import UnreadMessage from 'widget/components/UnreadMessage.vue';
|
||||
|
||||
export default {
|
||||
name: 'Unread',
|
||||
components: {
|
||||
FluentIcon,
|
||||
UnreadMessage,
|
||||
},
|
||||
mixins: [configMixin],
|
||||
props: {
|
||||
messages: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({ unreadMessageCount: 'conversation/getUnreadMessageCount' }),
|
||||
sender() {
|
||||
const [firstMessage] = this.messages;
|
||||
return firstMessage.sender || {};
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
openConversationView() {
|
||||
bus.$emit(ON_UNREAD_MESSAGE_CLICK);
|
||||
},
|
||||
closeFullView() {
|
||||
if (IFrameHelper.isIFrame()) {
|
||||
IFrameHelper.sendMessage({ event: 'toggleBubble' });
|
||||
}
|
||||
},
|
||||
getMessageContent(message) {
|
||||
const { attachments, content } = message;
|
||||
const hasAttachments = attachments && attachments.length;
|
||||
|
||||
if (content) return content;
|
||||
|
||||
if (hasAttachments) return `📑`;
|
||||
|
||||
return '';
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import '~widget/assets/scss/variables';
|
||||
|
||||
.unread-wrap {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
max-height: 100vh;
|
||||
background: transparent;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: flex-end;
|
||||
overflow: hidden;
|
||||
|
||||
.unread-messages {
|
||||
padding-bottom: $space-small;
|
||||
}
|
||||
|
||||
.clear-button {
|
||||
background: transparent;
|
||||
color: $color-woot;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
font-weight: $font-weight-bold;
|
||||
font-size: $font-size-medium;
|
||||
transition: all 0.3s $ease-in-cubic;
|
||||
margin-left: $space-smaller;
|
||||
padding-right: $space-one;
|
||||
|
||||
&:hover {
|
||||
transform: translateX($space-smaller);
|
||||
color: $color-primary-dark;
|
||||
}
|
||||
}
|
||||
|
||||
.close-unread-button {
|
||||
background: $color-background;
|
||||
color: $color-light-gray;
|
||||
border: 0;
|
||||
font-weight: $font-weight-medium;
|
||||
font-size: $font-size-mini;
|
||||
transition: all 0.3s $ease-in-cubic;
|
||||
margin-bottom: $space-slab;
|
||||
border-radius: $space-normal;
|
||||
|
||||
&:hover {
|
||||
color: $color-body;
|
||||
}
|
||||
}
|
||||
|
||||
.close-unread-wrap {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
</style>
|
118
app/javascript/widget/components/layouts/ViewWithHeader.vue
Normal file
118
app/javascript/widget/components/layouts/ViewWithHeader.vue
Normal file
|
@ -0,0 +1,118 @@
|
|||
<template>
|
||||
<div
|
||||
class="w-full h-full bg-slate-50 flex flex-col"
|
||||
@keydown.esc="closeWindow"
|
||||
>
|
||||
<div
|
||||
class="header-wrap bg-white"
|
||||
:class="{ expanded: !isHeaderCollapsed, collapsed: isHeaderCollapsed }"
|
||||
>
|
||||
<transition
|
||||
enter-active-class="transition-all delay-200 duration-300 ease-in"
|
||||
leave-active-class="transition-all duration-200 ease-out"
|
||||
enter-class="opacity-0"
|
||||
enter-to-class="opacity-100"
|
||||
leave-class="opacity-100"
|
||||
leave-to-class="opacity-0"
|
||||
>
|
||||
<chat-header-expanded
|
||||
v-if="!isHeaderCollapsed"
|
||||
:intro-heading="channelConfig.welcomeTitle"
|
||||
:intro-body="channelConfig.welcomeTagline"
|
||||
:avatar-url="channelConfig.avatarUrl"
|
||||
:show-popout-button="appConfig.showPopoutButton"
|
||||
/>
|
||||
<chat-header
|
||||
v-if="isHeaderCollapsed"
|
||||
:title="channelConfig.websiteName"
|
||||
:avatar-url="channelConfig.avatarUrl"
|
||||
:show-popout-button="appConfig.showPopoutButton"
|
||||
:available-agents="availableAgents"
|
||||
/>
|
||||
</transition>
|
||||
</div>
|
||||
<banner />
|
||||
<transition
|
||||
enter-active-class="transition-all delay-300 duration-300 ease-in"
|
||||
leave-active-class="transition-all duration-200 ease-out"
|
||||
enter-class="opacity-0"
|
||||
enter-to-class="opacity-100"
|
||||
leave-class="opacity-100"
|
||||
leave-to-class="opacity-0"
|
||||
>
|
||||
<router-view />
|
||||
</transition>
|
||||
<branding />
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import Banner from '../Banner.vue';
|
||||
import Branding from 'shared/components/Branding.vue';
|
||||
import ChatHeader from '../ChatHeader.vue';
|
||||
import ChatHeaderExpanded from '../ChatHeaderExpanded.vue';
|
||||
import configMixin from '../../mixins/configMixin';
|
||||
import { mapGetters } from 'vuex';
|
||||
import { IFrameHelper } from 'widget/helpers/utils';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Banner,
|
||||
Branding,
|
||||
ChatHeader,
|
||||
ChatHeaderExpanded,
|
||||
},
|
||||
mixins: [configMixin],
|
||||
data() {
|
||||
return {
|
||||
showPopoutButton: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
availableAgents: 'agent/availableAgents',
|
||||
appConfig: 'appConfig/getAppConfig',
|
||||
}),
|
||||
isHeaderCollapsed() {
|
||||
if (!this.hasIntroText) {
|
||||
return true;
|
||||
}
|
||||
return this.$route.name !== 'home';
|
||||
},
|
||||
hasIntroText() {
|
||||
return (
|
||||
this.channelConfig.welcomeTitle || this.channelConfig.welcomeTagline
|
||||
);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
closeWindow() {
|
||||
IFrameHelper.sendMessage({ event: 'closeWindow' });
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '~widget/assets/scss/variables';
|
||||
@import '~widget/assets/scss/mixins';
|
||||
|
||||
.header-wrap {
|
||||
border-radius: $space-normal $space-normal 0 0;
|
||||
flex-shrink: 0;
|
||||
transition: max-height 300ms;
|
||||
z-index: 99;
|
||||
@include shadow-large;
|
||||
|
||||
&.expanded {
|
||||
max-height: 16rem;
|
||||
}
|
||||
|
||||
&.collapsed {
|
||||
max-height: 4.5rem;
|
||||
}
|
||||
|
||||
@media only screen and (min-device-width: 320px) and (max-device-width: 667px) {
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
Loading…
Add table
Add a link
Reference in a new issue