Feature: API Channel (#1052)

This commit is contained in:
Sojan Jose
2020-07-21 12:15:24 +05:30
committed by GitHub
parent fa04098c20
commit 8079bf50a0
40 changed files with 735 additions and 246 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

@@ -63,6 +63,8 @@ const INBOX_TYPES = {
FB: 'Channel::FacebookPage',
TWITTER: 'Channel::TwitterProfile',
TWILIO: 'Channel::TwilioSms',
API: 'Channel::Api',
EMAIL: 'Channel::Email',
};
const getInboxClassByType = type => {
switch (type) {
@@ -78,6 +80,12 @@ const getInboxClassByType = type => {
case INBOX_TYPES.TWILIO:
return 'ion-android-textsms';
case INBOX_TYPES.API:
return 'ion-cloud';
case INBOX_TYPES.EMAIL:
return 'ion-email';
default:
return '';
}

View File

@@ -16,6 +16,14 @@
v-if="channel === 'telegram'"
src="~dashboard/assets/images/channels/telegram.png"
/>
<img
v-if="channel === 'api'"
src="~dashboard/assets/images/channels/api.png"
/>
<img
v-if="channel === 'email'"
src="~dashboard/assets/images/channels/email.png"
/>
<img
v-if="channel === 'line'"
src="~dashboard/assets/images/channels/line.png"
@@ -56,7 +64,10 @@ export default {
if (channel === 'twitter') {
return this.enabledFeatures.channel_twitter;
}
return ['website', 'twilio'].includes(channel);
if (channel === 'email') {
return this.enabledFeatures.channel_email;
}
return ['website', 'twilio', 'api'].includes(channel);
},
onItemClick() {
if (this.isActive(this.channel)) {

View File

@@ -115,6 +115,43 @@
"ERROR_MESSAGE": "We were not able to authenticate Twilio credentials, please try again"
}
},
"API_CHANNEL": {
"TITLE": "API Channel",
"DESC": "Integrate with API channel and start supporting your customers via chatwoot.",
"CHANNEL_NAME": {
"LABEL": "Channel Name",
"PLACEHOLDER": "Please enter a channel name",
"ERROR": "This field is required"
},
"WEBHOOK_URL": {
"LABEL": "Webhook Url",
"SUBTITLE": "Configure the url where you want to recieve callbacks from chatwoot on events.",
"PLACEHOLDER": "Webhook Url"
},
"SUBMIT_BUTTON": "Create API Channel",
"API": {
"ERROR_MESSAGE": "We were not able to save the api channel"
}
},
"EMAIL_CHANNEL": {
"TITLE": "Email Channel",
"DESC": "Integrate you email inbox with chatwoot.",
"CHANNEL_NAME": {
"LABEL": "Channel Name",
"PLACEHOLDER": "Please enter a channel name",
"ERROR": "This field is required"
},
"EMAIL": {
"LABEL": "Email",
"SUBTITLE": "Email where your customers sends you support tickets",
"PLACEHOLDER": "Email"
},
"SUBMIT_BUTTON": "Create Email Channel",
"API": {
"ERROR_MESSAGE": "We were not able to save the email channel"
},
"FINISH_MESSAGE" : "Start forwarding your emails to the following email address."
},
"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."

View File

@@ -34,6 +34,8 @@ export default {
'facebook',
'twitter',
'twilio',
'email',
'api',
'telegram',
'line',
],

View File

@@ -21,6 +21,14 @@
>
</woot-code>
</div>
<div class="medium-6 small-offset-3">
<woot-code
v-if="isAEmailInbox"
lang="html"
:script="currentInbox.forward_to_address"
>
</woot-code>
</div>
<router-link
class="button success nice"
:to="{
@@ -53,6 +61,9 @@ export default {
isATwilioInbox() {
return this.currentInbox.channel_type === 'Channel::TwilioSms';
},
isAEmailInbox() {
return this.currentInbox.channel_type === 'Channel::Email';
},
message() {
if (this.isATwilioInbox) {
return `${this.$t('INBOX_MGMT.FINISH.MESSAGE')}. ${this.$t(
@@ -60,6 +71,10 @@ export default {
)}`;
}
if (this.isAEmailInbox) {
return this.$t('INBOX_MGMT.ADD.EMAIL_CHANNEL.FINISH_MESSAGE');
}
if (!this.currentInbox.website_token) {
return this.$t('INBOX_MGMT.FINISH.MESSAGE');
}

View File

@@ -45,6 +45,12 @@
<span v-if="item.channel_type === 'Channel::TwilioSms'">
Twilio SMS
</span>
<span v-if="item.channel_type === 'Channel::Email'">
Email
</span>
<span v-if="item.channel_type === 'Channel::Api'">
Api
</span>
</td>
<!-- Action Buttons -->

View File

@@ -2,12 +2,16 @@ import Facebook from './channels/Facebook';
import Website from './channels/Website';
import Twitter from './channels/Twitter';
import Twilio from './channels/Twilio';
import Api from './channels/Api';
import Email from './channels/Email';
const channelViewList = {
facebook: Facebook,
website: Website,
twitter: Twitter,
twilio: Twilio,
api: Api,
email: Email,
};
export default {

View File

@@ -0,0 +1,110 @@
<template>
<div class="wizard-body small-9 columns">
<page-header
:header-title="$t('INBOX_MGMT.ADD.API_CHANNEL.TITLE')"
:header-content="$t('INBOX_MGMT.ADD.API_CHANNEL.DESC')"
/>
<form class="row" @submit.prevent="createChannel()">
<div class="medium-8 columns">
<label :class="{ error: $v.channelName.$error }">
{{ $t('INBOX_MGMT.ADD.API_CHANNEL.CHANNEL_NAME.LABEL') }}
<input
v-model.trim="channelName"
type="text"
:placeholder="
$t('INBOX_MGMT.ADD.API_CHANNEL.CHANNEL_NAME.PLACEHOLDER')
"
@blur="$v.channelName.$touch"
/>
<span v-if="$v.channelName.$error" class="message">{{
$t('INBOX_MGMT.ADD.API_CHANNEL.CHANNEL_NAME.ERROR')
}}</span>
</label>
</div>
<div class="medium-8 columns">
<label :class="{ error: $v.webhookUrl.$error }">
{{ $t('INBOX_MGMT.ADD.API_CHANNEL.WEBHOOK_URL.LABEL') }}
<input
v-model.trim="webhookUrl"
type="text"
:placeholder="
$t('INBOX_MGMT.ADD.API_CHANNEL.WEBHOOK_URL.PLACEHOLDER')
"
@blur="$v.webhookUrl.$touch"
/>
</label>
<p class="help-text">
{{ $t('INBOX_MGMT.ADD.API_CHANNEL.WEBHOOK_URL.SUBTITLE') }}
</p>
</div>
<div class="medium-12 columns">
<woot-submit-button
:loading="uiFlags.isCreating"
:button-text="$t('INBOX_MGMT.ADD.API_CHANNEL.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 shouldBeWebhookUrl = (value = '') => value.startsWith('http');
export default {
components: {
PageHeader,
},
mixins: [alertMixin],
data() {
return {
channelName: '',
webhookUrl: '',
};
},
computed: {
...mapGetters({
uiFlags: 'inboxes/getUIFlags',
}),
},
validations: {
channelName: { required },
webhookUrl: { required, shouldBeWebhookUrl },
},
methods: {
async createChannel() {
this.$v.$touch();
if (this.$v.$invalid) {
return;
}
try {
const apiChannel = await this.$store.dispatch('inboxes/createChannel', {
name: this.channelName,
channel: {
type: 'api',
webhook_url: this.webhookUrl,
},
});
router.replace({
name: 'settings_inboxes_add_agents',
params: {
page: 'new',
inbox_id: apiChannel.id,
},
});
} catch (error) {
this.showAlert(this.$t('INBOX_MGMT.ADD.API_CHANNEL.API.ERROR_MESSAGE'));
}
},
},
};
</script>

View File

@@ -0,0 +1,113 @@
<template>
<div class="wizard-body small-9 columns">
<page-header
:header-title="$t('INBOX_MGMT.ADD.EMAIL_CHANNEL.TITLE')"
:header-content="$t('INBOX_MGMT.ADD.EMAIL_CHANNEL.DESC')"
/>
<form class="row" @submit.prevent="createChannel()">
<div class="medium-8 columns">
<label :class="{ error: $v.channelName.$error }">
{{ $t('INBOX_MGMT.ADD.EMAIL_CHANNEL.CHANNEL_NAME.LABEL') }}
<input
v-model.trim="channelName"
type="text"
:placeholder="
$t('INBOX_MGMT.ADD.EMAIL_CHANNEL.CHANNEL_NAME.PLACEHOLDER')
"
@blur="$v.channelName.$touch"
/>
<span v-if="$v.channelName.$error" class="message">{{
$t('INBOX_MGMT.ADD.EMAIL_CHANNEL.CHANNEL_NAME.ERROR')
}}</span>
</label>
</div>
<div class="medium-8 columns">
<label :class="{ error: $v.email.$error }">
{{ $t('INBOX_MGMT.ADD.EMAIL_CHANNEL.EMAIL.LABEL') }}
<input
v-model.trim="email"
type="text"
:placeholder="$t('INBOX_MGMT.ADD.EMAIL_CHANNEL.EMAIL.PLACEHOLDER')"
@blur="$v.email.$touch"
/>
</label>
<p class="help-text">
{{ $t('INBOX_MGMT.ADD.EMAIL_CHANNEL.EMAIL.SUBTITLE') }}
</p>
</div>
<div class="medium-12 columns">
<woot-submit-button
:loading="uiFlags.isCreating"
:button-text="$t('INBOX_MGMT.ADD.EMAIL_CHANNEL.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 validEmail = (value = '') => value.includes('@');
export default {
components: {
PageHeader,
},
mixins: [alertMixin],
data() {
return {
channelName: '',
email: '',
};
},
computed: {
...mapGetters({
uiFlags: 'inboxes/getUIFlags',
}),
},
validations: {
channelName: { required },
email: { required, validEmail },
},
methods: {
async createChannel() {
this.$v.$touch();
if (this.$v.$invalid) {
return;
}
try {
const emailChannel = await this.$store.dispatch(
'inboxes/createChannel',
{
name: this.channelName,
channel: {
type: 'email',
email: this.email,
},
}
);
router.replace({
name: 'settings_inboxes_add_agents',
params: {
page: 'new',
inbox_id: emailChannel.id,
},
});
} catch (error) {
this.showAlert(
this.$t('INBOX_MGMT.ADD.EMAIL_CHANNEL.API.ERROR_MESSAGE')
);
}
},
},
};
</script>

View File

@@ -55,6 +55,18 @@ export const actions = {
commit(types.default.SET_INBOXES_UI_FLAG, { isFetching: false });
}
},
createChannel: async ({ commit }, params) => {
try {
commit(types.default.SET_INBOXES_UI_FLAG, { isCreating: true });
const response = await WebChannel.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);
}
},
createWebsiteChannel: async ({ commit }, params) => {
try {
commit(types.default.SET_INBOXES_UI_FLAG, { isCreating: true });