mirror of
https://github.com/lingble/chatwoot.git
synced 2025-11-02 20:18:08 +00:00
feat: Campaign table (#2212)
* code cleanup * add campaign table * update locale texts * locale text cleanup * Rename selectedAgent with selectedSender in add campaign form * code cleanup * remove timer mixin * update avatar size to 20px * add border for table * add campaigns get action specs * rename campaign table component * fix style issues * update sender list based on inbox permission * style fixes * review fixes * add campaign sender component * replace wootsubmit button with wootbutton * update scroll width * replace campaign status with woot label * changes as per review * style fixes * remove unused code * disable campaign in inbox settings page * review fixes
This commit is contained in:
@@ -3,9 +3,6 @@
|
|||||||
"HEADER": "Campaigns",
|
"HEADER": "Campaigns",
|
||||||
"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.",
|
"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",
|
"HEADER_BTN_TXT": "Create a campaign",
|
||||||
"LIST": {
|
|
||||||
"404": "There are no campaigns created for this inbox."
|
|
||||||
},
|
|
||||||
"ADD": {
|
"ADD": {
|
||||||
"TITLE": "Create a campaign",
|
"TITLE": "Create a campaign",
|
||||||
"DESC": "Proactive messages allow the customer to send outbound messages to their contacts which would trigger more conversations.",
|
"DESC": "Proactive messages allow the customer to send outbound messages to their contacts which would trigger more conversations.",
|
||||||
@@ -44,6 +41,27 @@
|
|||||||
"SUCCESS_MESSAGE": "Campaign created successfully",
|
"SUCCESS_MESSAGE": "Campaign created successfully",
|
||||||
"ERROR_MESSAGE": "There was an error. Please try again."
|
"ERROR_MESSAGE": "There was an error. Please try again."
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"LIST": {
|
||||||
|
"LOADING_MESSAGE": "Loading campaigns...",
|
||||||
|
"TABLE_HEADER": {
|
||||||
|
"TITLE": "Title",
|
||||||
|
"MESSAGE": "Message",
|
||||||
|
"STATUS": "Status",
|
||||||
|
"SENDER": "Sender",
|
||||||
|
"URL": "URL",
|
||||||
|
"TIME_ON_PAGE": "Time(Seconds)",
|
||||||
|
"CREATED_AT": "Created at"
|
||||||
|
},
|
||||||
|
"BUTTONS": {
|
||||||
|
"ADD": "Add",
|
||||||
|
"EDIT": "Edit",
|
||||||
|
"DELETE": "Delete"
|
||||||
|
},
|
||||||
|
"STATUS": {
|
||||||
|
"ENABLED": "Enabled",
|
||||||
|
"DISABLED": "Disabled"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -258,7 +258,7 @@
|
|||||||
<weekly-availability :inbox="inbox" />
|
<weekly-availability :inbox="inbox" />
|
||||||
</div>
|
</div>
|
||||||
<div v-if="selectedTabKey === 'campaign'">
|
<div v-if="selectedTabKey === 'campaign'">
|
||||||
<campaign />
|
<campaign :selected-agents="selectedAgents" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -32,18 +32,18 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="medium-12 columns">
|
<div class="medium-12 columns">
|
||||||
<label :class="{ error: $v.selectedAgent.$error }">
|
<label :class="{ error: $v.selectedSender.$error }">
|
||||||
{{ $t('CAMPAIGN.ADD.FORM.SENT_BY.LABEL') }}
|
{{ $t('CAMPAIGN.ADD.FORM.SENT_BY.LABEL') }}
|
||||||
<select v-model="selectedAgent">
|
<select v-model="selectedSender">
|
||||||
<option
|
<option
|
||||||
v-for="agent in agentsList"
|
v-for="sender in senderList"
|
||||||
:key="agent.name"
|
:key="sender.name"
|
||||||
:value="agent.name"
|
:value="sender.id"
|
||||||
>
|
>
|
||||||
{{ agent.name }}
|
{{ sender.name }}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
<span v-if="$v.selectedAgent.$error" class="message">
|
<span v-if="$v.selectedSender.$error" class="message">
|
||||||
{{ $t('CAMPAIGN.ADD.FORM.SENT_BY.ERROR') }}
|
{{ $t('CAMPAIGN.ADD.FORM.SENT_BY.ERROR') }}
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
@@ -119,6 +119,10 @@ export default {
|
|||||||
},
|
},
|
||||||
mixins: [alertMixin],
|
mixins: [alertMixin],
|
||||||
props: {
|
props: {
|
||||||
|
senderList: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
onClose: {
|
onClose: {
|
||||||
type: Function,
|
type: Function,
|
||||||
default: () => {},
|
default: () => {},
|
||||||
@@ -128,7 +132,7 @@ export default {
|
|||||||
return {
|
return {
|
||||||
title: '',
|
title: '',
|
||||||
message: '',
|
message: '',
|
||||||
selectedAgent: '',
|
selectedSender: '',
|
||||||
endPoint: '',
|
endPoint: '',
|
||||||
timeOnPage: 10,
|
timeOnPage: 10,
|
||||||
show: true,
|
show: true,
|
||||||
@@ -142,7 +146,7 @@ export default {
|
|||||||
message: {
|
message: {
|
||||||
required,
|
required,
|
||||||
},
|
},
|
||||||
selectedAgent: {
|
selectedSender: {
|
||||||
required,
|
required,
|
||||||
},
|
},
|
||||||
endPoint: {
|
endPoint: {
|
||||||
@@ -157,18 +161,13 @@ export default {
|
|||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters({
|
...mapGetters({
|
||||||
agentList: 'agents/getAgents',
|
|
||||||
uiFlags: 'campaigns/getUIFlags',
|
uiFlags: 'campaigns/getUIFlags',
|
||||||
}),
|
}),
|
||||||
|
|
||||||
agentsList() {
|
|
||||||
return this.agentList;
|
|
||||||
},
|
|
||||||
buttonDisabled() {
|
buttonDisabled() {
|
||||||
return (
|
return (
|
||||||
this.$v.message.$invalid ||
|
this.$v.message.$invalid ||
|
||||||
this.$v.title.$invalid ||
|
this.$v.title.$invalid ||
|
||||||
this.$v.selectedAgent.$invalid ||
|
this.$v.selectedSender.$invalid ||
|
||||||
this.$v.endPoint.$invalid ||
|
this.$v.endPoint.$invalid ||
|
||||||
this.$v.timeOnPage.$invalid ||
|
this.$v.timeOnPage.$invalid ||
|
||||||
this.uiFlags.isCreating
|
this.uiFlags.isCreating
|
||||||
@@ -182,7 +181,7 @@ export default {
|
|||||||
title: this.title,
|
title: this.title,
|
||||||
message: this.message,
|
message: this.message,
|
||||||
inbox_id: this.$route.params.inboxId,
|
inbox_id: this.$route.params.inboxId,
|
||||||
sender_id: this.selectedAgent,
|
sender_id: this.selectedSender,
|
||||||
enabled: this.enabled,
|
enabled: this.enabled,
|
||||||
trigger_rules: {
|
trigger_rules: {
|
||||||
url: this.endPoint,
|
url: this.endPoint,
|
||||||
|
|||||||
@@ -1,41 +1,37 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="column content-box">
|
<div class="column content-box">
|
||||||
<div v-if="campaigns.length" class="row button-wrapper">
|
<div class="row button-wrapper">
|
||||||
<woot-button @click="openAddPopup">
|
<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') }}
|
||||||
</woot-button>
|
</woot-button>
|
||||||
</div>
|
</div>
|
||||||
|
<campaigns-table
|
||||||
|
:campaigns="records"
|
||||||
|
:show-empty-state="showEmptyResult"
|
||||||
|
:is-loading="uiFlags.isFetching"
|
||||||
|
/>
|
||||||
|
|
||||||
<div v-if="!campaigns.length" class="row">
|
|
||||||
<div class="small-8 columns">
|
|
||||||
<p class="no-items-error-message">
|
|
||||||
{{ $t('CAMPAIGN.LIST.404') }}
|
|
||||||
<a @click="openAddPopup">
|
|
||||||
{{ $t('CAMPAIGN.HEADER_BTN_TXT') }}
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="small-4 columns">
|
|
||||||
<span>
|
|
||||||
<p>
|
|
||||||
<b> {{ $t('CAMPAIGN.HEADER') }}</b>
|
|
||||||
</p>
|
|
||||||
<p v-html="$t('CAMPAIGN.SIDEBAR_TXT')" />
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<woot-modal :show.sync="showAddPopup" :on-close="hideAddPopup">
|
<woot-modal :show.sync="showAddPopup" :on-close="hideAddPopup">
|
||||||
<add-campaign :on-close="hideAddPopup" />
|
<add-campaign :on-close="hideAddPopup" :sender-list="selectedAgents" />
|
||||||
</woot-modal>
|
</woot-modal>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
|
import { mapGetters } from 'vuex';
|
||||||
import AddCampaign from './AddCampaign';
|
import AddCampaign from './AddCampaign';
|
||||||
|
import CampaignsTable from './CampaignsTable';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
AddCampaign,
|
AddCampaign,
|
||||||
|
CampaignsTable,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
selectedAgents: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@@ -43,6 +39,19 @@ export default {
|
|||||||
showAddPopup: false,
|
showAddPopup: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
...mapGetters({
|
||||||
|
records: 'campaigns/getCampaigns',
|
||||||
|
uiFlags: 'campaigns/getUIFlags',
|
||||||
|
}),
|
||||||
|
showEmptyResult() {
|
||||||
|
const hasEmptyResults = this.records.length === 0;
|
||||||
|
return hasEmptyResults;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.$store.dispatch('campaigns/get');
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
openAddPopup() {
|
openAddPopup() {
|
||||||
this.showAddPopup = true;
|
this.showAddPopup = true;
|
||||||
@@ -58,5 +67,6 @@ export default {
|
|||||||
.button-wrapper {
|
.button-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
|
padding-bottom: var(--space-one);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
<template>
|
||||||
|
<div class="row--user-block">
|
||||||
|
<Thumbnail
|
||||||
|
:src="sender.thumbnail"
|
||||||
|
size="20px"
|
||||||
|
:username="sender.name"
|
||||||
|
:status="sender.availability_status"
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<h6 class="text-block-title text-truncate">
|
||||||
|
{{ sender.name }}
|
||||||
|
</h6>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
Thumbnail,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
sender: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import '~dashboard/assets/scss/mixins';
|
||||||
|
|
||||||
|
.row--user-block {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
text-align: left;
|
||||||
|
|
||||||
|
.user-name {
|
||||||
|
margin: 0;
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
.user-thumbnail-box {
|
||||||
|
margin-right: var(--space-small);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,210 @@
|
|||||||
|
<template>
|
||||||
|
<section class="campaigns-table-wrap">
|
||||||
|
<ve-table
|
||||||
|
:columns="columns"
|
||||||
|
scroll-width="155rem"
|
||||||
|
:table-data="tableData"
|
||||||
|
:border-around="true"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<empty-state v-if="showEmptyResult" :title="$t('CAMPAIGN.LIST.404')" />
|
||||||
|
<div v-if="isLoading" class="campaign--loader">
|
||||||
|
<spinner />
|
||||||
|
<span>{{ $t('CAMPAIGN.LIST.LOADING_MESSAGE') }}</span>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mixin as clickaway } from 'vue-clickaway';
|
||||||
|
import { VeTable } from 'vue-easytable';
|
||||||
|
import Spinner from 'shared/components/Spinner.vue';
|
||||||
|
import Label from 'dashboard/components/ui/Label';
|
||||||
|
import EmptyState from 'dashboard/components/widgets/EmptyState.vue';
|
||||||
|
import WootButton from 'dashboard/components/ui/WootButton.vue';
|
||||||
|
import CampaignSender from './CampaignSender';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
EmptyState,
|
||||||
|
Spinner,
|
||||||
|
VeTable,
|
||||||
|
},
|
||||||
|
mixins: [clickaway],
|
||||||
|
props: {
|
||||||
|
campaigns: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
showEmptyResult: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
isLoading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
field: 'title',
|
||||||
|
key: 'title',
|
||||||
|
title: this.$t('CAMPAIGN.LIST.TABLE_HEADER.TITLE'),
|
||||||
|
fixed: 'left',
|
||||||
|
align: 'left',
|
||||||
|
renderBodyCell: ({ row }) => (
|
||||||
|
<div class="row--title-block">
|
||||||
|
<h6 class="sub-block-title title text-truncate">{row.title}</h6>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
field: 'message',
|
||||||
|
key: 'message',
|
||||||
|
title: this.$t('CAMPAIGN.LIST.TABLE_HEADER.MESSAGE'),
|
||||||
|
align: 'left',
|
||||||
|
width: 350,
|
||||||
|
renderBodyCell: ({ row }) => {
|
||||||
|
return (
|
||||||
|
<div class="text-truncate">
|
||||||
|
<span title={row.message}>{row.message}</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'enabled',
|
||||||
|
key: 'enabled',
|
||||||
|
title: this.$t('CAMPAIGN.LIST.TABLE_HEADER.STATUS'),
|
||||||
|
align: 'left',
|
||||||
|
renderBodyCell: ({ row }) => {
|
||||||
|
const labelText = row.enabled
|
||||||
|
? this.$t('CAMPAIGN.LIST.STATUS.ENABLED')
|
||||||
|
: this.$t('CAMPAIGN.LIST.STATUS.DISABLED');
|
||||||
|
const colorScheme = row.enabled ? 'success' : 'secondary';
|
||||||
|
return <Label title={labelText} colorScheme={colorScheme} />;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
field: 'sender',
|
||||||
|
key: 'sender',
|
||||||
|
title: this.$t('CAMPAIGN.LIST.TABLE_HEADER.SENDER'),
|
||||||
|
align: 'left',
|
||||||
|
renderBodyCell: ({ row }) => {
|
||||||
|
if (row.sender) return <CampaignSender sender={row.sender} />;
|
||||||
|
return '---';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'url',
|
||||||
|
key: 'url',
|
||||||
|
title: this.$t('CAMPAIGN.LIST.TABLE_HEADER.URL'),
|
||||||
|
align: 'left',
|
||||||
|
renderBodyCell: ({ row }) => (
|
||||||
|
<div class="text-truncate">
|
||||||
|
<a
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer nofollow"
|
||||||
|
href={row.url}
|
||||||
|
title={row.url}
|
||||||
|
>
|
||||||
|
{row.url}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'timeOnPage',
|
||||||
|
key: 'timeOnPage',
|
||||||
|
title: this.$t('CAMPAIGN.LIST.TABLE_HEADER.TIME_ON_PAGE'),
|
||||||
|
align: 'left',
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
field: 'buttons',
|
||||||
|
key: 'buttons',
|
||||||
|
title: '',
|
||||||
|
align: 'left',
|
||||||
|
renderBodyCell: () => (
|
||||||
|
<div class="button-wrapper">
|
||||||
|
<WootButton
|
||||||
|
variant="clear"
|
||||||
|
icon="ion-edit"
|
||||||
|
color-scheme="secondary"
|
||||||
|
classNames="hollow grey-btn"
|
||||||
|
click="openEditPopup(label)"
|
||||||
|
>
|
||||||
|
{this.$t('CAMPAIGN.LIST.BUTTONS.EDIT')}
|
||||||
|
</WootButton>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
tableData() {
|
||||||
|
if (this.isLoading) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return this.campaigns.map((item) => {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
url: item.trigger_rules.url,
|
||||||
|
timeOnPage: item.trigger_rules.time_on_page,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.campaigns-table-wrap::v-deep {
|
||||||
|
.ve-table {
|
||||||
|
padding-bottom: var(--space-large);
|
||||||
|
thead.ve-table-header .ve-table-header-tr .ve-table-header-th {
|
||||||
|
font-size: var(--font-size-mini);
|
||||||
|
padding: var(--space-small) var(--space-two);
|
||||||
|
}
|
||||||
|
tbody.ve-table-body .ve-table-body-tr .ve-table-body-td {
|
||||||
|
padding: var(--space-slab) var(--space-two);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.row--title-block {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
text-align: left;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: var(--font-size-small);
|
||||||
|
margin: 0;
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.label {
|
||||||
|
padding: var(--space-smaller) var(--space-small);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.campaign--loader {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
font-size: var(--font-size-default);
|
||||||
|
justify-content: center;
|
||||||
|
padding: var(--space-big);
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-wrapper {
|
||||||
|
justify-content: space-evenly;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
min-width: 20rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -8,6 +8,25 @@ global.axios = axios;
|
|||||||
jest.mock('axios');
|
jest.mock('axios');
|
||||||
|
|
||||||
describe('#actions', () => {
|
describe('#actions', () => {
|
||||||
|
describe('#get', () => {
|
||||||
|
it('sends correct actions if API is success', async () => {
|
||||||
|
axios.get.mockResolvedValue({ data: campaignList });
|
||||||
|
await actions.get({ commit });
|
||||||
|
expect(commit.mock.calls).toEqual([
|
||||||
|
[types.default.SET_CAMPAIGN_UI_FLAG, { isFetching: true }],
|
||||||
|
[types.default.SET_CAMPAIGNS, campaignList],
|
||||||
|
[types.default.SET_CAMPAIGN_UI_FLAG, { isFetching: false }],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
it('sends correct actions if API is error', async () => {
|
||||||
|
axios.get.mockRejectedValue({ message: 'Incorrect header' });
|
||||||
|
await actions.get({ commit });
|
||||||
|
expect(commit.mock.calls).toEqual([
|
||||||
|
[types.default.SET_CAMPAIGN_UI_FLAG, { isFetching: true }],
|
||||||
|
[types.default.SET_CAMPAIGN_UI_FLAG, { isFetching: false }],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
describe('#create', () => {
|
describe('#create', () => {
|
||||||
it('sends correct actions if API is success', async () => {
|
it('sends correct actions if API is success', async () => {
|
||||||
axios.post.mockResolvedValue({ data: campaignList[0] });
|
axios.post.mockResolvedValue({ data: campaignList[0] });
|
||||||
|
|||||||
Reference in New Issue
Block a user