feat: Add ability to bulk import contacts (#3026)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
This commit is contained in:
co-authored by
Pranav Raj S
parent
6129edce08
commit
bba2750975
@@ -7,6 +7,7 @@
|
||||
this-selected-contact-id=""
|
||||
:on-input-search="onInputSearch"
|
||||
:on-toggle-create="onToggleCreate"
|
||||
:on-toggle-import="onToggleImport"
|
||||
:header-title="label"
|
||||
/>
|
||||
<contacts-table
|
||||
@@ -30,6 +31,9 @@
|
||||
:on-close="closeContactInfoPanel"
|
||||
/>
|
||||
<create-contact :show="showCreateModal" @cancel="onToggleCreate" />
|
||||
<woot-modal :show.sync="showImportModal" :on-close="onToggleImport">
|
||||
<import-contacts v-if="showImportModal" :on-close="onToggleImport" />
|
||||
</woot-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -41,6 +45,7 @@ import ContactsTable from './ContactsTable';
|
||||
import ContactInfoPanel from './ContactInfoPanel';
|
||||
import CreateContact from 'dashboard/routes/dashboard/conversation/contact/CreateContact';
|
||||
import TableFooter from 'dashboard/components/widgets/TableFooter';
|
||||
import ImportContacts from './ImportContacts.vue';
|
||||
|
||||
const DEFAULT_PAGE = 1;
|
||||
|
||||
@@ -51,6 +56,7 @@ export default {
|
||||
TableFooter,
|
||||
ContactInfoPanel,
|
||||
CreateContact,
|
||||
ImportContacts,
|
||||
},
|
||||
props: {
|
||||
label: { type: String, default: '' },
|
||||
@@ -59,6 +65,7 @@ export default {
|
||||
return {
|
||||
searchQuery: '',
|
||||
showCreateModal: false,
|
||||
showImportModal: false,
|
||||
selectedContactId: '',
|
||||
sortConfig: { name: 'asc' },
|
||||
};
|
||||
@@ -168,6 +175,9 @@ export default {
|
||||
onToggleCreate() {
|
||||
this.showCreateModal = !this.showCreateModal;
|
||||
},
|
||||
onToggleImport() {
|
||||
this.showImportModal = !this.showImportModal;
|
||||
},
|
||||
onSortChange(params) {
|
||||
this.sortConfig = params;
|
||||
this.fetchContacts(this.meta.currentPage);
|
||||
|
||||
@@ -29,11 +29,20 @@
|
||||
<woot-button
|
||||
color-scheme="success"
|
||||
icon="ion-android-add-circle"
|
||||
@click="onToggleCreate"
|
||||
class="margin-right-small"
|
||||
data-testid="create-new-contact"
|
||||
@click="onToggleCreate"
|
||||
>
|
||||
{{ $t('CREATE_CONTACT.BUTTON_LABEL') }}
|
||||
</woot-button>
|
||||
|
||||
<woot-button
|
||||
color-scheme="info"
|
||||
icon="ion-android-upload"
|
||||
@click="onToggleImport"
|
||||
>
|
||||
{{ $t('IMPORT_CONTACTS.BUTTON_LABEL') }}
|
||||
</woot-button>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
@@ -41,7 +50,6 @@
|
||||
|
||||
<script>
|
||||
export default {
|
||||
components: {},
|
||||
props: {
|
||||
headerTitle: {
|
||||
type: String,
|
||||
@@ -63,10 +71,15 @@ export default {
|
||||
type: Function,
|
||||
default: () => {},
|
||||
},
|
||||
onToggleImport: {
|
||||
type: Function,
|
||||
default: () => {},
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showCreateModal: false,
|
||||
showImportModal: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -78,6 +91,7 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~dashboard/assets/scss/_utility-helpers.scss';
|
||||
.page-title {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
<template>
|
||||
<modal :show.sync="show" :on-close="onClose">
|
||||
<div class="column content-box">
|
||||
<woot-modal-header :header-title="$t('IMPORT_CONTACTS.TITLE')">
|
||||
<p>
|
||||
{{ $t('IMPORT_CONTACTS.DESC') }}
|
||||
<a :href="csvUrl" download="import-contacts-sample">{{
|
||||
$t('IMPORT_CONTACTS.DOWNLOAD_LABEL')
|
||||
}}</a>
|
||||
</p>
|
||||
</woot-modal-header>
|
||||
<div class="row modal-content">
|
||||
<div class="medium-12 columns">
|
||||
<label>
|
||||
<span>{{ $t('IMPORT_CONTACTS.FORM.LABEL') }}</span>
|
||||
<input
|
||||
id="file"
|
||||
ref="file"
|
||||
type="file"
|
||||
accept="text/csv"
|
||||
@change="handleFileUpload"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div class="medium-12 columns">
|
||||
<woot-button
|
||||
:disabled="uiFlags.isCreating || !file"
|
||||
:loading="uiFlags.isCreating"
|
||||
@click="uploadFile"
|
||||
>
|
||||
{{ $t('IMPORT_CONTACTS.FORM.SUBMIT') }}
|
||||
</woot-button>
|
||||
<button class="button clear" @click.prevent="onClose">
|
||||
{{ $t('IMPORT_CONTACTS.FORM.CANCEL') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Modal from '../../../../components/Modal';
|
||||
import { mapGetters } from 'vuex';
|
||||
import alertMixin from 'shared/mixins/alertMixin';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Modal,
|
||||
},
|
||||
mixins: [alertMixin],
|
||||
props: {
|
||||
onClose: {
|
||||
type: Function,
|
||||
default: () => {},
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
show: true,
|
||||
file: '',
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
uiFlags: 'contacts/getUIFlags',
|
||||
}),
|
||||
csvUrl() {
|
||||
return '/downloads/import-contacts-sample.csv';
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async uploadFile() {
|
||||
try {
|
||||
if (!this.file) return;
|
||||
await this.$store.dispatch('contacts/import', this.file);
|
||||
this.onClose();
|
||||
this.showAlert(this.$t('IMPORT_CONTACTS.SUCCESS_MESSAGE'));
|
||||
} catch (error) {
|
||||
this.showAlert(
|
||||
error.message || this.$t('IMPORT_CONTACTS.ERROR_MESSAGE')
|
||||
);
|
||||
}
|
||||
},
|
||||
handleFileUpload() {
|
||||
this.file = this.$refs.file.files[0];
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
Reference in New Issue
Block a user