feat: Add campaign (#2177)
This commit is contained in:
parent
eaa61c3745
commit
7c7f91e70f
13 changed files with 792 additions and 19 deletions
9
app/javascript/dashboard/api/campaigns.js
Normal file
9
app/javascript/dashboard/api/campaigns.js
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import ApiClient from './ApiClient';
|
||||||
|
|
||||||
|
class CampaignsAPI extends ApiClient {
|
||||||
|
constructor() {
|
||||||
|
super('campaigns', { accountScoped: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default new CampaignsAPI();
|
|
@ -1,9 +1,49 @@
|
||||||
{
|
{
|
||||||
"CAMPAIGN": {
|
"CAMPAIGN": {
|
||||||
"HEADER": "Campaigns",
|
"HEADER": "Campaigns",
|
||||||
"HEADER_BTN_TXT": "Create Campaign",
|
"SIDEBAR_TXT": "Proactive messages allow the customer to send outbound messages to their contacts which would trigger more conversations. Click on <b>Add Campaign</b> to create a new campaign. You can also edit or delete an existing campaign by clicking on the Edit or Delete button.",
|
||||||
|
"HEADER_BTN_TXT": "Create a campaign",
|
||||||
"LIST": {
|
"LIST": {
|
||||||
"404": "There are no campaigns attached to this inbox"
|
"404": "There are no campaigns created for this inbox."
|
||||||
|
},
|
||||||
|
"ADD": {
|
||||||
|
"TITLE": "Create a campaign",
|
||||||
|
"DESC": "Proactive messages allow the customer to send outbound messages to their contacts which would trigger more conversations.",
|
||||||
|
"CANCEL_BUTTON_TEXT": "Cancel",
|
||||||
|
"CREATE_BUTTON_TEXT": "Create",
|
||||||
|
"FORM": {
|
||||||
|
"TITLE": {
|
||||||
|
"LABEL": "Title",
|
||||||
|
"PLACEHOLDER": "Please enter the title of campaign",
|
||||||
|
"ERROR": "Title is required"
|
||||||
|
},
|
||||||
|
"MESSAGE": {
|
||||||
|
"LABEL": "Message",
|
||||||
|
"PLACEHOLDER": "Please enter the message of campaign",
|
||||||
|
"ERROR": "Message is required"
|
||||||
|
},
|
||||||
|
"SENT_BY": {
|
||||||
|
"LABEL": "Sent by",
|
||||||
|
"PLACEHOLDER": "Please select the the content of campaign",
|
||||||
|
"ERROR": "Sender is required"
|
||||||
|
},
|
||||||
|
"END_POINT": {
|
||||||
|
"LABEL": "URL",
|
||||||
|
"PLACEHOLDER": "Please enter the URL",
|
||||||
|
"ERROR": "Please enter a valid URL"
|
||||||
|
},
|
||||||
|
"TIME_ON_PAGE": {
|
||||||
|
"LABEL": "Time on page(Seconds)",
|
||||||
|
"PLACEHOLDER": "Please enter the time",
|
||||||
|
"ERROR": "Time on page is required"
|
||||||
|
},
|
||||||
|
"ENABLED": "Enable campaign",
|
||||||
|
"SUBMIT": "Add Campaign"
|
||||||
|
},
|
||||||
|
"API": {
|
||||||
|
"SUCCESS_MESSAGE": "Campaign created successfully",
|
||||||
|
"ERROR_MESSAGE": "There was an error. Please try again."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -335,10 +335,10 @@ export default {
|
||||||
if (this.isAWebWidgetInbox) {
|
if (this.isAWebWidgetInbox) {
|
||||||
return [
|
return [
|
||||||
...visibleToAllChannelTabs,
|
...visibleToAllChannelTabs,
|
||||||
{
|
// {
|
||||||
key: 'campaign',
|
// key: 'campaign',
|
||||||
name: this.$t('INBOX_MGMT.TABS.CAMPAIGN'),
|
// name: this.$t('INBOX_MGMT.TABS.CAMPAIGN'),
|
||||||
},
|
// },
|
||||||
{
|
{
|
||||||
key: 'preChatForm',
|
key: 'preChatForm',
|
||||||
name: this.$t('INBOX_MGMT.TABS.PRE_CHAT_FORM'),
|
name: this.$t('INBOX_MGMT.TABS.PRE_CHAT_FORM'),
|
||||||
|
|
|
@ -0,0 +1,205 @@
|
||||||
|
<template>
|
||||||
|
<modal :show.sync="show" :on-close="onClose">
|
||||||
|
<div class="column content-box">
|
||||||
|
<woot-modal-header
|
||||||
|
:header-title="$t('CAMPAIGN.ADD.TITLE')"
|
||||||
|
:header-content="$t('CAMPAIGN.ADD.DESC')"
|
||||||
|
/>
|
||||||
|
<form class="row" @submit.prevent="addCampaign">
|
||||||
|
<div class="medium-12 columns">
|
||||||
|
<label :class="{ error: $v.title.$error }">
|
||||||
|
{{ $t('CAMPAIGN.ADD.FORM.TITLE.LABEL') }}
|
||||||
|
<input
|
||||||
|
v-model.trim="title"
|
||||||
|
type="text"
|
||||||
|
:placeholder="$t('CAMPAIGN.ADD.FORM.TITLE.PLACEHOLDER')"
|
||||||
|
@input="$v.title.$touch"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="medium-12 columns">
|
||||||
|
<label :class="{ error: $v.message.$error }">
|
||||||
|
{{ $t('CAMPAIGN.ADD.FORM.MESSAGE.LABEL') }}
|
||||||
|
<textarea
|
||||||
|
v-model.trim="message"
|
||||||
|
rows="5"
|
||||||
|
type="text"
|
||||||
|
:placeholder="$t('CAMPAIGN.ADD.FORM.MESSAGE.PLACEHOLDER')"
|
||||||
|
@input="$v.message.$touch"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="medium-12 columns">
|
||||||
|
<label :class="{ error: $v.selectedAgent.$error }">
|
||||||
|
{{ $t('CAMPAIGN.ADD.FORM.SENT_BY.LABEL') }}
|
||||||
|
<select v-model="selectedAgent">
|
||||||
|
<option
|
||||||
|
v-for="agent in agentsList"
|
||||||
|
:key="agent.name"
|
||||||
|
:value="agent.name"
|
||||||
|
>
|
||||||
|
{{ agent.name }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
<span v-if="$v.selectedAgent.$error" class="message">
|
||||||
|
{{ $t('CAMPAIGN.ADD.FORM.SENT_BY.ERROR') }}
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="medium-12 columns">
|
||||||
|
<label :class="{ error: $v.endPoint.$error }">
|
||||||
|
{{ $t('CAMPAIGN.ADD.FORM.END_POINT.LABEL') }}
|
||||||
|
<input
|
||||||
|
v-model.trim="endPoint"
|
||||||
|
type="text"
|
||||||
|
:placeholder="$t('CAMPAIGN.ADD.FORM.END_POINT.PLACEHOLDER')"
|
||||||
|
@input="$v.endPoint.$touch"
|
||||||
|
/>
|
||||||
|
<span v-if="$v.endPoint.$error" class="message">
|
||||||
|
{{ $t('CAMPAIGN.ADD.FORM.END_POINT.ERROR') }}
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="medium-12 columns">
|
||||||
|
<label :class="{ error: $v.timeOnPage.$error }">
|
||||||
|
{{ $t('CAMPAIGN.ADD.FORM.TIME_ON_PAGE.LABEL') }}
|
||||||
|
<input
|
||||||
|
v-model.trim="timeOnPage"
|
||||||
|
type="number"
|
||||||
|
:placeholder="$t('CAMPAIGN.ADD.FORM.TIME_ON_PAGE.PLACEHOLDER')"
|
||||||
|
@input="$v.timeOnPage.$touch"
|
||||||
|
/>
|
||||||
|
<span v-if="$v.timeOnPage.$error" class="message">
|
||||||
|
{{ $t('CAMPAIGN.ADD.FORM.TIME_ON_PAGE.ERROR') }}
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="medium-12 columns">
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
v-model="enabled"
|
||||||
|
type="checkbox"
|
||||||
|
value="enabled"
|
||||||
|
name="enabled"
|
||||||
|
/>
|
||||||
|
{{ $t('CAMPAIGN.ADD.FORM.ENABLED') }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-footer">
|
||||||
|
<div class="medium-12 columns">
|
||||||
|
<woot-submit-button
|
||||||
|
:disabled="buttonDisabled"
|
||||||
|
:loading="uiFlags.isCreating"
|
||||||
|
:button-text="$t('CAMPAIGN.ADD.CREATE_BUTTON_TEXT')"
|
||||||
|
/>
|
||||||
|
<button class="button clear" @click.prevent="onClose">
|
||||||
|
{{ $t('CAMPAIGN.ADD.CANCEL_BUTTON_TEXT') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapGetters } from 'vuex';
|
||||||
|
import { required, url, minLength } from 'vuelidate/lib/validators';
|
||||||
|
import Modal from 'dashboard/components/Modal';
|
||||||
|
import alertMixin from 'shared/mixins/alertMixin';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
Modal,
|
||||||
|
},
|
||||||
|
mixins: [alertMixin],
|
||||||
|
props: {
|
||||||
|
onClose: {
|
||||||
|
type: Function,
|
||||||
|
default: () => {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
title: '',
|
||||||
|
message: '',
|
||||||
|
selectedAgent: '',
|
||||||
|
endPoint: '',
|
||||||
|
timeOnPage: 10,
|
||||||
|
show: true,
|
||||||
|
enabled: true,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
validations: {
|
||||||
|
title: {
|
||||||
|
required,
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
required,
|
||||||
|
},
|
||||||
|
selectedAgent: {
|
||||||
|
required,
|
||||||
|
},
|
||||||
|
endPoint: {
|
||||||
|
required,
|
||||||
|
minLength: minLength(7),
|
||||||
|
url,
|
||||||
|
},
|
||||||
|
timeOnPage: {
|
||||||
|
required,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
...mapGetters({
|
||||||
|
agentList: 'agents/getAgents',
|
||||||
|
uiFlags: 'campaigns/getUIFlags',
|
||||||
|
}),
|
||||||
|
|
||||||
|
agentsList() {
|
||||||
|
return this.agentList;
|
||||||
|
},
|
||||||
|
buttonDisabled() {
|
||||||
|
return (
|
||||||
|
this.$v.message.$invalid ||
|
||||||
|
this.$v.title.$invalid ||
|
||||||
|
this.$v.selectedAgent.$invalid ||
|
||||||
|
this.$v.endPoint.$invalid ||
|
||||||
|
this.$v.timeOnPage.$invalid ||
|
||||||
|
this.uiFlags.isCreating
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async addCampaign() {
|
||||||
|
try {
|
||||||
|
await this.$store.dispatch('campaigns/create', {
|
||||||
|
title: this.title,
|
||||||
|
message: this.message,
|
||||||
|
inbox_id: this.$route.params.inboxId,
|
||||||
|
sender_id: this.selectedAgent,
|
||||||
|
enabled: this.enabled,
|
||||||
|
trigger_rules: {
|
||||||
|
url: this.endPoint,
|
||||||
|
time_on_page: this.timeOnPage,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.showAlert(this.$t('CAMPAIGN.ADD.API.SUCCESS_MESSAGE'));
|
||||||
|
this.onClose();
|
||||||
|
} catch (error) {
|
||||||
|
this.showAlert(this.$t('CAMPAIGN.ADD.API.ERROR_MESSAGE'));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.content-box .page-top-bar::v-deep {
|
||||||
|
padding: var(--space-large) var(--space-large) var(--space-zero);
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,17 +1,17 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="column content-box">
|
<div class="column content-box">
|
||||||
<div class="row">
|
<div v-if="campaigns.length" class="row button-wrapper">
|
||||||
<a class="button icon success nice button--fixed-right-top">
|
<woot-button @click="openAddPopup">
|
||||||
<i class="icon ion-android-add-circle"></i>
|
<i class="icon ion-android-add-circle"></i>
|
||||||
{{ $t('CAMPAIGN.HEADER_BTN_TXT') }}
|
{{ $t('CAMPAIGN.HEADER_BTN_TXT') }}
|
||||||
</a>
|
</woot-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div v-if="!campaigns.length" class="row">
|
||||||
<div class="small-8 columns">
|
<div class="small-8 columns">
|
||||||
<p class="no-items-error-message">
|
<p class="no-items-error-message">
|
||||||
{{ $t('CAMPAIGN.LIST.404') }}
|
{{ $t('CAMPAIGN.LIST.404') }}
|
||||||
<a>
|
<a @click="openAddPopup">
|
||||||
{{ $t('CAMPAIGN.HEADER_BTN_TXT') }}
|
{{ $t('CAMPAIGN.HEADER_BTN_TXT') }}
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
@ -22,16 +22,41 @@
|
||||||
<p>
|
<p>
|
||||||
<b> {{ $t('CAMPAIGN.HEADER') }}</b>
|
<b> {{ $t('CAMPAIGN.HEADER') }}</b>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p v-html="$t('CAMPAIGN.SIDEBAR_TXT')" />
|
||||||
Proactive messages allows customer send outbound messages to their
|
|
||||||
contacts which would trigger more conversations. Campaigns are tied
|
|
||||||
to inbox. Click on
|
|
||||||
<b>Add Campaign</b>
|
|
||||||
to create a new campaign. You can also edit or delete an existing
|
|
||||||
campaigns Response by clicking on the Edit or Delete button.
|
|
||||||
</p>
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<woot-modal :show.sync="showAddPopup" :on-close="hideAddPopup">
|
||||||
|
<add-campaign :on-close="hideAddPopup" />
|
||||||
|
</woot-modal>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
<script>
|
||||||
|
import AddCampaign from './AddCampaign';
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
AddCampaign,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
campaigns: [],
|
||||||
|
showAddPopup: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
openAddPopup() {
|
||||||
|
this.showAddPopup = true;
|
||||||
|
},
|
||||||
|
hideAddPopup() {
|
||||||
|
this.showAddPopup = false;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.button-wrapper {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -26,6 +26,7 @@ import userNotificationSettings from './modules/userNotificationSettings';
|
||||||
import webhooks from './modules/webhooks';
|
import webhooks from './modules/webhooks';
|
||||||
import teams from './modules/teams';
|
import teams from './modules/teams';
|
||||||
import teamMembers from './modules/teamMembers';
|
import teamMembers from './modules/teamMembers';
|
||||||
|
import campaigns from './modules/campaigns';
|
||||||
|
|
||||||
Vue.use(Vuex);
|
Vue.use(Vuex);
|
||||||
export default new Vuex.Store({
|
export default new Vuex.Store({
|
||||||
|
@ -55,5 +56,6 @@ export default new Vuex.Store({
|
||||||
webhooks,
|
webhooks,
|
||||||
teams,
|
teams,
|
||||||
teamMembers,
|
teamMembers,
|
||||||
|
campaigns,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
65
app/javascript/dashboard/store/modules/campaigns.js
Normal file
65
app/javascript/dashboard/store/modules/campaigns.js
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
import * as MutationHelpers from 'shared/helpers/vuex/mutationHelpers';
|
||||||
|
import types from '../mutation-types';
|
||||||
|
import CampaignsAPI from '../../api/campaigns';
|
||||||
|
|
||||||
|
export const state = {
|
||||||
|
records: [],
|
||||||
|
uiFlags: {
|
||||||
|
isFetching: false,
|
||||||
|
isCreating: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getters = {
|
||||||
|
getUIFlags(_state) {
|
||||||
|
return _state.uiFlags;
|
||||||
|
},
|
||||||
|
getCampaigns(_state) {
|
||||||
|
return _state.records;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const actions = {
|
||||||
|
get: async function getCampaigns({ commit }) {
|
||||||
|
commit(types.SET_CAMPAIGN_UI_FLAG, { isFetching: true });
|
||||||
|
try {
|
||||||
|
const response = await CampaignsAPI.get();
|
||||||
|
commit(types.SET_CAMPAIGNS, response.data);
|
||||||
|
} catch (error) {
|
||||||
|
// Ignore error
|
||||||
|
} finally {
|
||||||
|
commit(types.SET_CAMPAIGN_UI_FLAG, { isFetching: false });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
create: async function createCampaign({ commit }, campaignObj) {
|
||||||
|
commit(types.SET_CAMPAIGN_UI_FLAG, { isCreating: true });
|
||||||
|
try {
|
||||||
|
const response = await CampaignsAPI.create(campaignObj);
|
||||||
|
commit(types.ADD_CAMPAIGN, response.data);
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(error);
|
||||||
|
} finally {
|
||||||
|
commit(types.SET_CAMPAIGN_UI_FLAG, { isCreating: false });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const mutations = {
|
||||||
|
[types.SET_CAMPAIGN_UI_FLAG](_state, data) {
|
||||||
|
_state.uiFlags = {
|
||||||
|
..._state.uiFlags,
|
||||||
|
...data,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
[types.ADD_CAMPAIGN]: MutationHelpers.create,
|
||||||
|
[types.SET_CAMPAIGNS]: MutationHelpers.set,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
namespaced: true,
|
||||||
|
actions,
|
||||||
|
state,
|
||||||
|
getters,
|
||||||
|
mutations,
|
||||||
|
};
|
|
@ -0,0 +1,30 @@
|
||||||
|
import axios from 'axios';
|
||||||
|
import { actions } from '../../campaigns';
|
||||||
|
import * as types from '../../../mutation-types';
|
||||||
|
import campaignList from './fixtures';
|
||||||
|
|
||||||
|
const commit = jest.fn();
|
||||||
|
global.axios = axios;
|
||||||
|
jest.mock('axios');
|
||||||
|
|
||||||
|
describe('#actions', () => {
|
||||||
|
describe('#create', () => {
|
||||||
|
it('sends correct actions if API is success', async () => {
|
||||||
|
axios.post.mockResolvedValue({ data: campaignList[0] });
|
||||||
|
await actions.create({ commit }, campaignList[0]);
|
||||||
|
expect(commit.mock.calls).toEqual([
|
||||||
|
[types.default.SET_CAMPAIGN_UI_FLAG, { isCreating: true }],
|
||||||
|
[types.default.ADD_CAMPAIGN, campaignList[0]],
|
||||||
|
[types.default.SET_CAMPAIGN_UI_FLAG, { isCreating: false }],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
it('sends correct actions if API is error', async () => {
|
||||||
|
axios.post.mockRejectedValue({ message: 'Incorrect header' });
|
||||||
|
await expect(actions.create({ commit })).rejects.toThrow(Error);
|
||||||
|
expect(commit.mock.calls).toEqual([
|
||||||
|
[types.default.SET_CAMPAIGN_UI_FLAG, { isCreating: true }],
|
||||||
|
[types.default.SET_CAMPAIGN_UI_FLAG, { isCreating: false }],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,348 @@
|
||||||
|
export default [
|
||||||
|
{
|
||||||
|
id: 8,
|
||||||
|
title: 'Welcome',
|
||||||
|
description: null,
|
||||||
|
account_id: 1,
|
||||||
|
inbox: {
|
||||||
|
id: 37,
|
||||||
|
channel_id: 1,
|
||||||
|
name: 'Chatwoot',
|
||||||
|
channel_type: 'Channel::WebWidget',
|
||||||
|
greeting_enabled: true,
|
||||||
|
greeting_message: '',
|
||||||
|
working_hours_enabled: true,
|
||||||
|
out_of_office_message:
|
||||||
|
'We are unavailable at the moment. Leave a message we will respond once we are back.',
|
||||||
|
working_hours: [
|
||||||
|
{
|
||||||
|
day_of_week: 0,
|
||||||
|
closed_all_day: true,
|
||||||
|
open_hour: null,
|
||||||
|
open_minutes: null,
|
||||||
|
close_hour: null,
|
||||||
|
close_minutes: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
day_of_week: 1,
|
||||||
|
closed_all_day: false,
|
||||||
|
open_hour: 11,
|
||||||
|
open_minutes: 0,
|
||||||
|
close_hour: 23,
|
||||||
|
close_minutes: 30,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
day_of_week: 2,
|
||||||
|
closed_all_day: false,
|
||||||
|
open_hour: 11,
|
||||||
|
open_minutes: 0,
|
||||||
|
close_hour: 23,
|
||||||
|
close_minutes: 30,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
day_of_week: 3,
|
||||||
|
closed_all_day: false,
|
||||||
|
open_hour: 11,
|
||||||
|
open_minutes: 0,
|
||||||
|
close_hour: 23,
|
||||||
|
close_minutes: 30,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
day_of_week: 4,
|
||||||
|
closed_all_day: false,
|
||||||
|
open_hour: 11,
|
||||||
|
open_minutes: 0,
|
||||||
|
close_hour: 23,
|
||||||
|
close_minutes: 30,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
day_of_week: 5,
|
||||||
|
closed_all_day: false,
|
||||||
|
open_hour: 11,
|
||||||
|
open_minutes: 0,
|
||||||
|
close_hour: 23,
|
||||||
|
close_minutes: 30,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
day_of_week: 6,
|
||||||
|
closed_all_day: true,
|
||||||
|
open_hour: null,
|
||||||
|
open_minutes: null,
|
||||||
|
close_hour: null,
|
||||||
|
close_minutes: null,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
timezone: 'Asia/Kolkata',
|
||||||
|
avatar_url: '',
|
||||||
|
page_id: null,
|
||||||
|
widget_color: '#1F93FF',
|
||||||
|
website_url: 'chatwoot.com',
|
||||||
|
welcome_title: 'Hi there ! 🙌🏼',
|
||||||
|
welcome_tagline:
|
||||||
|
'We make it simple to connect with us. Ask us anything, or share your feedback.',
|
||||||
|
enable_auto_assignment: true,
|
||||||
|
website_token: '',
|
||||||
|
forward_to_email: null,
|
||||||
|
phone_number: null,
|
||||||
|
selected_feature_flags: ['attachments', 'emoji_picker'],
|
||||||
|
reply_time: 'in_a_few_hours',
|
||||||
|
hmac_token: '',
|
||||||
|
pre_chat_form_enabled: true,
|
||||||
|
pre_chat_form_options: {
|
||||||
|
require_email: true,
|
||||||
|
pre_chat_message: 'Share your queries or comments here.',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
sender: {
|
||||||
|
account_id: 1,
|
||||||
|
availability_status: 'offline',
|
||||||
|
confirmed: true,
|
||||||
|
email: 'sojan@chatwoot.com',
|
||||||
|
available_name: 'Sojan',
|
||||||
|
id: 10,
|
||||||
|
name: 'Sojan',
|
||||||
|
role: 'administrator',
|
||||||
|
thumbnail:
|
||||||
|
'http://0.0.0.0:3000/rails/active_storage/representations/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBDZz09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--bfa5e8a4563aef73980771fc9b8007d380e586e5/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdCam9MY21WemFYcGxTU0lNTWpVd2VESTFNQVk2QmtWVSIsImV4cCI6bnVsbCwicHVyIjoidmFyaWF0aW9uIn19--c13bd5229b2a2a692444606e22f76ad61c634661/73185.jpeg',
|
||||||
|
},
|
||||||
|
message: 'Hey, What brings you today',
|
||||||
|
enabled: true,
|
||||||
|
trigger_rules: {
|
||||||
|
url: 'https://github.com',
|
||||||
|
time_on_page: 10,
|
||||||
|
},
|
||||||
|
created_at: '2021-05-03T04:53:36.354Z',
|
||||||
|
updated_at: '2021-05-03T04:53:36.354Z',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 11,
|
||||||
|
title: 'Onboarding Campaign',
|
||||||
|
description: null,
|
||||||
|
account_id: 1,
|
||||||
|
inbox: {
|
||||||
|
id: 37,
|
||||||
|
channel_id: 1,
|
||||||
|
name: 'Chatwoot',
|
||||||
|
channel_type: 'Channel::WebWidget',
|
||||||
|
greeting_enabled: true,
|
||||||
|
greeting_message: '',
|
||||||
|
working_hours_enabled: true,
|
||||||
|
out_of_office_message:
|
||||||
|
'We are unavailable at the moment. Leave a message we will respond once we are back.',
|
||||||
|
working_hours: [
|
||||||
|
{
|
||||||
|
day_of_week: 0,
|
||||||
|
closed_all_day: true,
|
||||||
|
open_hour: null,
|
||||||
|
open_minutes: null,
|
||||||
|
close_hour: null,
|
||||||
|
close_minutes: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
day_of_week: 1,
|
||||||
|
closed_all_day: false,
|
||||||
|
open_hour: 11,
|
||||||
|
open_minutes: 0,
|
||||||
|
close_hour: 23,
|
||||||
|
close_minutes: 30,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
day_of_week: 2,
|
||||||
|
closed_all_day: false,
|
||||||
|
open_hour: 11,
|
||||||
|
open_minutes: 0,
|
||||||
|
close_hour: 23,
|
||||||
|
close_minutes: 30,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
day_of_week: 3,
|
||||||
|
closed_all_day: false,
|
||||||
|
open_hour: 11,
|
||||||
|
open_minutes: 0,
|
||||||
|
close_hour: 23,
|
||||||
|
close_minutes: 30,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
day_of_week: 4,
|
||||||
|
closed_all_day: false,
|
||||||
|
open_hour: 11,
|
||||||
|
open_minutes: 0,
|
||||||
|
close_hour: 23,
|
||||||
|
close_minutes: 30,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
day_of_week: 5,
|
||||||
|
closed_all_day: false,
|
||||||
|
open_hour: 11,
|
||||||
|
open_minutes: 0,
|
||||||
|
close_hour: 23,
|
||||||
|
close_minutes: 30,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
day_of_week: 6,
|
||||||
|
closed_all_day: true,
|
||||||
|
open_hour: null,
|
||||||
|
open_minutes: null,
|
||||||
|
close_hour: null,
|
||||||
|
close_minutes: null,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
timezone: 'Asia/Kolkata',
|
||||||
|
avatar_url: '',
|
||||||
|
page_id: null,
|
||||||
|
widget_color: '#1F93FF',
|
||||||
|
website_url: 'chatwoot.com',
|
||||||
|
welcome_title: 'Hi there ! 🙌🏼',
|
||||||
|
welcome_tagline:
|
||||||
|
'We make it simple to connect with us. Ask us anything, or share your feedback.',
|
||||||
|
enable_auto_assignment: true,
|
||||||
|
web_widget_script: '',
|
||||||
|
website_token: '',
|
||||||
|
forward_to_email: null,
|
||||||
|
phone_number: null,
|
||||||
|
selected_feature_flags: ['attachments', 'emoji_picker'],
|
||||||
|
reply_time: 'in_a_few_hours',
|
||||||
|
hmac_token: '',
|
||||||
|
pre_chat_form_enabled: true,
|
||||||
|
pre_chat_form_options: {
|
||||||
|
require_email: true,
|
||||||
|
pre_chat_message: 'Share your queries or comments here.',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
sender: {
|
||||||
|
account_id: 1,
|
||||||
|
availability_status: 'offline',
|
||||||
|
confirmed: true,
|
||||||
|
email: 'sojan@chatwoot.com',
|
||||||
|
available_name: 'Sojan',
|
||||||
|
id: 10,
|
||||||
|
name: 'Sojan',
|
||||||
|
role: 'administrator',
|
||||||
|
thumbnail:
|
||||||
|
'http://0.0.0.0:3000/rails/active_storage/representations/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBDZz09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--bfa5e8a4563aef73980771fc9b8007d380e586e5/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdCam9MY21WemFYcGxTU0lNTWpVd2VESTFNQVk2QmtWVSIsImV4cCI6bnVsbCwicHVyIjoidmFyaWF0aW9uIn19--c13bd5229b2a2a692444606e22f76ad61c634661/73185.jpeg',
|
||||||
|
},
|
||||||
|
message: 'Begin your onboarding campaign with a welcome message',
|
||||||
|
enabled: true,
|
||||||
|
trigger_rules: {
|
||||||
|
url: 'https://chatwoot.com',
|
||||||
|
time_on_page: '20',
|
||||||
|
},
|
||||||
|
created_at: '2021-05-03T08:15:35.828Z',
|
||||||
|
updated_at: '2021-05-03T08:15:35.828Z',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 12,
|
||||||
|
title: 'Thanks',
|
||||||
|
description: null,
|
||||||
|
account_id: 1,
|
||||||
|
inbox: {
|
||||||
|
id: 37,
|
||||||
|
channel_id: 1,
|
||||||
|
name: 'Chatwoot',
|
||||||
|
channel_type: 'Channel::WebWidget',
|
||||||
|
greeting_enabled: true,
|
||||||
|
greeting_message: '',
|
||||||
|
working_hours_enabled: true,
|
||||||
|
out_of_office_message:
|
||||||
|
'We are unavailable at the moment. Leave a message we will respond once we are back.',
|
||||||
|
working_hours: [
|
||||||
|
{
|
||||||
|
day_of_week: 0,
|
||||||
|
closed_all_day: true,
|
||||||
|
open_hour: null,
|
||||||
|
open_minutes: null,
|
||||||
|
close_hour: null,
|
||||||
|
close_minutes: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
day_of_week: 1,
|
||||||
|
closed_all_day: false,
|
||||||
|
open_hour: 11,
|
||||||
|
open_minutes: 0,
|
||||||
|
close_hour: 23,
|
||||||
|
close_minutes: 30,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
day_of_week: 2,
|
||||||
|
closed_all_day: false,
|
||||||
|
open_hour: 11,
|
||||||
|
open_minutes: 0,
|
||||||
|
close_hour: 23,
|
||||||
|
close_minutes: 30,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
day_of_week: 3,
|
||||||
|
closed_all_day: false,
|
||||||
|
open_hour: 11,
|
||||||
|
open_minutes: 0,
|
||||||
|
close_hour: 23,
|
||||||
|
close_minutes: 30,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
day_of_week: 4,
|
||||||
|
closed_all_day: false,
|
||||||
|
open_hour: 11,
|
||||||
|
open_minutes: 0,
|
||||||
|
close_hour: 23,
|
||||||
|
close_minutes: 30,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
day_of_week: 5,
|
||||||
|
closed_all_day: false,
|
||||||
|
open_hour: 11,
|
||||||
|
open_minutes: 0,
|
||||||
|
close_hour: 23,
|
||||||
|
close_minutes: 30,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
day_of_week: 6,
|
||||||
|
closed_all_day: true,
|
||||||
|
open_hour: null,
|
||||||
|
open_minutes: null,
|
||||||
|
close_hour: null,
|
||||||
|
close_minutes: null,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
timezone: 'Asia/Kolkata',
|
||||||
|
avatar_url: '',
|
||||||
|
page_id: null,
|
||||||
|
widget_color: '#1F93FF',
|
||||||
|
website_url: 'chatwoot.com',
|
||||||
|
welcome_title: 'Hi there ! 🙌🏼',
|
||||||
|
welcome_tagline:
|
||||||
|
'We make it simple to connect with us. Ask us anything, or share your feedback.',
|
||||||
|
enable_auto_assignment: true,
|
||||||
|
web_widget_script: '',
|
||||||
|
website_token: '',
|
||||||
|
forward_to_email: null,
|
||||||
|
phone_number: null,
|
||||||
|
selected_feature_flags: ['attachments', 'emoji_picker'],
|
||||||
|
reply_time: 'in_a_few_hours',
|
||||||
|
hmac_token: '',
|
||||||
|
pre_chat_form_enabled: true,
|
||||||
|
pre_chat_form_options: {
|
||||||
|
require_email: true,
|
||||||
|
pre_chat_message: 'Share your queries or comments here.',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
sender: {
|
||||||
|
account_id: 1,
|
||||||
|
availability_status: 'offline',
|
||||||
|
confirmed: true,
|
||||||
|
email: 'nithin@chatwoot.com',
|
||||||
|
available_name: 'Nithin',
|
||||||
|
id: 13,
|
||||||
|
name: 'Nithin',
|
||||||
|
role: 'administrator',
|
||||||
|
thumbnail: '',
|
||||||
|
},
|
||||||
|
message: 'Thanks for coming to the show. How may I help you?',
|
||||||
|
enabled: false,
|
||||||
|
trigger_rules: {
|
||||||
|
url: 'https://noshow.com',
|
||||||
|
time_on_page: 10,
|
||||||
|
},
|
||||||
|
created_at: '2021-05-03T10:22:51.025Z',
|
||||||
|
updated_at: '2021-05-03T10:22:51.025Z',
|
||||||
|
},
|
||||||
|
];
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { getters } from '../../campaigns';
|
||||||
|
import campaigns from './fixtures';
|
||||||
|
|
||||||
|
describe('#getters', () => {
|
||||||
|
it('getCampaigns', () => {
|
||||||
|
const state = { records: campaigns };
|
||||||
|
expect(getters.getCampaigns(state)).toEqual(campaigns);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('getUIFlags', () => {
|
||||||
|
const state = {
|
||||||
|
uiFlags: {
|
||||||
|
isFetching: true,
|
||||||
|
isCreating: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
expect(getters.getUIFlags(state)).toEqual({
|
||||||
|
isFetching: true,
|
||||||
|
isCreating: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,21 @@
|
||||||
|
import types from '../../../mutation-types';
|
||||||
|
import { mutations } from '../../campaigns';
|
||||||
|
import campaigns from './fixtures';
|
||||||
|
|
||||||
|
describe('#mutations', () => {
|
||||||
|
describe('#SET_CAMPAIGNS', () => {
|
||||||
|
it('set campaigns records', () => {
|
||||||
|
const state = { records: [] };
|
||||||
|
mutations[types.SET_CAMPAIGNS](state, campaigns);
|
||||||
|
expect(state.records).toEqual(campaigns);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#ADD_CAMPAIGN', () => {
|
||||||
|
it('push newly created campaigns to the store', () => {
|
||||||
|
const state = { records: [campaigns[0]] };
|
||||||
|
mutations[types.ADD_CAMPAIGN](state, campaigns[1]);
|
||||||
|
expect(state.records).toEqual([campaigns[0], campaigns[1]]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -145,4 +145,9 @@ export default {
|
||||||
// Conversation Search
|
// Conversation Search
|
||||||
SEARCH_CONVERSATIONS_SET: 'SEARCH_CONVERSATIONS_SET',
|
SEARCH_CONVERSATIONS_SET: 'SEARCH_CONVERSATIONS_SET',
|
||||||
SEARCH_CONVERSATIONS_SET_UI_FLAG: 'SEARCH_CONVERSATIONS_SET_UI_FLAG',
|
SEARCH_CONVERSATIONS_SET_UI_FLAG: 'SEARCH_CONVERSATIONS_SET_UI_FLAG',
|
||||||
|
|
||||||
|
// Campaigns
|
||||||
|
SET_CAMPAIGN_UI_FLAG: 'SET_CAMPAIGN_UI_FLAG',
|
||||||
|
SET_CAMPAIGNS: 'SET_CAMPAIGNS',
|
||||||
|
ADD_CAMPAIGN: 'ADD_CAMPAIGN',
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
"test:coverage": "jest -w 1 --no-cache --collectCoverage",
|
"test:coverage": "jest -w 1 --no-cache --collectCoverage",
|
||||||
"webpacker-start": "webpack-dev-server -d --config webpack.dev.config.js --content-base public/ --progress --colors",
|
"webpacker-start": "webpack-dev-server -d --config webpack.dev.config.js --content-base public/ --progress --colors",
|
||||||
"start:dev": "foreman start -f ./Procfile.dev",
|
"start:dev": "foreman start -f ./Procfile.dev",
|
||||||
|
"start:dev-overmind": "overmind start -f ./Procfile.dev",
|
||||||
"storybook": "start-storybook -p 6006",
|
"storybook": "start-storybook -p 6006",
|
||||||
"build-storybook": "build-storybook"
|
"build-storybook": "build-storybook"
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue