9
app/javascript/dashboard/api/channel/twilioChannel.js
Normal file
9
app/javascript/dashboard/api/channel/twilioChannel.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import ApiClient from '../ApiClient';
|
||||
|
||||
class TwilioChannel extends ApiClient {
|
||||
constructor() {
|
||||
super('channels/twilio_channel', { accountScoped: true });
|
||||
}
|
||||
}
|
||||
|
||||
export default new TwilioChannel();
|
||||
BIN
app/javascript/dashboard/assets/images/channels/twilio.png
Normal file
BIN
app/javascript/dashboard/assets/images/channels/twilio.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
@@ -56,6 +56,7 @@ const INBOX_TYPES = {
|
||||
WEB: 'Channel::WebWidget',
|
||||
FB: 'Channel::FacebookPage',
|
||||
TWITTER: 'Channel::TwitterProfile',
|
||||
TWILIO: 'Channel::TwilioSms',
|
||||
};
|
||||
const getInboxClassByType = type => {
|
||||
switch (type) {
|
||||
@@ -68,6 +69,9 @@ const getInboxClassByType = type => {
|
||||
case INBOX_TYPES.TWITTER:
|
||||
return 'ion-social-twitter';
|
||||
|
||||
case INBOX_TYPES.TWILIO:
|
||||
return 'ion-android-textsms';
|
||||
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -24,6 +24,10 @@
|
||||
v-if="channel === 'website'"
|
||||
src="~dashboard/assets/images/channels/website.png"
|
||||
/>
|
||||
<img
|
||||
v-if="channel === 'twilio'"
|
||||
src="~dashboard/assets/images/channels/twilio.png"
|
||||
/>
|
||||
<h3 class="channel__title">
|
||||
{{ channel }}
|
||||
</h3>
|
||||
@@ -39,7 +43,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
isActive(channel) {
|
||||
return ['facebook', 'website', 'twitter'].includes(channel);
|
||||
return ['facebook', 'website', 'twitter', 'twilio'].includes(channel);
|
||||
},
|
||||
onItemClick() {
|
||||
if (this.isActive(this.channel)) {
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
"WEBSITE_CHANNEL": {
|
||||
"TITLE": "Website channel",
|
||||
"DESC": "Create a channel for your website and start supporting your customers via our website widget.",
|
||||
"LOADING_MESSAGE": "Creating Website Support Channel",
|
||||
"CHANNEL_NAME": {
|
||||
"LABEL": "Website Name",
|
||||
"PLACEHOLDER": "Enter your website name (eg: Acme Inc)"
|
||||
@@ -35,6 +36,34 @@
|
||||
},
|
||||
"SUBMIT_BUTTON":"Create inbox"
|
||||
},
|
||||
"TWILIO": {
|
||||
"TITLE": "Twilio SMS Channel",
|
||||
"DESC": "Integrate Twilio and start supporting your customers via SMS.",
|
||||
"ACCOUNT_SID": {
|
||||
"LABEL": "Account SID",
|
||||
"PLACEHOLDER": "Please enter your Twilio Account SID",
|
||||
"ERROR": "This field is required"
|
||||
},
|
||||
"AUTH_TOKEN": {
|
||||
"LABEL": "Auth Token",
|
||||
"PLACEHOLDER": "Please enter your Twilio Auth Token",
|
||||
"ERROR": "This field is required"
|
||||
},
|
||||
"CHANNEL_NAME": {
|
||||
"LABEL": "Channel Name",
|
||||
"PLACEHOLDER": "Please enter a channel name",
|
||||
"ERROR": "This field is required"
|
||||
},
|
||||
"PHONE_NUMBER": {
|
||||
"LABEL": "Phone number",
|
||||
"PLACEHOLDER": "Please enter the phone number from which message will be sent.",
|
||||
"ERROR": "Please enter a valid value. Phone number should start with `+` sign."
|
||||
},
|
||||
"SUBMIT_BUTTON": "Create Twilio Channel",
|
||||
"API": {
|
||||
"ERROR_MESSAGE": "We were not able to authenticate Twilio credentials, please try again"
|
||||
}
|
||||
},
|
||||
"AUTH": {
|
||||
"TITLE": "Channels",
|
||||
"DESC": "Currently we support Website live chat widgets, Facebook Pages and Twitter profiles as platforms. We have more platforms like Whatsapp, Email, Telegram and Line in the works, which will be out soon."
|
||||
|
||||
@@ -128,11 +128,11 @@ export default {
|
||||
this.showAlert(this.$t('AGENT_MGMT.ADD.API.SUCCESS_MESSAGE'));
|
||||
this.onClose();
|
||||
} catch (error) {
|
||||
if (error.response.status === 422) {
|
||||
this.showAlert(this.$t('AGENT_MGMT.ADD.API.EXIST_MESSAGE'));
|
||||
} else {
|
||||
this.showAlert(this.$t('AGENT_MGMT.ADD.API.ERROR_MESSAGE'));
|
||||
}
|
||||
if (error.response.status === 422) {
|
||||
this.showAlert(this.$t('AGENT_MGMT.ADD.API.EXIST_MESSAGE'));
|
||||
} else {
|
||||
this.showAlert(this.$t('AGENT_MGMT.ADD.API.ERROR_MESSAGE'));
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -27,7 +27,14 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
channelList: ['website', 'facebook', 'twitter', 'telegram', 'line'],
|
||||
channelList: [
|
||||
'website',
|
||||
'facebook',
|
||||
'twitter',
|
||||
'twilio',
|
||||
'telegram',
|
||||
'line',
|
||||
],
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
|
||||
@@ -28,12 +28,14 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import configMixin from 'shared/mixins/configMixin';
|
||||
import EmptyState from '../../../../components/widgets/EmptyState';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
EmptyState,
|
||||
},
|
||||
mixins: [configMixin],
|
||||
computed: {
|
||||
currentInbox() {
|
||||
return this.$store.getters['inboxes/getInbox'](
|
||||
|
||||
@@ -42,6 +42,9 @@
|
||||
<span v-if="item.channel_type === 'Channel::TwitterProfile'">
|
||||
Twitter
|
||||
</span>
|
||||
<span v-if="item.channel_type === 'Channel::TwilioSms'">
|
||||
Twilio SMS
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="settings columns container">
|
||||
<woot-modal-header
|
||||
:header-image="inbox.avatarUrl"
|
||||
:header-title="inbox.name"
|
||||
:header-title="inboxName"
|
||||
/>
|
||||
<div
|
||||
v-if="inbox.channel_type === 'Channel::FacebookPage'"
|
||||
@@ -87,6 +87,7 @@
|
||||
import { mapGetters } from 'vuex';
|
||||
import { createMessengerScript } from 'dashboard/helper/scriptGenerator';
|
||||
import { Compact } from 'vue-color';
|
||||
import configMixin from 'shared/mixins/configMixin';
|
||||
import SettingsFormHeader from '../../../../components/SettingsFormHeader.vue';
|
||||
|
||||
export default {
|
||||
@@ -94,6 +95,7 @@ export default {
|
||||
Compact,
|
||||
SettingsFormHeader,
|
||||
},
|
||||
mixins: [configMixin],
|
||||
data() {
|
||||
return {
|
||||
selectedAgents: [],
|
||||
@@ -113,6 +115,12 @@ export default {
|
||||
inbox() {
|
||||
return this.$store.getters['inboxes/getInbox'](this.currentInboxId);
|
||||
},
|
||||
inboxName() {
|
||||
if (this.inbox.channel_type === 'Channel::TwilioSms') {
|
||||
return `${this.inbox.name} (${this.inbox.phone_number})`;
|
||||
}
|
||||
return this.inbox.name;
|
||||
},
|
||||
messengerScript() {
|
||||
return createMessengerScript(this.inbox.page_id);
|
||||
},
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import Facebook from './channels/Facebook';
|
||||
import Website from './channels/Website';
|
||||
import Twitter from './channels/Twitter';
|
||||
import Twilio from './channels/Twilio';
|
||||
|
||||
const channelViewList = {
|
||||
facebook: Facebook,
|
||||
website: Website,
|
||||
twitter: Twitter,
|
||||
twilio: Twilio,
|
||||
};
|
||||
|
||||
export default {
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
<template>
|
||||
<div class="wizard-body small-9 columns">
|
||||
<page-header
|
||||
:header-title="$t('INBOX_MGMT.ADD.TWILIO.TITLE')"
|
||||
:header-content="$t('INBOX_MGMT.ADD.TWILIO.DESC')"
|
||||
/>
|
||||
<form class="row" @submit.prevent="createChannel()">
|
||||
<div class="medium-8 columns">
|
||||
<label :class="{ error: $v.channelName.$error }">
|
||||
{{ $t('INBOX_MGMT.ADD.TWILIO.CHANNEL_NAME.LABEL') }}
|
||||
<input
|
||||
v-model.trim="channelName"
|
||||
type="text"
|
||||
:placeholder="$t('INBOX_MGMT.ADD.TWILIO.CHANNEL_NAME.PLACEHOLDER')"
|
||||
@blur="$v.channelName.$touch"
|
||||
/>
|
||||
<span v-if="$v.channelName.$error" class="message">
|
||||
{{ $t('INBOX_MGMT.ADD.TWILIO.CHANNEL_NAME.ERROR') }}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="medium-8 columns">
|
||||
<label :class="{ error: $v.phoneNumber.$error }">
|
||||
{{ $t('INBOX_MGMT.ADD.TWILIO.PHONE_NUMBER.LABEL') }}
|
||||
<input
|
||||
v-model.trim="phoneNumber"
|
||||
type="text"
|
||||
:placeholder="$t('INBOX_MGMT.ADD.TWILIO.PHONE_NUMBER.PLACEHOLDER')"
|
||||
@blur="$v.phoneNumber.$touch"
|
||||
/>
|
||||
<span v-if="$v.phoneNumber.$error" class="message">
|
||||
{{ $t('INBOX_MGMT.ADD.TWILIO.PHONE_NUMBER.ERROR') }}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="medium-8 columns">
|
||||
<label :class="{ error: $v.accountSID.$error }">
|
||||
{{ $t('INBOX_MGMT.ADD.TWILIO.ACCOUNT_SID.LABEL') }}
|
||||
<input
|
||||
v-model.trim="accountSID"
|
||||
type="text"
|
||||
:placeholder="$t('INBOX_MGMT.ADD.TWILIO.ACCOUNT_SID.PLACEHOLDER')"
|
||||
@blur="$v.accountSID.$touch"
|
||||
/>
|
||||
<span v-if="$v.accountSID.$error" class="message">
|
||||
{{ $t('INBOX_MGMT.ADD.TWILIO.ACCOUNT_SID.ERROR') }}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="medium-8 columns">
|
||||
<label :class="{ error: $v.authToken.$error }">
|
||||
{{ $t('INBOX_MGMT.ADD.TWILIO.AUTH_TOKEN.LABEL') }}
|
||||
<input
|
||||
v-model.trim="authToken"
|
||||
type="text"
|
||||
:placeholder="$t('INBOX_MGMT.ADD.TWILIO.AUTH_TOKEN.PLACEHOLDER')"
|
||||
@blur="$v.authToken.$touch"
|
||||
/>
|
||||
<span v-if="$v.authToken.$error" class="message">
|
||||
{{ $t('INBOX_MGMT.ADD.TWILIO.AUTH_TOKEN.ERROR') }}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="medium-12 columns">
|
||||
<woot-submit-button
|
||||
:loading="uiFlags.isCreating"
|
||||
:button-text="$t('INBOX_MGMT.ADD.TWILIO.SUBMIT_BUTTON')"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import alertMixin from 'shared/mixins/alertMixin';
|
||||
import { required } from 'vuelidate/lib/validators';
|
||||
import router from '../../../../index';
|
||||
import PageHeader from '../../SettingsSubPageHeader';
|
||||
|
||||
const shouldStartWithPlusSign = (value = '') => value.startsWith('+');
|
||||
|
||||
export default {
|
||||
components: {
|
||||
PageHeader,
|
||||
},
|
||||
mixins: [alertMixin],
|
||||
data() {
|
||||
return {
|
||||
accountSID: '',
|
||||
authToken: '',
|
||||
channelName: '',
|
||||
phoneNumber: '',
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
uiFlags: 'inboxes/getUIFlags',
|
||||
}),
|
||||
},
|
||||
validations: {
|
||||
channelName: { required },
|
||||
phoneNumber: { required, shouldStartWithPlusSign },
|
||||
authToken: { required },
|
||||
accountSID: { required },
|
||||
},
|
||||
methods: {
|
||||
async createChannel() {
|
||||
this.$v.$touch();
|
||||
if (this.$v.$invalid) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const twilioChannel = await this.$store.dispatch(
|
||||
'inboxes/createTwilioChannel',
|
||||
{
|
||||
twilio_channel: {
|
||||
name: this.channelName,
|
||||
account_sid: this.accountSID,
|
||||
auth_token: this.authToken,
|
||||
phone_number: this.phoneNumber,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
router.replace({
|
||||
name: 'settings_inboxes_add_agents',
|
||||
params: {
|
||||
page: 'new',
|
||||
inbox_id: twilioChannel.id,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
this.showAlert(this.$t('INBOX_MGMT.ADD.TWILIO.API.ERROR_MESSAGE'));
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -5,11 +5,15 @@
|
||||
:header-content="$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.DESC')"
|
||||
/>
|
||||
<woot-loading-state
|
||||
v-if="isCreating"
|
||||
message="Creating Website Support Channel"
|
||||
v-if="uiFlags.isCreating"
|
||||
:message="$('INBOX_MGMT.ADD.WEBSITE_CHANNEL.LOADING_MESSAGE')"
|
||||
>
|
||||
</woot-loading-state>
|
||||
<form v-if="!isCreating" class="row" @submit.prevent="createChannel()">
|
||||
<form
|
||||
v-if="!uiFlags.isCreating"
|
||||
class="row"
|
||||
@submit.prevent="createChannel()"
|
||||
>
|
||||
<div class="medium-12 columns">
|
||||
<label>
|
||||
{{ $t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.CHANNEL_NAME.LABEL') }}
|
||||
@@ -45,6 +49,7 @@
|
||||
<div class="modal-footer">
|
||||
<div class="medium-12 columns">
|
||||
<woot-submit-button
|
||||
:loading="uiFlags.isCreating"
|
||||
:disabled="!websiteUrl || !websiteName"
|
||||
:button-text="$t('INBOX_MGMT.ADD.WEBSITE_CHANNEL.SUBMIT_BUTTON')"
|
||||
/>
|
||||
@@ -70,7 +75,6 @@ export default {
|
||||
websiteName: '',
|
||||
websiteUrl: '',
|
||||
widgetColor: { hex: '#009CE0' },
|
||||
isCreating: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
||||
@@ -3,6 +3,7 @@ import * as types from '../mutation-types';
|
||||
import InboxesAPI from '../../api/inboxes';
|
||||
import WebChannel from '../../api/channel/webChannel';
|
||||
import FBChannel from '../../api/channel/fbChannel';
|
||||
import TwilioChannel from '../../api/channel/twilioChannel';
|
||||
|
||||
export const state = {
|
||||
records: [],
|
||||
@@ -54,6 +55,18 @@ export const actions = {
|
||||
throw new Error(error);
|
||||
}
|
||||
},
|
||||
createTwilioChannel: async ({ commit }, params) => {
|
||||
try {
|
||||
commit(types.default.SET_INBOXES_UI_FLAG, { isCreating: true });
|
||||
const response = await TwilioChannel.create(params);
|
||||
commit(types.default.ADD_INBOXES, response.data);
|
||||
commit(types.default.SET_INBOXES_UI_FLAG, { isCreating: false });
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
commit(types.default.SET_INBOXES_UI_FLAG, { isCreating: false });
|
||||
throw new Error(error);
|
||||
}
|
||||
},
|
||||
createFBChannel: async ({ commit }, params) => {
|
||||
try {
|
||||
commit(types.default.SET_INBOXES_UI_FLAG, { isCreating: true });
|
||||
|
||||
Reference in New Issue
Block a user