feat: Display reply time in widget (#1349)

Fixes #1132
This commit is contained in:
Pranav Raj S
2020-10-18 23:32:22 +05:30
committed by GitHub
parent bd11b2ec58
commit 85514cae8d
43 changed files with 707 additions and 345 deletions

View File

@@ -1,3 +1,4 @@
.button {
font-family: $body-font-family;
font-weight: $font-weight-medium;

View File

@@ -14,5 +14,4 @@
@import '~bourbon/core/bourbon';
@include foundation-everything($flex: true);
@import 'woot';

View File

@@ -10,6 +10,7 @@
</div>
</template>
<script>
import { getContrastingTextColor } from 'shared/helpers/ColorHelper';
export default {
props: {
title: {
@@ -43,12 +44,7 @@ export default {
},
computed: {
textColor() {
const color = this.bgColor.replace('#', '');
const r = parseInt(color.slice(0, 2), 16);
const g = parseInt(color.slice(2, 4), 16);
const b = parseInt(color.slice(4, 6), 16);
// http://stackoverflow.com/a/3943023/112731
return r * 0.299 + g * 0.587 + b * 0.114 > 186 ? '#000000' : '#FFFFFF';
return getContrastingTextColor(this.bgColor);
},
labelClass() {
return `label ${this.small ? 'small' : ''}`;

View File

@@ -73,6 +73,13 @@
"ENABLED": "Enabled",
"DISABLED": "Disabled"
},
"REPLY_TIME": {
"TITLE": "Set Reply time",
"IN_A_FEW_MINUTES": "In a few minutes",
"IN_A_FEW_HOURS": "In a few hours",
"IN_A_DAY": "In a day",
"HELP_TEXT": "This reply time will be displayed on the live chat widget"
},
"WIDGET_COLOR": {
"LABEL": "Widget Color",
"PLACEHOLDER": "Update the widget color used in widget"

View File

@@ -78,8 +78,6 @@
</template>
<script>
/* global bus */
import { required, minLength, email } from 'vuelidate/lib/validators';
import Auth from '../../api/auth';
import { mapGetters } from 'vuex';

View File

@@ -8,7 +8,7 @@
<div class="medium-12 columns text-center">
<div class="website--code">
<woot-code
v-if="currentInbox.website_token"
v-if="currentInbox.web_widget_script"
:script="currentInbox.web_widget_script"
>
</woot-code>
@@ -75,7 +75,7 @@ export default {
return this.$t('INBOX_MGMT.ADD.EMAIL_CHANNEL.FINISH_MESSAGE');
}
if (!this.currentInbox.website_token) {
if (!this.currentInbox.web_widget_script) {
return this.$t('INBOX_MGMT.FINISH.MESSAGE');
}
return this.$t('INBOX_MGMT.FINISH.WEBSITE_SUCCESS');

View File

@@ -103,6 +103,7 @@
}}
</p>
</label>
<woot-input
v-if="greetingEnabled"
v-model.trim="greetingMessage"
@@ -116,6 +117,30 @@
)
"
/>
<label class="medium-9 columns">
{{ $t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.REPLY_TIME.TITLE') }}
<select v-model="replyTime">
<option key="in_a_few_minutes" value="in_a_few_minutes">
{{
$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.REPLY_TIME.IN_A_FEW_MINUTES')
}}
</option>
<option key="in_a_few_hours" value="in_a_few_hours">
{{
$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.REPLY_TIME.IN_A_FEW_HOURS')
}}
</option>
<option key="in_a_day" value="in_a_day">
{{ $t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.REPLY_TIME.IN_A_DAY') }}
</option>
</select>
<p class="help-text">
{{ $t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.REPLY_TIME.HELP_TEXT') }}
</p>
</label>
<label class="medium-9 columns">
{{ $t('INBOX_MGMT.SETTINGS_POPUP.AUTO_ASSIGNMENT') }}
<select v-model="autoAssignment">
@@ -220,7 +245,6 @@
</template>
<script>
/* eslint no-console: 0 */
import { mapGetters } from 'vuex';
import { createMessengerScript } from 'dashboard/helper/scriptGenerator';
import configMixin from 'shared/mixins/configMixin';
@@ -249,6 +273,7 @@ export default {
channelWelcomeTitle: '',
channelWelcomeTagline: '',
selectedFeatureFlags: [],
replyTime: '',
autoAssignmentOptions: [
{
value: true,
@@ -352,6 +377,7 @@ export default {
this.channelWelcomeTitle = this.inbox.welcome_title;
this.channelWelcomeTagline = this.inbox.welcome_tagline;
this.selectedFeatureFlags = this.inbox.selected_feature_flags || [];
this.replyTime = this.inbox.reply_time;
});
},
async fetchAttachedAgents() {
@@ -364,7 +390,7 @@ export default {
} = response;
this.selectedAgents = inboxMembers;
} catch (error) {
console.log(error);
// Handle error
}
},
async updateAgents() {
@@ -395,6 +421,7 @@ export default {
welcome_title: this.channelWelcomeTitle || '',
welcome_tagline: this.channelWelcomeTagline || '',
selectedFeatureFlags: this.selectedFeatureFlags,
reply_time: this.replyTime || 'in_a_few_minutes',
},
};
if (this.avatarFile) {
@@ -409,7 +436,6 @@ export default {
handleImageUpload({ file, url }) {
this.avatarFile = file;
this.avatarUrl = url;
console.log(this.avatarUrl);
},
},
validations: {

View File

@@ -6,3 +6,12 @@
src: url('~shared/assets/fonts/Inter-Regular.woff2?v=3.11') format('woff2'),
url('~shared/assets/fonts/Inter-Regular.woff?v=3.11') format('woff');
}
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 500;
font-display: swap;
src: url('~shared/assets/fonts/Inter-Medium.woff2?v=3.11') format('woff2'),
url('~shared/assets/fonts/Inter-Medium.woff?v=3.11') format('woff');
}

View File

@@ -0,0 +1,54 @@
<template>
<button :class="buttonClassName" :style="buttonStyles" @click="onClick">
<slot></slot>
</button>
</template>
<script>
export default {
props: {
block: {
type: Boolean,
default: false,
},
type: {
type: String,
default: 'blue',
},
bgColor: {
type: String,
default: '',
},
textColor: {
type: String,
default: '',
},
},
computed: {
buttonClassName() {
let className = 'text-white py-3 px-4 rounded shadow-sm';
if (this.type === 'blue' && !Object.keys(this.buttonStyles).length) {
className = `${className} bg-woot-500 hover:bg-woot-700`;
}
if (this.block) {
className = `${className} w-full`;
}
return className;
},
buttonStyles() {
const styles = {};
if (this.bgColor) {
styles.backgroundColor = this.bgColor;
}
if (this.textColor) {
styles.color = this.textColor;
}
return styles;
},
},
methods: {
onClick(e) {
this.$emit('click', e);
},
},
};
</script>

View File

@@ -22,7 +22,7 @@ export default {
},
minHeight: {
type: Number,
default: 3.2,
default: 2,
},
},
watch: {

View File

@@ -0,0 +1,8 @@
export const getContrastingTextColor = bgColor => {
const color = bgColor.replace('#', '');
const r = parseInt(color.slice(0, 2), 16);
const g = parseInt(color.slice(2, 4), 16);
const b = parseInt(color.slice(4, 6), 16);
// http://stackoverflow.com/a/3943023/112731
return r * 0.299 + g * 0.587 + b * 0.114 > 186 ? '#000000' : '#FFFFFF';
};

View File

@@ -1,31 +1,30 @@
// Font sizes
$font-size-nano: 0.8rem;
$font-size-micro: 0.8rem;
$font-size-mini: 1rem;
$font-size-small: 1.2rem;
$font-size-default: 1.4rem;
$font-size-medium: 1.6rem;
$font-size-large: 2rem;
$font-size-big: 2.4rem;
$font-size-bigger: 3.2rem;
$font-size-mega: 4rem;
$font-size-giga: 5.6rem;
$font-size-micro: 0.5rem;
$font-size-mini: 0.625rem;
$font-size-small: 0.75rem;
$font-size-default: 0.875rem;
$font-size-medium: 1rem;
$font-size-large: 1.25rem;
$font-size-big: 1.5rem;
$font-size-bigger: 2rem;
$font-size-mega: 2.5rem;
$font-size-giga: 3.5rem;
// spaces
$zero: 0;
$space-micro: 0.2rem;
$space-smaller: 0.4rem;
$space-small: 0.8rem;
$space-one: 1rem;
$space-slab: 1.2rem;
$space-normal: 1.6rem;
$space-two: 2rem;
$space-medium: 2.4rem;
$space-large: 3.2rem;
$space-larger: 4.8rem;
$space-big: 6.4rem;
$space-jumbo: 8rem;
$space-mega: 10rem;
$space-micro: 0.125rem;
$space-smaller: 0.25rem;
$space-small: 0.5rem;
$space-one: 0.625rem;
$space-slab: 0.75rem;
$space-normal: 1rem;
$space-two: 1.25rem;
$space-medium: 1.5rem;
$space-large: 2rem;
$space-larger: 3rem;
$space-big: 4rem;
$space-jumbo: 5rem;
$space-mega: 6.25rem;
// font-weight
$font-weight-feather: 100;
@@ -35,15 +34,6 @@ $font-weight-medium: 500;
$font-weight-bold: 600;
$font-weight-black: 700;
//Navbar
$nav-bar-width: 23rem;
$header-height: 5.6rem;
// Woot Logo
$woot-logo-width: 20rem;
$woot-logo-height: 8rem;
$woot-logo-padding: $space-large $space-large $space-large $space-large;
// Colors
$color-woot: #1f93ff;
$color-primary: $color-woot;
@@ -65,20 +55,6 @@ $color-error: #ff382d;
$color-primary-light: #c7e3ff;
$color-primary-dark: darken($color-woot, 20%);
// Thumbnail
$thumbnail-radius: 4rem;
// chat-header
$conv-header-height: 4rem;
// login
// Inbox List
$inbox-thumb-size: 4.8rem;
// Spinner
$spinkit-spinner-color: $color-white !default;
$spinkit-spinner-margin: 0 0 0 1.6rem !default;
@@ -92,7 +68,7 @@ $swift-ease-out-duration: .4s !default;
$swift-ease-out-timing-function: cubic-bezier(.25, .8, .25, 1) !default;
$swift-ease-out: all $swift-ease-out-duration $swift-ease-out-timing-function !default;
$border-radius: 3px;
$border-radius: 0.1875px;
$line-height: 1;
$footer-height: 11.2rem;
$header-expanded-height: $space-medium * 10;
@@ -109,10 +85,6 @@ Arial,
sans-serif;
$ionicons-font-path: '~ionicons/fonts';
$spinkit-spinner-color: $color-white !default;
$spinkit-spinner-margin: 0 0 0 1.6rem !default;
$spinkit-size: 1.6rem !default;
// Break points
$break-point-medium: 667px;

View File

@@ -1,4 +1,7 @@
@import 'reset';
@import 'tailwindcss/base';
@import 'tailwindcss/components';
@import 'tailwindcss/utilities';
@import 'variables';
@import 'buttons';
@import 'mixins';
@@ -10,7 +13,6 @@
html,
body {
font-family: $font-family;
font-size: 10px;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
height: 100%;

View File

@@ -25,8 +25,8 @@ export default {
@import '~widget/assets/scss/variables.scss';
.typing-bubble {
max-width: $space-medium;
padding: $space-smaller $space-small;
max-width: $space-normal * 2.4;
padding: $space-small;
border-bottom-left-radius: $space-two;
border-top-left-radius: $space-small;

View File

@@ -1,80 +1,27 @@
<template>
<div class="available-agents">
<div class="toast-bg">
<div class="avatars-wrap">
<GroupedAvatars :users="users" />
</div>
<div class="title">
{{ title }}
</div>
</div>
</div>
<grouped-avatars :users="users" />
</template>
<script>
import GroupedAvatars from 'widget/components/GroupedAvatars.vue';
import agentMixin from '../mixins/agentMixin';
export default {
name: 'AvailableAgents',
components: { GroupedAvatars },
mixins: [agentMixin],
props: {
agents: {
type: Array,
default: () => [],
},
onClose: {
type: Function,
default: () => {},
},
},
computed: {
users() {
return this.agents.map(agent => ({
return this.agents.slice(0, 5).map(agent => ({
id: agent.id,
avatar: agent.avatar_url,
name: agent.name,
}));
},
title() {
return this.getAvailableAgentsText(this.agents);
},
},
};
</script>
<style scoped lang="scss">
@import '~widget/assets/scss/variables.scss';
@import '~widget/assets/scss/mixins.scss';
.available-agents {
display: flex;
position: relative;
justify-content: center;
margin: $space-normal $space-medium;
box-sizing: border-box;
.toast-bg {
border-radius: $space-large;
background: $color-body;
@include shadow-medium;
}
.title {
font-size: $font-size-default;
font-weight: $font-weight-medium;
color: $color-white;
padding: $space-small $space-normal $space-small $space-small;
line-height: 1.4;
display: inline-block;
vertical-align: middle;
}
.avatars-wrap {
display: inline-block;
vertical-align: middle;
margin-left: $space-small;
}
}
</style>

View File

@@ -1,8 +1,27 @@
<template>
<header class="header-collapsed">
<div class="header-branding">
<img v-if="avatarUrl" :src="avatarUrl" alt="avatar" />
<h2 class="title" v-html="title"></h2>
<img
v-if="avatarUrl"
class="inbox--avatar mr-3"
:src="avatarUrl"
alt="avatar"
/>
<div>
<div class="text-black-900 font-medium text-base flex items-center">
<span class="mr-1" v-html="title" />
<div
:class="
`status-view--badge rounded-full leading-4 ${
availableAgents.length ? 'bg-green-500' : 'hidden'
}`
"
/>
</div>
<div class="text-xs mt-1 text-black-700">
{{ replyTimeStatus }}
</div>
</div>
</div>
<header-actions :show-popout-button="showPopoutButton" />
</header>
@@ -11,11 +30,15 @@
<script>
import { mapGetters } from 'vuex';
import HeaderActions from './HeaderActions';
import configMixin from 'widget/mixins/configMixin';
import teamAvailabilityMixin from 'widget/mixins/teamAvailabilityMixin';
export default {
name: 'ChatHeader',
components: {
HeaderActions,
},
mixins: [configMixin, teamAvailabilityMixin],
props: {
avatarUrl: {
type: String,
@@ -29,6 +52,10 @@ export default {
type: Boolean,
default: false,
},
availableAgents: {
type: Array,
default: () => {},
},
},
computed: {
...mapGetters({
@@ -48,7 +75,8 @@ export default {
padding: $space-two $space-medium;
width: 100%;
box-sizing: border-box;
color: $color-white;
background: white;
@include shadow-large;
.header-branding {
display: flex;
@@ -60,15 +88,17 @@ export default {
}
.title {
font-size: $font-size-large;
font-weight: $font-weight-medium;
color: $color-heading;
}
img {
height: 24px;
width: 24px;
margin-right: $space-small;
.inbox--avatar {
height: 32px;
width: 32px;
}
}
.status-view--badge {
height: $space-small;
width: $space-small;
}
</style>

View File

@@ -1,11 +1,14 @@
<template>
<header class="header-expanded">
<div class="header--row">
<header class="header-expanded py-8 px-6 bg-white relative box-border w-full">
<div class="flex justify-between items-start">
<img v-if="avatarUrl" class="logo" :src="avatarUrl" />
<header-actions :show-popout-button="showPopoutButton" />
</div>
<h2 class="title" v-html="introHeading"></h2>
<p class="body" v-html="introBody"></p>
<h2
class="text-slate-900 mt-6 text-4xl mb-3 font-normal"
v-html="introHeading"
/>
<p class="text-lg text-black-700 leading-normal" v-html="introBody" />
</header>
</template>
@@ -44,38 +47,14 @@ export default {
</script>
<style scoped lang="scss">
@import '~widget/assets/scss/variables.scss';
@import '~widget/assets/scss/mixins.scss';
.header-expanded {
padding: $space-large $space-medium $space-large;
width: 100%;
box-sizing: border-box;
position: relative;
@include shadow-large;
.logo {
width: 56px;
height: 56px;
}
.title {
color: $color-heading;
font-size: $font-size-mega;
font-weight: $font-weight-normal;
margin-bottom: $space-slab;
margin-top: $space-medium;
}
.body {
color: $color-body;
font-size: 1.8rem;
line-height: 1.5;
}
}
.header--row {
display: flex;
align-items: flex-start;
justify-content: space-between;
}
</style>

View File

@@ -2,7 +2,7 @@
<button
type="submit"
:disabled="disabled"
class="send-button"
class="send-button ml-1"
@click="onClick"
>
<i

View File

@@ -1,8 +1,16 @@
<template>
<div class="avatars">
<span v-for="user in users" :key="user.id" class="avatar">
<Thumbnail
size="24px"
<div class="flex overflow-hidden">
<span
v-for="(user, index) in users"
:key="user.id"
:class="
`${
index ? '-ml-4' : ''
} inline-block rounded-full text-white shadow-solid`
"
>
<thumbnail
size="40px"
:username="user.name"
:src="user.avatar"
has-border
@@ -25,22 +33,3 @@ export default {
},
};
</script>
<style scoped lang="scss">
@import '~widget/assets/scss/variables.scss';
@import '~widget/assets/scss/mixins.scss';
.avatars {
display: inline-block;
padding-left: $space-one;
.avatar {
margin-left: -$space-slab;
position: relative;
display: inline-block;
overflow: hidden;
width: $space-medium;
height: $space-medium;
}
}
</style>

View File

@@ -1,5 +1,5 @@
<template>
<div v-if="isIframe" class="actions">
<div v-if="isIframe" class="actions flex items-center">
<button
v-if="showPopoutButton"
class="button transparent compact new-window--button"
@@ -66,9 +66,6 @@ export default {
@import '~widget/assets/scss/variables.scss';
.actions {
display: flex;
align-items: center;
button {
margin-left: $space-normal;
}

View File

@@ -0,0 +1,59 @@
<template>
<div class="px-4">
<div class="flex items-center justify-between mb-4">
<div class="text-black-700">
<div class="text-base leading-5 font-medium mb-1">
{{ teamAvailabilityStatus }}
</div>
<div class="text-xs leading-4 mt-1">
{{ replyTimeStatus }}
</div>
</div>
<available-agents :agents="availableAgents" />
</div>
<woot-button
class="font-medium"
block
:bg-color="widgetColor"
:text-color="textColor"
@click="startConversation"
>
{{ $t('START_CONVERSATION') }}
</woot-button>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
import AvailableAgents from 'widget/components/AvailableAgents.vue';
import { getContrastingTextColor } from 'shared/helpers/ColorHelper';
import WootButton from 'shared/components/Button';
import configMixin from 'widget/mixins/configMixin';
import teamAvailabilityMixin from 'widget/mixins/teamAvailabilityMixin';
export default {
name: 'TeamAvailability',
components: {
AvailableAgents,
WootButton,
},
mixins: [configMixin, teamAvailabilityMixin],
props: {
availableAgents: {
type: Array,
default: () => {},
},
},
computed: {
...mapGetters({ widgetColor: 'appConfig/getWidgetColor' }),
textColor() {
return getContrastingTextColor(this.widgetColor);
},
},
methods: {
startConversation() {
this.$emit('start-conversation');
},
},
};
</script>

View File

@@ -8,12 +8,16 @@
"SUBMIT": "Submit"
}
},
"AGENT_AVAILABILITY": {
"IS_AVAILABLE": "is available",
"ARE_AVAILABLE": "are available",
"OTHERS_ARE_AVAILABLE": "others are available",
"AND": "and"
"TEAM_AVAILABILITY": {
"ONLINE": "We are online",
"OFFLINE": "We are offline"
},
"REPLY_TIME": {
"IN_A_FEW_MINUTES": "Typically replies in a few minutes",
"IN_A_FEW_HOURS": "Typically replies in a few hours",
"IN_A_DAY": "Typically replies in a day"
},
"START_CONVERSATION": "Start Conversation",
"UNREAD_VIEW": {
"VIEW_MESSAGES_BUTTON": "See new messages",
"CLOSE_MESSAGES_BUTTON": "Close"

View File

@@ -1,24 +0,0 @@
export default {
methods: {
getAvailableAgentsText(agents) {
const count = agents.length;
if (count === 1) {
const [agent] = agents;
return `${agent.name} ${this.$t('AGENT_AVAILABILITY.IS_AVAILABLE')}`;
}
if (count === 2) {
const [first, second] = agents;
return `${first.name} ${this.$t('AGENT_AVAILABILITY.AND')} ${
second.name
} ${this.$t('AGENT_AVAILABILITY.ARE_AVAILABLE')}`;
}
const [agent] = agents;
const rest = agents.length - 1;
return `${agent.name} ${this.$t(
'AGENT_AVAILABILITY.AND'
)} ${rest} ${this.$t('AGENT_AVAILABILITY.OTHERS_ARE_AVAILABLE')}`;
},
},
};

View File

@@ -21,5 +21,20 @@ export default {
hasAttachmentsEnabled() {
return this.channelConfig.enabledFeatures.includes('attachments');
},
replyTime() {
return window.chatwootWebChannel.replyTime;
},
replyTimeStatus() {
switch (this.replyTime) {
case 'in_a_few_minutes':
return this.$t('REPLY_TIME.IN_A_FEW_MINUTES');
case 'in_a_few_hours':
return this.$t('REPLY_TIME.IN_A_FEW_HOURS');
case 'in_a_day':
return this.$t('REPLY_TIME.IN_A_DAY');
default:
return this.$t('REPLY_TIME.IN_A_FEW_HOURS');
}
},
},
};

View File

@@ -1,49 +0,0 @@
import { createWrapper } from '@vue/test-utils';
import agentMixin from '../agentMixin';
import Vue from 'vue';
const translations = {
'AGENT_AVAILABILITY.IS_AVAILABLE': 'is available',
'AGENT_AVAILABILITY.ARE_AVAILABLE': 'are available',
'AGENT_AVAILABILITY.OTHERS_ARE_AVAILABLE': 'others are available',
'AGENT_AVAILABILITY.AND': 'and',
};
const TestComponent = {
render() {},
title: 'TestComponent',
mixins: [agentMixin],
methods: {
$t(key) {
return translations[key];
},
},
};
describe('agentMixin', () => {
test('returns correct text', () => {
const Constructor = Vue.extend(TestComponent);
const vm = new Constructor().$mount();
const wrapper = createWrapper(vm);
expect(wrapper.vm.getAvailableAgentsText([{ name: 'Pranav' }])).toEqual(
'Pranav is available'
);
expect(
wrapper.vm.getAvailableAgentsText([
{ name: 'Pranav' },
{ name: 'Nithin' },
])
).toEqual('Pranav and Nithin are available');
expect(
wrapper.vm.getAvailableAgentsText([
{ name: 'Pranav' },
{ name: 'Nithin' },
{ name: 'Subin' },
{ name: 'Sojan' },
])
).toEqual('Pranav and 3 others are available');
});
});

View File

@@ -0,0 +1,10 @@
export default {
computed: {
teamAvailabilityStatus() {
if (this.availableAgents.length) {
return this.$t('TEAM_AVAILABILITY.ONLINE');
}
return this.$t('TEAM_AVAILABILITY.OFFLINE');
},
},
};

View File

@@ -1,26 +1,55 @@
<template>
<div class="home">
<div
v-if="!conversationSize && isFetchingList"
class="flex flex-1 items-center h-full bg-black-25 justify-center"
>
<spinner size=""></spinner>
</div>
<div v-else class="home">
<div class="header-wrap">
<ChatHeaderExpanded
v-if="isHeaderExpanded && !hideWelcomeHeader"
:intro-heading="introHeading"
:intro-body="introBody"
:avatar-url="channelConfig.avatarUrl"
:show-popout-button="showPopoutButton"
/>
<ChatHeader
v-else
:title="channelConfig.websiteName"
:avatar-url="channelConfig.avatarUrl"
:show-popout-button="showPopoutButton"
/>
<transition
enter-active-class="transition-all delay-200 duration-300 ease"
leave-active-class="transition-all duration-200 ease-in"
enter-class="opacity-0 transform -translate-y-32"
enter-to-class="opacity-100 transform translate-y-0"
leave-class="opacity-100 transform translate-y-0"
leave-to-class="opacity-0 transform -translate-y-32"
>
<chat-header-expanded
v-if="!isOnMessageView"
:intro-heading="introHeading"
:intro-body="introBody"
:avatar-url="channelConfig.avatarUrl"
:show-popout-button="showPopoutButton"
/>
<chat-header
v-if="isOnMessageView"
:title="channelConfig.websiteName"
:avatar-url="channelConfig.avatarUrl"
:show-popout-button="showPopoutButton"
:available-agents="availableAgents"
/>
</transition>
</div>
<AvailableAgents v-if="showAvailableAgents" :agents="availableAgents" />
<ConversationWrap :grouped-messages="groupedMessages" />
<conversation-wrap :grouped-messages="groupedMessages" />
<div class="footer-wrap">
<div v-if="showInputTextArea" class="input-wrap">
<ChatFooter />
</div>
<transition
enter-active-class="transition-all delay-300 duration-300 ease"
leave-active-class="transition-all duration-200 ease-in"
enter-class="opacity-0 transform translate-y-32"
enter-to-class="opacity-100 transform translate-y-0"
leave-class="opacity-100 transform translate-y-0"
leave-to-class="opacity-0 transform translate-y-32 "
>
<div v-if="showInputTextArea && isOnMessageView" class="input-wrap">
<chat-footer />
</div>
<team-availability
v-if="!isOnMessageView"
:available-agents="availableAgents"
@start-conversation="startConversation"
/>
</transition>
<branding></branding>
</div>
</div>
@@ -32,18 +61,21 @@ import ChatFooter from 'widget/components/ChatFooter.vue';
import ChatHeaderExpanded from 'widget/components/ChatHeaderExpanded.vue';
import ChatHeader from 'widget/components/ChatHeader.vue';
import ConversationWrap from 'widget/components/ConversationWrap.vue';
import AvailableAgents from 'widget/components/AvailableAgents.vue';
import configMixin from '../mixins/configMixin';
import TeamAvailability from 'widget/components/TeamAvailability';
import Spinner from 'shared/components/Spinner.vue';
import { mapGetters } from 'vuex';
export default {
name: 'Home',
components: {
Branding,
ChatFooter,
ChatHeader,
ChatHeaderExpanded,
ConversationWrap,
ChatHeader,
Branding,
AvailableAgents,
Spinner,
TeamAvailability,
},
mixins: [configMixin],
props: {
@@ -67,16 +99,20 @@ export default {
type: Object,
default: () => {},
},
unreadMessageCount: {
type: Number,
default: 0,
},
showPopoutButton: {
type: Boolean,
default: false,
},
},
data() {
return {
showMessageView: false,
};
},
computed: {
...mapGetters({
isFetchingList: 'conversation/getIsFetchingList',
}),
isOpen() {
return this.conversationAttributes.status === 'open';
},
@@ -89,12 +125,18 @@ export default {
}
return true;
},
isOnMessageView() {
if (this.hideWelcomeHeader) {
return true;
}
if (this.conversationSize === 0) {
return this.showMessageView;
}
return true;
},
isHeaderExpanded() {
return this.conversationSize === 0;
},
showAvailableAgents() {
return this.availableAgents.length > 0 && this.conversationSize < 1;
},
introHeading() {
return this.channelConfig.welcomeTitle;
},
@@ -105,11 +147,16 @@ export default {
return !(this.introHeading || this.introBody);
},
},
methods: {
startConversation() {
this.showMessageView = !this.showMessageView;
},
},
};
</script>
<style scoped lang="scss">
@import '~widget/assets/scss/woot.scss';
@import '~widget/assets/scss/variables';
.home {
width: 100%;
@@ -117,14 +164,13 @@ export default {
display: flex;
flex-direction: column;
flex-wrap: nowrap;
overflow: hidden;
background: $color-background;
.header-wrap {
flex-shrink: 0;
border-radius: $space-normal $space-normal $space-small $space-small;
background: white;
z-index: 99;
@include shadow-large;
@media only screen and (min-device-width: 320px) and (max-device-width: 667px) {
border-radius: 0;

View File

@@ -32,8 +32,6 @@
</template>
<script>
/* global bus */
import { IFrameHelper } from 'widget/helpers/utils';
import AgentBubble from 'widget/components/AgentMessageBubble.vue';
import configMixin from '../mixins/configMixin';
@@ -94,7 +92,8 @@ export default {
};
</script>
<style lang="scss" scoped>
@import '~widget/assets/scss/woot.scss';
@import '~widget/assets/scss/variables';
.unread-wrap {
width: 100%;
height: 100%;
@@ -148,7 +147,7 @@ export default {
</style>
<style lang="scss">
@import '~widget/assets/scss/woot.scss';
@import '~widget/assets/scss/variables';
.unread-messages {
width: 100%;