mirror of
https://github.com/lingble/chatwoot.git
synced 2025-10-31 19:17:48 +00:00
--------- Co-authored-by: Pranav <pranavrajs@gmail.com> Co-authored-by: Pranav <pranav@chatwoot.com>
277 lines
8.2 KiB
Vue
277 lines
8.2 KiB
Vue
<script setup>
|
|
import { ref, computed } from 'vue';
|
|
import { useI18n } from 'vue-i18n';
|
|
import { useStore } from 'dashboard/composables/store';
|
|
import { useRouter } from 'vue-router';
|
|
import { useAlert, useTrack } from 'dashboard/composables';
|
|
import { CONTACTS_EVENTS } from 'dashboard/helper/AnalyticsHelper/events';
|
|
import filterQueryGenerator from 'dashboard/helper/filterQueryGenerator';
|
|
import contactFilterItems from 'dashboard/routes/dashboard/contacts/contactFilterItems';
|
|
import { generateValuesForEditCustomViews } from 'dashboard/helper/customViewsHelper';
|
|
import countries from 'shared/constants/countries';
|
|
|
|
import ContactsHeader from 'dashboard/components-next/Contacts/ContactsHeader/ContactHeader.vue';
|
|
import CreateNewContactDialog from 'dashboard/components-next/Contacts/ContactsForm/CreateNewContactDialog.vue';
|
|
import ContactExportDialog from 'dashboard/components-next/Contacts/ContactsForm/ContactExportDialog.vue';
|
|
import ContactImportDialog from 'dashboard/components-next/Contacts/ContactsForm/ContactImportDialog.vue';
|
|
import CreateSegmentDialog from 'dashboard/components-next/Contacts/ContactsForm/CreateSegmentDialog.vue';
|
|
import DeleteSegmentDialog from 'dashboard/components-next/Contacts/ContactsForm/DeleteSegmentDialog.vue';
|
|
import ContactsAdvancedFilters from 'dashboard/routes/dashboard/contacts/components/ContactsAdvancedFilters.vue';
|
|
|
|
const props = defineProps({
|
|
showSearch: {
|
|
type: Boolean,
|
|
default: true,
|
|
},
|
|
searchValue: {
|
|
type: String,
|
|
default: '',
|
|
},
|
|
activeSort: {
|
|
type: String,
|
|
default: 'last_activity_at',
|
|
},
|
|
activeOrdering: {
|
|
type: String,
|
|
default: '',
|
|
},
|
|
headerTitle: {
|
|
type: String,
|
|
default: '',
|
|
},
|
|
segmentsId: {
|
|
type: [String, Number],
|
|
default: 0,
|
|
},
|
|
activeSegment: {
|
|
type: Object,
|
|
default: null,
|
|
},
|
|
hasAppliedFilters: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
});
|
|
|
|
const emit = defineEmits([
|
|
'update:sort',
|
|
'search',
|
|
'applyFilter',
|
|
'clearFilters',
|
|
]);
|
|
|
|
const { t } = useI18n();
|
|
const store = useStore();
|
|
const router = useRouter();
|
|
|
|
const createNewContactDialogRef = ref(null);
|
|
const contactExportDialogRef = ref(null);
|
|
const contactImportDialogRef = ref(null);
|
|
const createSegmentDialogRef = ref(null);
|
|
const deleteSegmentDialogRef = ref(null);
|
|
|
|
const showFiltersModal = ref(false);
|
|
const appliedFilter = ref([]);
|
|
const segmentsQuery = ref({});
|
|
|
|
const hasActiveSegments = computed(
|
|
() => props.activeSegment && props.segmentsId !== 0
|
|
);
|
|
const activeSegmentName = computed(() => props.activeSegment?.name);
|
|
|
|
const contactFilterItemsList = computed(() =>
|
|
contactFilterItems.map(filter => ({
|
|
...filter,
|
|
attributeName: t(`CONTACTS_FILTER.ATTRIBUTES.${filter.attributeI18nKey}`),
|
|
}))
|
|
);
|
|
|
|
const openCreateNewContactDialog = async () => {
|
|
await createNewContactDialogRef.value?.contactsFormRef.resetValidation();
|
|
createNewContactDialogRef.value?.dialogRef.open();
|
|
};
|
|
const openContactImportDialog = () =>
|
|
contactImportDialogRef.value?.dialogRef.open();
|
|
const openContactExportDialog = () =>
|
|
contactExportDialogRef.value?.dialogRef.open();
|
|
const openCreateSegmentDialog = () =>
|
|
createSegmentDialogRef.value?.dialogRef.open();
|
|
const openDeleteSegmentDialog = () =>
|
|
deleteSegmentDialogRef.value?.dialogRef.open();
|
|
|
|
const onCreate = async contact => {
|
|
await store.dispatch('contacts/create', contact);
|
|
createNewContactDialogRef.value?.dialogRef.close();
|
|
};
|
|
|
|
const onImport = async file => {
|
|
try {
|
|
await store.dispatch('contacts/import', file);
|
|
contactImportDialogRef.value?.dialogRef.close();
|
|
useAlert(t('IMPORT_CONTACTS.SUCCESS_MESSAGE'));
|
|
useTrack(CONTACTS_EVENTS.IMPORT_SUCCESS);
|
|
} catch (error) {
|
|
useAlert(error.message ?? t('IMPORT_CONTACTS.ERROR_MESSAGE'));
|
|
useTrack(CONTACTS_EVENTS.IMPORT_FAILURE);
|
|
}
|
|
};
|
|
|
|
const onExport = async query => {
|
|
try {
|
|
await store.dispatch('contacts/export', query);
|
|
useAlert(
|
|
t('CONTACTS_LAYOUT.HEADER.ACTIONS.EXPORT_CONTACT.SUCCESS_MESSAGE')
|
|
);
|
|
} catch (error) {
|
|
useAlert(
|
|
error.message ||
|
|
t('CONTACTS_LAYOUT.HEADER.ACTIONS.EXPORT_CONTACT.ERROR_MESSAGE')
|
|
);
|
|
}
|
|
};
|
|
|
|
const onCreateSegment = async payload => {
|
|
try {
|
|
const payloadData = {
|
|
...payload,
|
|
query: segmentsQuery.value,
|
|
};
|
|
await store.dispatch('customViews/create', payloadData);
|
|
createSegmentDialogRef.value?.dialogRef.close();
|
|
useAlert(
|
|
t('CONTACTS_LAYOUT.HEADER.ACTIONS.FILTERS.CREATE_SEGMENT.SUCCESS_MESSAGE')
|
|
);
|
|
} catch {
|
|
useAlert(
|
|
t('CONTACTS_LAYOUT.HEADER.ACTIONS.FILTERS.CREATE_SEGMENT.ERROR_MESSAGE')
|
|
);
|
|
}
|
|
};
|
|
|
|
const onDeleteSegment = async payload => {
|
|
try {
|
|
await store.dispatch('customViews/delete', {
|
|
id: Number(props.segmentsId),
|
|
...payload,
|
|
});
|
|
router.push({
|
|
name: 'contacts_dashboard_index',
|
|
query: {
|
|
page: 1,
|
|
},
|
|
});
|
|
deleteSegmentDialogRef.value?.dialogRef.close();
|
|
useAlert(
|
|
t('CONTACTS_LAYOUT.HEADER.ACTIONS.FILTERS.DELETE_SEGMENT.SUCCESS_MESSAGE')
|
|
);
|
|
} catch (error) {
|
|
useAlert(
|
|
t('CONTACTS_LAYOUT.HEADER.ACTIONS.FILTERS.DELETE_SEGMENT.ERROR_MESSAGE')
|
|
);
|
|
}
|
|
};
|
|
|
|
const closeAdvanceFiltersModal = () => {
|
|
showFiltersModal.value = false;
|
|
appliedFilter.value = [];
|
|
};
|
|
|
|
const clearFilters = async () => {
|
|
await store.dispatch('contacts/clearContactFilters');
|
|
emit('clearFilters');
|
|
};
|
|
|
|
const onApplyFilter = async payload => {
|
|
segmentsQuery.value = filterQueryGenerator(payload);
|
|
emit('applyFilter', filterQueryGenerator(payload));
|
|
showFiltersModal.value = false;
|
|
};
|
|
|
|
const onUpdateSegment = async (payload, segmentName) => {
|
|
const payloadData = {
|
|
...props.activeSegment,
|
|
name: segmentName,
|
|
query: filterQueryGenerator(payload),
|
|
};
|
|
await store.dispatch('customViews/update', payloadData);
|
|
closeAdvanceFiltersModal();
|
|
};
|
|
|
|
const setParamsForEditSegmentModal = () => {
|
|
return {
|
|
countries,
|
|
filterTypes: contactFilterItems,
|
|
allCustomAttributes:
|
|
store.getters['attributes/getAttributesByModel']('contact_attribute'),
|
|
};
|
|
};
|
|
|
|
const initializeSegmentToFilterModal = segment => {
|
|
const query = segment?.query?.payload;
|
|
if (!Array.isArray(query)) return;
|
|
|
|
appliedFilter.value = query.map(filter => ({
|
|
attribute_key: filter.attribute_key,
|
|
attribute_model: filter.attribute_model,
|
|
filter_operator: filter.filter_operator,
|
|
values: Array.isArray(filter.values)
|
|
? generateValuesForEditCustomViews(filter, setParamsForEditSegmentModal())
|
|
: [],
|
|
query_operator: filter.query_operator,
|
|
custom_attribute_type: filter.custom_attribute_type,
|
|
}));
|
|
};
|
|
|
|
const onToggleFilters = () => {
|
|
appliedFilter.value = [];
|
|
if (hasActiveSegments.value) {
|
|
initializeSegmentToFilterModal(props.activeSegment);
|
|
}
|
|
showFiltersModal.value = true;
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<ContactsHeader
|
|
:show-search="showSearch"
|
|
:search-value="searchValue"
|
|
:active-sort="activeSort"
|
|
:active-ordering="activeOrdering"
|
|
:header-title="headerTitle"
|
|
:is-segments-view="hasActiveSegments"
|
|
:has-active-filters="hasAppliedFilters"
|
|
:button-label="t('CONTACTS_LAYOUT.HEADER.MESSAGE_BUTTON')"
|
|
@search="emit('search', $event)"
|
|
@update:sort="emit('update:sort', $event)"
|
|
@add="openCreateNewContactDialog"
|
|
@import="openContactImportDialog"
|
|
@export="openContactExportDialog"
|
|
@filter="onToggleFilters"
|
|
@create-segment="openCreateSegmentDialog"
|
|
@delete-segment="openDeleteSegmentDialog"
|
|
/>
|
|
|
|
<CreateNewContactDialog ref="createNewContactDialogRef" @create="onCreate" />
|
|
<ContactExportDialog ref="contactExportDialogRef" @export="onExport" />
|
|
<ContactImportDialog ref="contactImportDialogRef" @import="onImport" />
|
|
<CreateSegmentDialog ref="createSegmentDialogRef" @create="onCreateSegment" />
|
|
<DeleteSegmentDialog ref="deleteSegmentDialogRef" @delete="onDeleteSegment" />
|
|
<woot-modal
|
|
v-model:show="showFiltersModal"
|
|
:on-close="closeAdvanceFiltersModal"
|
|
size="medium"
|
|
>
|
|
<ContactsAdvancedFilters
|
|
v-if="showFiltersModal"
|
|
:on-close="closeAdvanceFiltersModal"
|
|
:initial-filter-types="contactFilterItemsList"
|
|
:initial-applied-filters="appliedFilter"
|
|
:active-segment-name="activeSegmentName"
|
|
:is-segments-view="hasActiveSegments"
|
|
@apply-filter="onApplyFilter"
|
|
@update-segment="onUpdateSegment"
|
|
@clear-filters="clearFilters"
|
|
/>
|
|
</woot-modal>
|
|
</template>
|