feat: Disable attachments and emoji picker in the web widget (#1102)
Signed-off-by: Pranav Raj Sreepuram <pranavrajs@gmail.com>
This commit is contained in:
parent
3b23aa7913
commit
db877453a4
23 changed files with 422 additions and 141 deletions
|
@ -4,7 +4,7 @@ class Api::V1::Accounts::InboxesController < Api::V1::Accounts::BaseController
|
||||||
before_action :check_authorization
|
before_action :check_authorization
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@inboxes = policy_scope(Current.account.inboxes.includes(:channel, :avatar_attachment))
|
@inboxes = policy_scope(Current.account.inboxes.order_by_id.includes(:channel, :avatar_attachment))
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
|
@ -23,7 +23,10 @@ class Api::V1::Accounts::InboxesController < Api::V1::Accounts::BaseController
|
||||||
|
|
||||||
def update
|
def update
|
||||||
@inbox.update(inbox_update_params.except(:channel))
|
@inbox.update(inbox_update_params.except(:channel))
|
||||||
@inbox.channel.update!(inbox_update_params[:channel]) if @inbox.channel.is_a?(Channel::WebWidget) && inbox_update_params[:channel].present?
|
return unless @inbox.channel.is_a?(Channel::WebWidget) && inbox_update_params[:channel].present?
|
||||||
|
|
||||||
|
@inbox.channel.update!(inbox_update_params[:channel])
|
||||||
|
update_channel_feature_flags
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_agent_bot
|
def set_agent_bot
|
||||||
|
@ -67,6 +70,13 @@ class Api::V1::Accounts::InboxesController < Api::V1::Accounts::BaseController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def update_channel_feature_flags
|
||||||
|
return unless inbox_update_params[:channel].key? :selected_feature_flags
|
||||||
|
|
||||||
|
@inbox.channel.selected_feature_flags = inbox_update_params[:channel][:selected_feature_flags]
|
||||||
|
@inbox.channel.save!
|
||||||
|
end
|
||||||
|
|
||||||
def permitted_params
|
def permitted_params
|
||||||
params.permit(:id, :avatar, :name, :greeting_message, :greeting_enabled, channel:
|
params.permit(:id, :avatar, :name, :greeting_message, :greeting_enabled, channel:
|
||||||
[:type, :website_url, :widget_color, :welcome_title, :welcome_tagline, :webhook_url, :email])
|
[:type, :website_url, :widget_color, :welcome_title, :welcome_tagline, :webhook_url, :email])
|
||||||
|
@ -74,6 +84,14 @@ class Api::V1::Accounts::InboxesController < Api::V1::Accounts::BaseController
|
||||||
|
|
||||||
def inbox_update_params
|
def inbox_update_params
|
||||||
params.permit(:enable_auto_assignment, :name, :avatar, :greeting_message, :greeting_enabled,
|
params.permit(:enable_auto_assignment, :name, :avatar, :greeting_message, :greeting_enabled,
|
||||||
channel: [:website_url, :widget_color, :welcome_title, :welcome_tagline, :webhook_url, :email])
|
channel: [
|
||||||
|
:website_url,
|
||||||
|
:widget_color,
|
||||||
|
:welcome_title,
|
||||||
|
:welcome_tagline,
|
||||||
|
:webhook_url,
|
||||||
|
:email,
|
||||||
|
selected_feature_flags: []
|
||||||
|
])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
html,
|
html,
|
||||||
body {
|
body {
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-wrapper {
|
.app-wrapper {
|
||||||
|
@ -26,36 +26,40 @@ body {
|
||||||
|
|
||||||
.view-box {
|
.view-box {
|
||||||
@include full-height;
|
@include full-height;
|
||||||
height: 100vh;
|
|
||||||
@include margin(0);
|
@include margin(0);
|
||||||
@include space-between-column;
|
@include space-between-column;
|
||||||
|
|
||||||
|
height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
.view-panel {
|
.view-panel {
|
||||||
flex-direction: column;
|
|
||||||
@include margin($zero);
|
@include margin($zero);
|
||||||
@include padding($space-normal);
|
@include padding($space-normal);
|
||||||
|
|
||||||
|
flex-direction: column;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content-box {
|
.content-box {
|
||||||
overflow: auto;
|
|
||||||
@include padding($space-normal);
|
@include padding($space-normal);
|
||||||
|
|
||||||
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.back-button {
|
.back-button {
|
||||||
@include flex;
|
@include flex;
|
||||||
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
color: $color-woot;
|
color: $color-woot;
|
||||||
|
cursor: pointer;
|
||||||
font-size: $font-size-default;
|
font-size: $font-size-default;
|
||||||
font-weight: $font-weight-normal;
|
font-weight: $font-weight-normal;
|
||||||
margin-right: $space-normal;
|
margin-right: $space-normal;
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&:before {
|
&::before {
|
||||||
vertical-align: text-bottom;
|
|
||||||
margin-right: $space-smaller;
|
|
||||||
font-size: $font-size-large;
|
font-size: $font-size-large;
|
||||||
|
margin-right: $space-small;
|
||||||
|
vertical-align: text-bottom;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,12 +70,14 @@ body {
|
||||||
.no-items-error-message {
|
.no-items-error-message {
|
||||||
@include flex;
|
@include flex;
|
||||||
@include full-height;
|
@include full-height;
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
img {
|
img {
|
||||||
max-width: $space-mega;
|
|
||||||
@include padding($space-one);
|
@include padding($space-one);
|
||||||
|
|
||||||
|
max-width: $space-mega;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -202,7 +202,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.settings--content {
|
.settings--content {
|
||||||
@include margin($space-small $space-larger);
|
@include margin($space-small $space-large);
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
font-weight: $font-weight-medium;
|
font-weight: $font-weight-medium;
|
||||||
|
|
|
@ -7,15 +7,25 @@
|
||||||
<p v-if="headerContent" class="small-12 column">
|
<p v-if="headerContent" class="small-12 column">
|
||||||
{{ headerContent }}
|
{{ headerContent }}
|
||||||
</p>
|
</p>
|
||||||
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
headerTitle: String,
|
headerTitle: {
|
||||||
headerContent: String,
|
type: String,
|
||||||
headerImage: String,
|
default: '',
|
||||||
|
},
|
||||||
|
headerContent: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
headerImage: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -57,15 +57,8 @@ import { mapGetters } from 'vuex';
|
||||||
|
|
||||||
import router from '../../routes';
|
import router from '../../routes';
|
||||||
import adminMixin from '../../mixins/isAdmin';
|
import adminMixin from '../../mixins/isAdmin';
|
||||||
|
import { INBOX_TYPES } from 'shared/mixins/inboxMixin';
|
||||||
|
|
||||||
const INBOX_TYPES = {
|
|
||||||
WEB: 'Channel::WebWidget',
|
|
||||||
FB: 'Channel::FacebookPage',
|
|
||||||
TWITTER: 'Channel::TwitterProfile',
|
|
||||||
TWILIO: 'Channel::TwilioSms',
|
|
||||||
API: 'Channel::Api',
|
|
||||||
EMAIL: 'Channel::Email',
|
|
||||||
};
|
|
||||||
const getInboxClassByType = type => {
|
const getInboxClassByType = type => {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case INBOX_TYPES.WEB:
|
case INBOX_TYPES.WEB:
|
||||||
|
|
|
@ -1,43 +1,43 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="small-3 columns channel"
|
class="small-3 columns channel"
|
||||||
:class="{ inactive: !isActive(channel) }"
|
:class="{ inactive: !isActive }"
|
||||||
@click="onItemClick"
|
@click="onItemClick"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
v-if="channel === 'facebook'"
|
v-if="channel.key === 'facebook'"
|
||||||
src="~dashboard/assets/images/channels/facebook.png"
|
src="~dashboard/assets/images/channels/facebook.png"
|
||||||
/>
|
/>
|
||||||
<img
|
<img
|
||||||
v-if="channel === 'twitter'"
|
v-if="channel.key === 'twitter'"
|
||||||
src="~dashboard/assets/images/channels/twitter.png"
|
src="~dashboard/assets/images/channels/twitter.png"
|
||||||
/>
|
/>
|
||||||
<img
|
<img
|
||||||
v-if="channel === 'telegram'"
|
v-if="channel.key === 'telegram'"
|
||||||
src="~dashboard/assets/images/channels/telegram.png"
|
src="~dashboard/assets/images/channels/telegram.png"
|
||||||
/>
|
/>
|
||||||
<img
|
<img
|
||||||
v-if="channel === 'api'"
|
v-if="channel.key === 'api'"
|
||||||
src="~dashboard/assets/images/channels/api.png"
|
src="~dashboard/assets/images/channels/api.png"
|
||||||
/>
|
/>
|
||||||
<img
|
<img
|
||||||
v-if="channel === 'email'"
|
v-if="channel.key === 'email'"
|
||||||
src="~dashboard/assets/images/channels/email.png"
|
src="~dashboard/assets/images/channels/email.png"
|
||||||
/>
|
/>
|
||||||
<img
|
<img
|
||||||
v-if="channel === 'line'"
|
v-if="channel.key === 'line'"
|
||||||
src="~dashboard/assets/images/channels/line.png"
|
src="~dashboard/assets/images/channels/line.png"
|
||||||
/>
|
/>
|
||||||
<img
|
<img
|
||||||
v-if="channel === 'website'"
|
v-if="channel.key === 'website'"
|
||||||
src="~dashboard/assets/images/channels/website.png"
|
src="~dashboard/assets/images/channels/website.png"
|
||||||
/>
|
/>
|
||||||
<img
|
<img
|
||||||
v-if="channel === 'twilio'"
|
v-if="channel.key === 'twilio'"
|
||||||
src="~dashboard/assets/images/channels/twilio.png"
|
src="~dashboard/assets/images/channels/twilio.png"
|
||||||
/>
|
/>
|
||||||
<h3 class="channel__title">
|
<h3 class="channel__title">
|
||||||
{{ channel }}
|
{{ channel.name }}
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -45,7 +45,7 @@
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
channel: {
|
channel: {
|
||||||
type: String,
|
type: Object,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
enabledFeatures: {
|
enabledFeatures: {
|
||||||
|
@ -53,25 +53,28 @@ export default {
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
computed: {
|
||||||
isActive(channel) {
|
isActive() {
|
||||||
|
const { key } = this.channel;
|
||||||
if (Object.keys(this.enabledFeatures) === 0) {
|
if (Object.keys(this.enabledFeatures) === 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (channel === 'facebook') {
|
if (key === 'facebook') {
|
||||||
return this.enabledFeatures.channel_facebook;
|
return this.enabledFeatures.channel_facebook;
|
||||||
}
|
}
|
||||||
if (channel === 'twitter') {
|
if (key === 'twitter') {
|
||||||
return this.enabledFeatures.channel_twitter;
|
return this.enabledFeatures.channel_twitter;
|
||||||
}
|
}
|
||||||
if (channel === 'email') {
|
if (key === 'email') {
|
||||||
return this.enabledFeatures.channel_email;
|
return this.enabledFeatures.channel_email;
|
||||||
}
|
}
|
||||||
return ['website', 'twilio', 'api'].includes(channel);
|
return ['website', 'twilio', 'api'].includes(key);
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
onItemClick() {
|
onItemClick() {
|
||||||
if (this.isActive(this.channel)) {
|
if (this.isActive) {
|
||||||
this.$emit('channel-item-click', this.channel);
|
this.$emit('channel-item-click', this.channel.key);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -96,6 +96,7 @@ import {
|
||||||
hasPressedShift,
|
hasPressedShift,
|
||||||
} from 'shared/helpers/KeyboardHelpers';
|
} from 'shared/helpers/KeyboardHelpers';
|
||||||
import { MESSAGE_MAX_LENGTH } from 'shared/helpers/MessageTypeHelper';
|
import { MESSAGE_MAX_LENGTH } from 'shared/helpers/MessageTypeHelper';
|
||||||
|
import inboxMixin from 'shared/mixins/inboxMixin';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
@ -104,7 +105,7 @@ export default {
|
||||||
FileUpload,
|
FileUpload,
|
||||||
ResizableTextArea,
|
ResizableTextArea,
|
||||||
},
|
},
|
||||||
mixins: [clickaway],
|
mixins: [clickaway, inboxMixin],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
message: '',
|
message: '',
|
||||||
|
@ -148,9 +149,6 @@ export default {
|
||||||
this.message.length > this.maxLength
|
this.message.length > this.maxLength
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
channelType() {
|
|
||||||
return this.inbox.channel_type;
|
|
||||||
},
|
|
||||||
conversationType() {
|
conversationType() {
|
||||||
const { additional_attributes: additionalAttributes } = this.currentChat;
|
const { additional_attributes: additionalAttributes } = this.currentChat;
|
||||||
const type = additionalAttributes ? additionalAttributes.type : '';
|
const type = additionalAttributes ? additionalAttributes.type : '';
|
||||||
|
@ -174,29 +172,6 @@ export default {
|
||||||
}
|
}
|
||||||
return MESSAGE_MAX_LENGTH.GENERAL;
|
return MESSAGE_MAX_LENGTH.GENERAL;
|
||||||
},
|
},
|
||||||
isATwitterInbox() {
|
|
||||||
return this.channelType === 'Channel::TwitterProfile';
|
|
||||||
},
|
|
||||||
isAFacebookInbox() {
|
|
||||||
return this.channelType === 'Channel::FacebookPage';
|
|
||||||
},
|
|
||||||
isAWebWidgetInbox() {
|
|
||||||
return this.channelType === 'Channel::WebWidget';
|
|
||||||
},
|
|
||||||
isATwilioSMSChannel() {
|
|
||||||
const { phone_number: phoneNumber = '' } = this.inbox;
|
|
||||||
return (
|
|
||||||
this.channelType === 'Channel::TwilioSms' &&
|
|
||||||
!phoneNumber.startsWith('whatsapp')
|
|
||||||
);
|
|
||||||
},
|
|
||||||
isATwilioWhatsappChannel() {
|
|
||||||
const { phone_number: phoneNumber = '' } = this.inbox;
|
|
||||||
return (
|
|
||||||
this.channelType === 'Channel::TwilioSms' &&
|
|
||||||
phoneNumber.startsWith('whatsapp')
|
|
||||||
);
|
|
||||||
},
|
|
||||||
showFileUpload() {
|
showFileUpload() {
|
||||||
return (
|
return (
|
||||||
this.isAWebWidgetInbox ||
|
this.isAWebWidgetInbox ||
|
||||||
|
|
|
@ -117,16 +117,16 @@
|
||||||
},
|
},
|
||||||
"API_CHANNEL": {
|
"API_CHANNEL": {
|
||||||
"TITLE": "API Channel",
|
"TITLE": "API Channel",
|
||||||
"DESC": "Integrate with API channel and start supporting your customers via chatwoot.",
|
"DESC": "Integrate with API channel and start supporting your customers.",
|
||||||
"CHANNEL_NAME": {
|
"CHANNEL_NAME": {
|
||||||
"LABEL": "Channel Name",
|
"LABEL": "Channel Name",
|
||||||
"PLACEHOLDER": "Please enter a channel name",
|
"PLACEHOLDER": "Please enter a channel name",
|
||||||
"ERROR": "This field is required"
|
"ERROR": "This field is required"
|
||||||
},
|
},
|
||||||
"WEBHOOK_URL": {
|
"WEBHOOK_URL": {
|
||||||
"LABEL": "Webhook Url",
|
"LABEL": "Webhook URL",
|
||||||
"SUBTITLE": "Configure the url where you want to recieve callbacks from chatwoot on events.",
|
"SUBTITLE": "Configure the URL where you want to recieve callbacks on events.",
|
||||||
"PLACEHOLDER": "Webhook Url"
|
"PLACEHOLDER": "Webhook URL"
|
||||||
},
|
},
|
||||||
"SUBMIT_BUTTON": "Create API Channel",
|
"SUBMIT_BUTTON": "Create API Channel",
|
||||||
"API": {
|
"API": {
|
||||||
|
@ -135,7 +135,7 @@
|
||||||
},
|
},
|
||||||
"EMAIL_CHANNEL": {
|
"EMAIL_CHANNEL": {
|
||||||
"TITLE": "Email Channel",
|
"TITLE": "Email Channel",
|
||||||
"DESC": "Integrate you email inbox with chatwoot.",
|
"DESC": "Integrate you email inbox.",
|
||||||
"CHANNEL_NAME": {
|
"CHANNEL_NAME": {
|
||||||
"LABEL": "Channel Name",
|
"LABEL": "Channel Name",
|
||||||
"PLACEHOLDER": "Please enter a channel name",
|
"PLACEHOLDER": "Please enter a channel name",
|
||||||
|
@ -150,7 +150,7 @@
|
||||||
"API": {
|
"API": {
|
||||||
"ERROR_MESSAGE": "We were not able to save the email channel"
|
"ERROR_MESSAGE": "We were not able to save the email channel"
|
||||||
},
|
},
|
||||||
"FINISH_MESSAGE" : "Start forwarding your emails to the following email address."
|
"FINISH_MESSAGE": "Start forwarding your emails to the following email address."
|
||||||
},
|
},
|
||||||
"AUTH": {
|
"AUTH": {
|
||||||
"TITLE": "Channels",
|
"TITLE": "Channels",
|
||||||
|
@ -212,7 +212,17 @@
|
||||||
"ERROR_MESSAGE": "Could not delete inbox. Please try again later."
|
"ERROR_MESSAGE": "Could not delete inbox. Please try again later."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"TABS": {
|
||||||
|
"SETTINGS": "Settings",
|
||||||
|
"COLLABORATORS": "Collaborators",
|
||||||
|
"CONFIGURATION": "Configuration"
|
||||||
|
},
|
||||||
"SETTINGS": "Settings",
|
"SETTINGS": "Settings",
|
||||||
|
"FEATURES": {
|
||||||
|
"LABEL": "Features",
|
||||||
|
"DISPLAY_FILE_PICKER": "Display file picker on the widget",
|
||||||
|
"DISPLAY_EMOJI_PICKER": "Display emoji picker on the widget"
|
||||||
|
},
|
||||||
"SETTINGS_POPUP": {
|
"SETTINGS_POPUP": {
|
||||||
"MESSENGER_HEADING": "Messenger Script",
|
"MESSENGER_HEADING": "Messenger Script",
|
||||||
"MESSENGER_SUB_HEAD": "Place this button inside your body tag",
|
"MESSENGER_SUB_HEAD": "Place this button inside your body tag",
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
v-model="selectedAgents"
|
v-model="selectedAgents"
|
||||||
:options="agentList"
|
:options="agentList"
|
||||||
track-by="id"
|
track-by="id"
|
||||||
label="name"
|
label="available_name"
|
||||||
:multiple="true"
|
:multiple="true"
|
||||||
:close-on-select="false"
|
:close-on-select="false"
|
||||||
:clear-on-select="false"
|
:clear-on-select="false"
|
||||||
|
|
|
@ -30,14 +30,14 @@ export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
channelList: [
|
channelList: [
|
||||||
'website',
|
{ key: 'website', name: 'Website' },
|
||||||
'facebook',
|
{ key: 'facebook', name: 'Facebook' },
|
||||||
'twitter',
|
{ key: 'twitter', name: 'Twitter' },
|
||||||
'twilio',
|
{ key: 'twilio', name: 'Twilio' },
|
||||||
'email',
|
{ key: 'email', name: 'Email' },
|
||||||
'api',
|
{ key: 'api', name: 'API' },
|
||||||
'telegram',
|
{ key: 'telegram', name: 'Telegram' },
|
||||||
'line',
|
{ key: 'line', name: 'Line' },
|
||||||
],
|
],
|
||||||
enabledFeatures: {},
|
enabledFeatures: {},
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,9 +3,18 @@
|
||||||
<woot-modal-header
|
<woot-modal-header
|
||||||
:header-image="inbox.avatarUrl"
|
:header-image="inbox.avatarUrl"
|
||||||
:header-title="inboxName"
|
:header-title="inboxName"
|
||||||
/>
|
>
|
||||||
|
<woot-tabs :index="selectedTabIndex" @change="onTabChange">
|
||||||
|
<woot-tabs-item
|
||||||
|
v-for="tab in tabs"
|
||||||
|
:key="tab.key"
|
||||||
|
:name="tab.name"
|
||||||
|
:show-badge="false"
|
||||||
|
/>
|
||||||
|
</woot-tabs>
|
||||||
|
</woot-modal-header>
|
||||||
|
|
||||||
<div class="settings--content">
|
<div v-if="selectedTabKey === 'inbox_settings'" class="settings--content">
|
||||||
<settings-section
|
<settings-section
|
||||||
:title="$t('INBOX_MGMT.SETTINGS_POPUP.INBOX_UPDATE_TITLE')"
|
:title="$t('INBOX_MGMT.SETTINGS_POPUP.INBOX_UPDATE_TITLE')"
|
||||||
:sub-title="$t('INBOX_MGMT.SETTINGS_POPUP.INBOX_UPDATE_SUB_TEXT')"
|
:sub-title="$t('INBOX_MGMT.SETTINGS_POPUP.INBOX_UPDATE_SUB_TEXT')"
|
||||||
|
@ -16,7 +25,7 @@
|
||||||
@change="handleImageUpload"
|
@change="handleImageUpload"
|
||||||
/>
|
/>
|
||||||
<woot-input
|
<woot-input
|
||||||
v-if="isAWidgetInbox"
|
v-if="isAWebWidgetInbox"
|
||||||
v-model.trim="selectedInboxName"
|
v-model.trim="selectedInboxName"
|
||||||
class="medium-9 columns"
|
class="medium-9 columns"
|
||||||
:label="$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_NAME.LABEL')"
|
:label="$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_NAME.LABEL')"
|
||||||
|
@ -25,7 +34,7 @@
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
<woot-input
|
<woot-input
|
||||||
v-if="isAWidgetInbox"
|
v-if="isAWebWidgetInbox"
|
||||||
v-model.trim="channelWebsiteUrl"
|
v-model.trim="channelWebsiteUrl"
|
||||||
class="medium-9 columns"
|
class="medium-9 columns"
|
||||||
:label="$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_DOMAIN.LABEL')"
|
:label="$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_DOMAIN.LABEL')"
|
||||||
|
@ -34,7 +43,7 @@
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
<woot-input
|
<woot-input
|
||||||
v-if="isAWidgetInbox"
|
v-if="isAWebWidgetInbox"
|
||||||
v-model.trim="channelWelcomeTitle"
|
v-model.trim="channelWelcomeTitle"
|
||||||
class="medium-9 columns"
|
class="medium-9 columns"
|
||||||
:label="
|
:label="
|
||||||
|
@ -48,7 +57,7 @@
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<woot-input
|
<woot-input
|
||||||
v-if="isAWidgetInbox"
|
v-if="isAWebWidgetInbox"
|
||||||
v-model.trim="channelWelcomeTagline"
|
v-model.trim="channelWelcomeTagline"
|
||||||
class="medium-9 columns"
|
class="medium-9 columns"
|
||||||
:label="
|
:label="
|
||||||
|
@ -61,7 +70,7 @@
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<label v-if="isAWidgetInbox" class="medium-9 columns">
|
<label v-if="isAWebWidgetInbox" class="medium-9 columns">
|
||||||
{{ $t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.WIDGET_COLOR.LABEL') }}
|
{{ $t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.WIDGET_COLOR.LABEL') }}
|
||||||
<woot-color-picker v-model="inbox.widget_color" />
|
<woot-color-picker v-model="inbox.widget_color" />
|
||||||
</label>
|
</label>
|
||||||
|
@ -94,7 +103,6 @@
|
||||||
}}
|
}}
|
||||||
</p>
|
</p>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<woot-input
|
<woot-input
|
||||||
v-if="greetingEnabled"
|
v-if="greetingEnabled"
|
||||||
v-model.trim="greetingMessage"
|
v-model.trim="greetingMessage"
|
||||||
|
@ -122,6 +130,33 @@
|
||||||
{{ $t('INBOX_MGMT.SETTINGS_POPUP.AUTO_ASSIGNMENT_SUB_TEXT') }}
|
{{ $t('INBOX_MGMT.SETTINGS_POPUP.AUTO_ASSIGNMENT_SUB_TEXT') }}
|
||||||
</p>
|
</p>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
|
<label v-if="isAWebWidgetInbox">
|
||||||
|
{{ $t('INBOX_MGMT.FEATURES.LABEL') }}
|
||||||
|
</label>
|
||||||
|
<div v-if="isAWebWidgetInbox" class="widget--feature-flag">
|
||||||
|
<input
|
||||||
|
v-model="selectedFeatureFlags"
|
||||||
|
type="checkbox"
|
||||||
|
value="attachments"
|
||||||
|
@input="handleFeatureFlag"
|
||||||
|
/>
|
||||||
|
<label for="attachments">
|
||||||
|
{{ $t('INBOX_MGMT.FEATURES.DISPLAY_FILE_PICKER') }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div v-if="isAWebWidgetInbox">
|
||||||
|
<input
|
||||||
|
v-model="selectedFeatureFlags"
|
||||||
|
type="checkbox"
|
||||||
|
value="emoji_picker"
|
||||||
|
@input="handleFeatureFlag"
|
||||||
|
/>
|
||||||
|
<label for="emoji_picker">
|
||||||
|
{{ $t('INBOX_MGMT.FEATURES.DISPLAY_EMOJI_PICKER') }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
<woot-submit-button
|
<woot-submit-button
|
||||||
:button-text="$t('INBOX_MGMT.SETTINGS_POPUP.UPDATE')"
|
:button-text="$t('INBOX_MGMT.SETTINGS_POPUP.UPDATE')"
|
||||||
:loading="uiFlags.isUpdatingInbox"
|
:loading="uiFlags.isUpdatingInbox"
|
||||||
|
@ -132,7 +167,7 @@
|
||||||
|
|
||||||
<!-- update agents in inbox -->
|
<!-- update agents in inbox -->
|
||||||
|
|
||||||
<div class="settings--content">
|
<div v-if="selectedTabKey === 'collaborators'" class="settings--content">
|
||||||
<settings-section
|
<settings-section
|
||||||
:title="$t('INBOX_MGMT.SETTINGS_POPUP.INBOX_AGENTS')"
|
:title="$t('INBOX_MGMT.SETTINGS_POPUP.INBOX_AGENTS')"
|
||||||
:sub-title="$t('INBOX_MGMT.SETTINGS_POPUP.INBOX_AGENTS_SUB_TEXT')"
|
:sub-title="$t('INBOX_MGMT.SETTINGS_POPUP.INBOX_AGENTS_SUB_TEXT')"
|
||||||
|
@ -141,7 +176,7 @@
|
||||||
v-model="selectedAgents"
|
v-model="selectedAgents"
|
||||||
:options="agentList"
|
:options="agentList"
|
||||||
track-by="id"
|
track-by="id"
|
||||||
label="name"
|
label="available_name"
|
||||||
:multiple="true"
|
:multiple="true"
|
||||||
:close-on-select="false"
|
:close-on-select="false"
|
||||||
:clear-on-select="false"
|
:clear-on-select="false"
|
||||||
|
@ -157,56 +192,43 @@
|
||||||
/>
|
/>
|
||||||
</settings-section>
|
</settings-section>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="selectedTabKey === 'configuration'">
|
||||||
<div
|
<div v-if="isATwilioChannel" class="settings--content">
|
||||||
v-if="inbox.channel_type === 'Channel::TwilioSms'"
|
|
||||||
class="settings--content"
|
|
||||||
>
|
|
||||||
<settings-section
|
|
||||||
:title="$t('INBOX_MGMT.ADD.TWILIO.API_CALLBACK.TITLE')"
|
|
||||||
:sub-title="$t('INBOX_MGMT.ADD.TWILIO.API_CALLBACK.SUBTITLE')"
|
|
||||||
>
|
|
||||||
<woot-code :script="twilioCallbackURL" lang="html"></woot-code>
|
|
||||||
</settings-section>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
v-if="inbox.channel_type === 'Channel::FacebookPage'"
|
|
||||||
class="settings--content"
|
|
||||||
>
|
|
||||||
<settings-section
|
|
||||||
:title="$t('INBOX_MGMT.SETTINGS_POPUP.MESSENGER_HEADING')"
|
|
||||||
:sub-title="$t('INBOX_MGMT.SETTINGS_POPUP.MESSENGER_SUB_HEAD')"
|
|
||||||
>
|
|
||||||
<woot-code :script="messengerScript"></woot-code>
|
|
||||||
</settings-section>
|
|
||||||
</div>
|
|
||||||
<div v-else-if="inbox.channel_type === 'Channel::WebWidget'">
|
|
||||||
<div class="settings--content">
|
|
||||||
<settings-section
|
<settings-section
|
||||||
:title="$t('INBOX_MGMT.SETTINGS_POPUP.MESSENGER_HEADING')"
|
:title="$t('INBOX_MGMT.ADD.TWILIO.API_CALLBACK.TITLE')"
|
||||||
:sub-title="$t('INBOX_MGMT.SETTINGS_POPUP.MESSENGER_SUB_HEAD')"
|
:sub-title="$t('INBOX_MGMT.ADD.TWILIO.API_CALLBACK.SUBTITLE')"
|
||||||
>
|
>
|
||||||
<woot-code :script="inbox.web_widget_script"></woot-code>
|
<woot-code :script="twilioCallbackURL" lang="html"></woot-code>
|
||||||
</settings-section>
|
</settings-section>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else-if="isAWebWidgetInbox">
|
||||||
|
<div class="settings--content">
|
||||||
|
<settings-section
|
||||||
|
:title="$t('INBOX_MGMT.SETTINGS_POPUP.MESSENGER_HEADING')"
|
||||||
|
:sub-title="$t('INBOX_MGMT.SETTINGS_POPUP.MESSENGER_SUB_HEAD')"
|
||||||
|
>
|
||||||
|
<woot-code :script="inbox.web_widget_script"></woot-code>
|
||||||
|
</settings-section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
/* eslint no-console: 0 */
|
/* eslint no-console: 0 */
|
||||||
/* global bus */
|
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import { createMessengerScript } from 'dashboard/helper/scriptGenerator';
|
import { createMessengerScript } from 'dashboard/helper/scriptGenerator';
|
||||||
import configMixin from 'shared/mixins/configMixin';
|
import configMixin from 'shared/mixins/configMixin';
|
||||||
|
import alertMixin from 'shared/mixins/alertMixin';
|
||||||
import SettingsSection from '../../../../components/SettingsSection';
|
import SettingsSection from '../../../../components/SettingsSection';
|
||||||
|
import inboxMixin from 'shared/mixins/inboxMixin';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
SettingsSection,
|
SettingsSection,
|
||||||
},
|
},
|
||||||
mixins: [configMixin],
|
mixins: [alertMixin, configMixin, inboxMixin],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
avatarFile: null,
|
avatarFile: null,
|
||||||
|
@ -220,6 +242,7 @@ export default {
|
||||||
channelWebsiteUrl: '',
|
channelWebsiteUrl: '',
|
||||||
channelWelcomeTitle: '',
|
channelWelcomeTitle: '',
|
||||||
channelWelcomeTagline: '',
|
channelWelcomeTagline: '',
|
||||||
|
selectedFeatureFlags: [],
|
||||||
autoAssignmentOptions: [
|
autoAssignmentOptions: [
|
||||||
{
|
{
|
||||||
value: true,
|
value: true,
|
||||||
|
@ -230,6 +253,7 @@ export default {
|
||||||
label: this.$t('INBOX_MGMT.EDIT.AUTO_ASSIGNMENT.DISABLED'),
|
label: this.$t('INBOX_MGMT.EDIT.AUTO_ASSIGNMENT.DISABLED'),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
selectedTabIndex: 0,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -237,17 +261,41 @@ export default {
|
||||||
agentList: 'agents/getAgents',
|
agentList: 'agents/getAgents',
|
||||||
uiFlags: 'inboxes/getUIFlags',
|
uiFlags: 'inboxes/getUIFlags',
|
||||||
}),
|
}),
|
||||||
|
selectedTabKey() {
|
||||||
|
return this.tabs[this.selectedTabIndex]?.key;
|
||||||
|
},
|
||||||
|
tabs() {
|
||||||
|
const visibleToAllChannelTabs = [
|
||||||
|
{
|
||||||
|
key: 'inbox_settings',
|
||||||
|
name: this.$t('INBOX_MGMT.TABS.SETTINGS'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'collaborators',
|
||||||
|
name: this.$t('INBOX_MGMT.TABS.COLLABORATORS'),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
if (this.isAWebWidgetInbox || this.isATwilioChannel) {
|
||||||
|
return [
|
||||||
|
...visibleToAllChannelTabs,
|
||||||
|
{
|
||||||
|
key: 'configuration',
|
||||||
|
name: this.$t('INBOX_MGMT.TABS.CONFIGURATION'),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return visibleToAllChannelTabs;
|
||||||
|
},
|
||||||
currentInboxId() {
|
currentInboxId() {
|
||||||
return this.$route.params.inboxId;
|
return this.$route.params.inboxId;
|
||||||
},
|
},
|
||||||
inbox() {
|
inbox() {
|
||||||
return this.$store.getters['inboxes/getInbox'](this.currentInboxId);
|
return this.$store.getters['inboxes/getInbox'](this.currentInboxId);
|
||||||
},
|
},
|
||||||
isAWidgetInbox() {
|
|
||||||
return this.inbox.channel_type === 'Channel::WebWidget';
|
|
||||||
},
|
|
||||||
inboxName() {
|
inboxName() {
|
||||||
if (this.inbox.channel_type === 'Channel::TwilioSms') {
|
if (this.isATwilioSMSChannel || this.isATwilioWhatsappChannel) {
|
||||||
return `${this.inbox.name} (${this.inbox.phone_number})`;
|
return `${this.inbox.name} (${this.inbox.phone_number})`;
|
||||||
}
|
}
|
||||||
return this.inbox.name;
|
return this.inbox.name;
|
||||||
|
@ -267,10 +315,25 @@ export default {
|
||||||
this.fetchInboxSettings();
|
this.fetchInboxSettings();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
showAlert(message) {
|
handleFeatureFlag(e) {
|
||||||
bus.$emit('newToastMessage', message);
|
console.log(e.target.value);
|
||||||
|
this.selectedFeatureFlags = this.toggleInput(
|
||||||
|
this.selectedFeatureFlags,
|
||||||
|
e.target.value
|
||||||
|
);
|
||||||
|
},
|
||||||
|
toggleInput(selected, current) {
|
||||||
|
if (selected.includes(current)) {
|
||||||
|
const newSelectedFlags = selected.filter(flag => flag !== current);
|
||||||
|
return newSelectedFlags;
|
||||||
|
}
|
||||||
|
return [...selected, current];
|
||||||
|
},
|
||||||
|
onTabChange(selectedTabIndex) {
|
||||||
|
this.selectedTabIndex = selectedTabIndex;
|
||||||
},
|
},
|
||||||
fetchInboxSettings() {
|
fetchInboxSettings() {
|
||||||
|
this.selectedTabIndex = 0;
|
||||||
this.selectedAgents = [];
|
this.selectedAgents = [];
|
||||||
this.$store.dispatch('agents/get');
|
this.$store.dispatch('agents/get');
|
||||||
this.$store.dispatch('inboxes/get').then(() => {
|
this.$store.dispatch('inboxes/get').then(() => {
|
||||||
|
@ -283,6 +346,7 @@ export default {
|
||||||
this.channelWebsiteUrl = this.inbox.website_url;
|
this.channelWebsiteUrl = this.inbox.website_url;
|
||||||
this.channelWelcomeTitle = this.inbox.welcome_title;
|
this.channelWelcomeTitle = this.inbox.welcome_title;
|
||||||
this.channelWelcomeTagline = this.inbox.welcome_tagline;
|
this.channelWelcomeTagline = this.inbox.welcome_tagline;
|
||||||
|
this.selectedFeatureFlags = this.inbox.selected_feature_flags || [];
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
async fetchAttachedAgents() {
|
async fetchAttachedAgents() {
|
||||||
|
@ -325,6 +389,7 @@ export default {
|
||||||
website_url: this.channelWebsiteUrl,
|
website_url: this.channelWebsiteUrl,
|
||||||
welcome_title: this.channelWelcomeTitle || '',
|
welcome_title: this.channelWelcomeTitle || '',
|
||||||
welcome_tagline: this.channelWelcomeTagline || '',
|
welcome_tagline: this.channelWelcomeTagline || '',
|
||||||
|
selectedFeatureFlags: this.selectedFeatureFlags,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
if (this.avatarFile) {
|
if (this.avatarFile) {
|
||||||
|
@ -370,7 +435,16 @@ export default {
|
||||||
.page-top-bar {
|
.page-top-bar {
|
||||||
@include background-light;
|
@include background-light;
|
||||||
@include border-normal-bottom;
|
@include border-normal-bottom;
|
||||||
padding: $space-normal $space-larger;
|
padding: $space-normal $space-large 0;
|
||||||
|
|
||||||
|
.tabs {
|
||||||
|
padding: 0;
|
||||||
|
margin-bottom: -1px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.widget--feature-flag {
|
||||||
|
padding-top: var(--space-small);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -11,7 +11,15 @@ const buildInboxData = inboxParams => {
|
||||||
Object.keys(inboxProperties).forEach(key => {
|
Object.keys(inboxProperties).forEach(key => {
|
||||||
formData.append(key, inboxProperties[key]);
|
formData.append(key, inboxProperties[key]);
|
||||||
});
|
});
|
||||||
Object.keys(channel).forEach(key => {
|
const { selectedFeatureFlags = [], ...channelParams } = channel;
|
||||||
|
if (selectedFeatureFlags.length) {
|
||||||
|
selectedFeatureFlags.forEach(featureFlag => {
|
||||||
|
formData.append(`channel[selected_feature_flags][]`, featureFlag);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
formData.append('channel[selected_feature_flags][]', '');
|
||||||
|
}
|
||||||
|
Object.keys(channelParams).forEach(key => {
|
||||||
formData.append(`channel[${key}]`, channel[key]);
|
formData.append(`channel[${key}]`, channel[key]);
|
||||||
});
|
});
|
||||||
return formData;
|
return formData;
|
||||||
|
|
42
app/javascript/shared/mixins/inboxMixin.js
Normal file
42
app/javascript/shared/mixins/inboxMixin.js
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
export const INBOX_TYPES = {
|
||||||
|
WEB: 'Channel::WebWidget',
|
||||||
|
FB: 'Channel::FacebookPage',
|
||||||
|
TWITTER: 'Channel::TwitterProfile',
|
||||||
|
TWILIO: 'Channel::TwilioSms',
|
||||||
|
API: 'Channel::Api',
|
||||||
|
EMAIL: 'Channel::Email',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
computed: {
|
||||||
|
channelType() {
|
||||||
|
return this.inbox.channel_type;
|
||||||
|
},
|
||||||
|
isAPIInbox() {
|
||||||
|
return this.channelType === INBOX_TYPES.API;
|
||||||
|
},
|
||||||
|
isATwitterInbox() {
|
||||||
|
return this.channelType === INBOX_TYPES.TWITTER;
|
||||||
|
},
|
||||||
|
isAFacebookInbox() {
|
||||||
|
return this.channelType === INBOX_TYPES.FB;
|
||||||
|
},
|
||||||
|
isAWebWidgetInbox() {
|
||||||
|
return this.channelType === INBOX_TYPES.WEB;
|
||||||
|
},
|
||||||
|
isATwilioChannel() {
|
||||||
|
return this.channelType === INBOX_TYPES.TWILIO;
|
||||||
|
},
|
||||||
|
isAnEmailChannel() {
|
||||||
|
return this.channelType === INBOX_TYPES.EMAIL;
|
||||||
|
},
|
||||||
|
isATwilioSMSChannel() {
|
||||||
|
const { phone_number: phoneNumber = '' } = this.inbox;
|
||||||
|
return this.isATwilioChannel && !phoneNumber.startsWith('whatsapp');
|
||||||
|
},
|
||||||
|
isATwilioWhatsappChannel() {
|
||||||
|
const { phone_number: phoneNumber = '' } = this.inbox;
|
||||||
|
return this.isATwilioChannel && phoneNumber.startsWith('whatsapp');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
114
app/javascript/shared/mixins/specs/inboxMixin.spec.js
Normal file
114
app/javascript/shared/mixins/specs/inboxMixin.spec.js
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
import { shallowMount } from '@vue/test-utils';
|
||||||
|
import inboxMixin from '../inboxMixin';
|
||||||
|
|
||||||
|
describe('inboxMixin', () => {
|
||||||
|
it('returns the correct channel type', () => {
|
||||||
|
const Component = {
|
||||||
|
render() {},
|
||||||
|
mixins: [inboxMixin],
|
||||||
|
data() {
|
||||||
|
return { inbox: { channel_type: 'Channel::WebWidget' } };
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const wrapper = shallowMount(Component);
|
||||||
|
expect(wrapper.vm.channelType).toBe('Channel::WebWidget');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('isAPIInbox returns true if channel type is API', () => {
|
||||||
|
const Component = {
|
||||||
|
render() {},
|
||||||
|
mixins: [inboxMixin],
|
||||||
|
data() {
|
||||||
|
return { inbox: { channel_type: 'Channel::Api' } };
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const wrapper = shallowMount(Component);
|
||||||
|
expect(wrapper.vm.isAPIInbox).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('isATwitterInbox returns true if channel type is twitter', () => {
|
||||||
|
const Component = {
|
||||||
|
render() {},
|
||||||
|
mixins: [inboxMixin],
|
||||||
|
data() {
|
||||||
|
return { inbox: { channel_type: 'Channel::TwitterProfile' } };
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const wrapper = shallowMount(Component);
|
||||||
|
expect(wrapper.vm.isATwitterInbox).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('isAFacebookInbox returns true if channel type is Facebook', () => {
|
||||||
|
const Component = {
|
||||||
|
render() {},
|
||||||
|
mixins: [inboxMixin],
|
||||||
|
data() {
|
||||||
|
return { inbox: { channel_type: 'Channel::FacebookPage' } };
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const wrapper = shallowMount(Component);
|
||||||
|
expect(wrapper.vm.isAFacebookInbox).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('isAWebWidgetInbox returns true if channel type is Facebook', () => {
|
||||||
|
const Component = {
|
||||||
|
render() {},
|
||||||
|
mixins: [inboxMixin],
|
||||||
|
data() {
|
||||||
|
return { inbox: { channel_type: 'Channel::WebWidget' } };
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const wrapper = shallowMount(Component);
|
||||||
|
expect(wrapper.vm.isAWebWidgetInbox).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('isATwilioChannel returns true if channel type is Twilio', () => {
|
||||||
|
const Component = {
|
||||||
|
render() {},
|
||||||
|
mixins: [inboxMixin],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
inbox: {
|
||||||
|
channel_type: 'Channel::TwilioSms',
|
||||||
|
phone_number: '+91944444444',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const wrapper = shallowMount(Component);
|
||||||
|
expect(wrapper.vm.isATwilioChannel).toBe(true);
|
||||||
|
expect(wrapper.vm.isATwilioSMSChannel).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('isATwilioWhatsappChannel returns true if channel type is Twilio and phonenumber is a whatsapp number', () => {
|
||||||
|
const Component = {
|
||||||
|
render() {},
|
||||||
|
mixins: [inboxMixin],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
inbox: {
|
||||||
|
channel_type: 'Channel::TwilioSms',
|
||||||
|
phone_number: 'whatsapp:+91944444444',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const wrapper = shallowMount(Component);
|
||||||
|
expect(wrapper.vm.isATwilioChannel).toBe(true);
|
||||||
|
expect(wrapper.vm.isATwilioWhatsappChannel).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('isAnEmailChannel returns true if channel type is email', () => {
|
||||||
|
const Component = {
|
||||||
|
render() {},
|
||||||
|
mixins: [inboxMixin],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
inbox: { channel_type: 'Channel::Email' },
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const wrapper = shallowMount(Component);
|
||||||
|
expect(wrapper.vm.isAnEmailChannel).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
|
@ -18,6 +18,7 @@
|
||||||
:on-click="emojiOnClick"
|
:on-click="emojiOnClick"
|
||||||
/>
|
/>
|
||||||
<i
|
<i
|
||||||
|
v-if="hasEmojiPickerEnabled"
|
||||||
class="emoji-toggle icon ion-happy-outline"
|
class="emoji-toggle icon ion-happy-outline"
|
||||||
:class="{ active: showEmojiPicker }"
|
:class="{ active: showEmojiPicker }"
|
||||||
@click="toggleEmojiPicker()"
|
@click="toggleEmojiPicker()"
|
||||||
|
@ -39,6 +40,7 @@ import ChatSendButton from 'widget/components/ChatSendButton.vue';
|
||||||
import ChatAttachmentButton from 'widget/components/ChatAttachment.vue';
|
import ChatAttachmentButton from 'widget/components/ChatAttachment.vue';
|
||||||
import ResizableTextArea from 'shared/components/ResizableTextArea';
|
import ResizableTextArea from 'shared/components/ResizableTextArea';
|
||||||
import EmojiInput from 'dashboard/components/widgets/emoji/EmojiInput';
|
import EmojiInput from 'dashboard/components/widgets/emoji/EmojiInput';
|
||||||
|
import configMixin from '../mixins/configMixin';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ChatInputWrap',
|
name: 'ChatInputWrap',
|
||||||
|
@ -48,7 +50,7 @@ export default {
|
||||||
EmojiInput,
|
EmojiInput,
|
||||||
ResizableTextArea,
|
ResizableTextArea,
|
||||||
},
|
},
|
||||||
mixins: [clickaway],
|
mixins: [clickaway, configMixin],
|
||||||
props: {
|
props: {
|
||||||
onSendMessage: {
|
onSendMessage: {
|
||||||
type: Function,
|
type: Function,
|
||||||
|
@ -72,7 +74,7 @@ export default {
|
||||||
widgetColor: 'appConfig/getWidgetColor',
|
widgetColor: 'appConfig/getWidgetColor',
|
||||||
}),
|
}),
|
||||||
showAttachment() {
|
showAttachment() {
|
||||||
return this.userInput.length === 0;
|
return this.hasAttachmentsEnabled && this.userInput.length === 0;
|
||||||
},
|
},
|
||||||
showSendButton() {
|
showSendButton() {
|
||||||
return this.userInput.length > 0;
|
return this.userInput.length > 0;
|
||||||
|
|
|
@ -15,5 +15,11 @@ export default {
|
||||||
channelConfig() {
|
channelConfig() {
|
||||||
return window.chatwootWebChannel;
|
return window.chatwootWebChannel;
|
||||||
},
|
},
|
||||||
|
hasEmojiPickerEnabled() {
|
||||||
|
return this.channelConfig.enabledFeatures.includes('emoji_picker');
|
||||||
|
},
|
||||||
|
hasAttachmentsEnabled() {
|
||||||
|
return this.channelConfig.enabledFeatures.includes('attachments');
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,6 +6,7 @@ global.chatwootWebChannel = {
|
||||||
hideInputForBotConversations: true,
|
hideInputForBotConversations: true,
|
||||||
avatarUrl: 'https://test.url',
|
avatarUrl: 'https://test.url',
|
||||||
hasAConnectedAgentBot: 'AgentBot',
|
hasAConnectedAgentBot: 'AgentBot',
|
||||||
|
enabledFeatures: ['emoji_picker', 'attachments'],
|
||||||
};
|
};
|
||||||
|
|
||||||
global.chatwootWidgetDefaults = {
|
global.chatwootWidgetDefaults = {
|
||||||
|
@ -22,6 +23,8 @@ describe('configMixin', () => {
|
||||||
const Constructor = Vue.extend(Component);
|
const Constructor = Vue.extend(Component);
|
||||||
const vm = new Constructor().$mount();
|
const vm = new Constructor().$mount();
|
||||||
const wrapper = createWrapper(vm);
|
const wrapper = createWrapper(vm);
|
||||||
|
expect(wrapper.vm.hasEmojiPickerEnabled).toBe(true);
|
||||||
|
expect(wrapper.vm.hasAttachmentsEnabled).toBe(true);
|
||||||
expect(wrapper.vm.hideInputForBotConversations).toBe(true);
|
expect(wrapper.vm.hideInputForBotConversations).toBe(true);
|
||||||
expect(wrapper.vm.hasAConnectedAgentBot).toBe(true);
|
expect(wrapper.vm.hasAConnectedAgentBot).toBe(true);
|
||||||
expect(wrapper.vm.useInboxAvatarForBot).toBe(true);
|
expect(wrapper.vm.useInboxAvatarForBot).toBe(true);
|
||||||
|
@ -30,6 +33,7 @@ describe('configMixin', () => {
|
||||||
hideInputForBotConversations: true,
|
hideInputForBotConversations: true,
|
||||||
avatarUrl: 'https://test.url',
|
avatarUrl: 'https://test.url',
|
||||||
hasAConnectedAgentBot: 'AgentBot',
|
hasAConnectedAgentBot: 'AgentBot',
|
||||||
|
enabledFeatures: ['emoji_picker', 'attachments'],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
# Table name: channel_web_widgets
|
# Table name: channel_web_widgets
|
||||||
#
|
#
|
||||||
# id :integer not null, primary key
|
# id :integer not null, primary key
|
||||||
|
# feature_flags :integer default(3), not null
|
||||||
# website_token :string
|
# website_token :string
|
||||||
# website_url :string
|
# website_url :string
|
||||||
# welcome_tagline :string
|
# welcome_tagline :string
|
||||||
|
@ -18,6 +19,8 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
class Channel::WebWidget < ApplicationRecord
|
class Channel::WebWidget < ApplicationRecord
|
||||||
|
include FlagShihTzu
|
||||||
|
|
||||||
self.table_name = 'channel_web_widgets'
|
self.table_name = 'channel_web_widgets'
|
||||||
|
|
||||||
validates :website_url, presence: true
|
validates :website_url, presence: true
|
||||||
|
@ -26,6 +29,9 @@ class Channel::WebWidget < ApplicationRecord
|
||||||
belongs_to :account
|
belongs_to :account
|
||||||
has_one :inbox, as: :channel, dependent: :destroy
|
has_one :inbox, as: :channel, dependent: :destroy
|
||||||
has_secure_token :website_token
|
has_secure_token :website_token
|
||||||
|
has_flags 1 => :attachments,
|
||||||
|
2 => :emoji_picker,
|
||||||
|
:column => 'feature_flags'
|
||||||
|
|
||||||
def has_24_hour_messaging_window?
|
def has_24_hour_messaging_window?
|
||||||
false
|
false
|
||||||
|
|
|
@ -46,6 +46,8 @@ class Inbox < ApplicationRecord
|
||||||
|
|
||||||
after_destroy :delete_round_robin_agents
|
after_destroy :delete_round_robin_agents
|
||||||
|
|
||||||
|
scope :order_by_id, -> { order(id: :asc) }
|
||||||
|
|
||||||
def add_member(user_id)
|
def add_member(user_id)
|
||||||
member = inbox_members.new(user_id: user_id)
|
member = inbox_members.new(user_id: user_id)
|
||||||
member.save!
|
member.save!
|
||||||
|
|
|
@ -14,3 +14,4 @@ json.enable_auto_assignment resource.enable_auto_assignment
|
||||||
json.web_widget_script resource.channel.try(:web_widget_script)
|
json.web_widget_script resource.channel.try(:web_widget_script)
|
||||||
json.forward_to_address resource.channel.try(:forward_to_address)
|
json.forward_to_address resource.channel.try(:forward_to_address)
|
||||||
json.phone_number resource.channel.try(:phone_number)
|
json.phone_number resource.channel.try(:phone_number)
|
||||||
|
json.selected_feature_flags resource.channel.try(:selected_feature_flags)
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
welcomeTagline: '<%= @web_widget.welcome_tagline %>',
|
welcomeTagline: '<%= @web_widget.welcome_tagline %>',
|
||||||
welcomeTitle: '<%= @web_widget.welcome_title %>',
|
welcomeTitle: '<%= @web_widget.welcome_title %>',
|
||||||
widgetColor: '<%= @web_widget.widget_color %>',
|
widgetColor: '<%= @web_widget.widget_color %>',
|
||||||
|
enabledFeatures: <%= @web_widget.selected_feature_flags.to_json.html_safe %>,
|
||||||
enabledLanguages: <%= available_locales_with_name.to_json.html_safe %>,
|
enabledLanguages: <%= available_locales_with_name.to_json.html_safe %>,
|
||||||
}
|
}
|
||||||
window.chatwootWidgetDefaults = {
|
window.chatwootWidgetDefaults = {
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
class AddFeatureSettingToWebsiteInbox < ActiveRecord::Migration[6.0]
|
||||||
|
def change
|
||||||
|
add_column :channel_web_widgets, :feature_flags, :integer, default: 3, null: false
|
||||||
|
end
|
||||||
|
end
|
|
@ -178,6 +178,7 @@ ActiveRecord::Schema.define(version: 2020_08_02_170002) do
|
||||||
t.string "widget_color", default: "#1f93ff"
|
t.string "widget_color", default: "#1f93ff"
|
||||||
t.string "welcome_title"
|
t.string "welcome_title"
|
||||||
t.string "welcome_tagline"
|
t.string "welcome_tagline"
|
||||||
|
t.integer "feature_flags", default: 3, null: false
|
||||||
t.index ["website_token"], name: "index_channel_web_widgets_on_website_token", unique: true
|
t.index ["website_token"], name: "index_channel_web_widgets_on_website_token", unique: true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue