feat: New contacts advanced filter (#10514)

This commit is contained in:
Sivin Varghese
2024-11-29 10:55:15 +05:30
committed by GitHub
parent a50e4f1748
commit 1c12fbceb9
9 changed files with 643 additions and 117 deletions

View File

@@ -81,21 +81,25 @@ const emit = defineEmits([
</Input>
</div>
<div class="flex items-center gap-2">
<Button
:icon="
isSegmentsView ? 'i-lucide-pen-line' : 'i-lucide-list-filter'
"
color="slate"
size="sm"
class="relative"
variant="ghost"
@click="emit('filter')"
>
<div
v-if="hasActiveFilters && !isSegmentsView"
class="absolute top-0 right-0 w-2 h-2 rounded-full bg-n-brand"
/>
</Button>
<div class="relative">
<Button
id="toggleContactsFilterButton"
:icon="
isSegmentsView ? 'i-lucide-pen-line' : 'i-lucide-list-filter'
"
color="slate"
size="sm"
class="relative"
variant="ghost"
@click="emit('filter')"
>
<div
v-if="hasActiveFilters && !isSegmentsView"
class="absolute top-0 right-0 w-2 h-2 rounded-full bg-n-brand"
/>
</Button>
<slot name="filter" />
</div>
<Button
v-if="hasActiveFilters && !isSegmentsView"
icon="i-lucide-save"

View File

@@ -1,7 +1,7 @@
<script setup>
import { ref, computed } from 'vue';
import { ref, computed, unref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useStore } from 'dashboard/composables/store';
import { useStore, useMapGetter } from 'dashboard/composables/store';
import { useRouter } from 'vue-router';
import { useAlert, useTrack } from 'dashboard/composables';
import { CONTACTS_EVENTS } from 'dashboard/helper/AnalyticsHelper/events';
@@ -9,6 +9,10 @@ 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 {
useCamelCase,
useSnakeCase,
} from 'dashboard/composables/useTransformKeys';
import ContactsHeader from 'dashboard/components-next/Contacts/ContactsHeader/ContactHeader.vue';
import CreateNewContactDialog from 'dashboard/components-next/Contacts/ContactsForm/CreateNewContactDialog.vue';
@@ -16,7 +20,7 @@ import ContactExportDialog from 'dashboard/components-next/Contacts/ContactsForm
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';
import ContactsFilter from 'dashboard/components-next/filter/ContactsFilter.vue';
const props = defineProps({
showSearch: {
@@ -74,18 +78,13 @@ const showFiltersModal = ref(false);
const appliedFilter = ref([]);
const segmentsQuery = ref({});
const appliedFilters = useMapGetter('contacts/getAppliedContactFiltersV4');
const contactAttributes = useMapGetter('attributes/getContactAttributes');
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();
@@ -182,12 +181,14 @@ const clearFilters = async () => {
};
const onApplyFilter = async payload => {
payload = useSnakeCase(payload);
segmentsQuery.value = filterQueryGenerator(payload);
emit('applyFilter', filterQueryGenerator(payload));
showFiltersModal.value = false;
};
const onUpdateSegment = async (payload, segmentName) => {
payload = useSnakeCase(payload);
const payloadData = {
...props.activeSegment,
name: segmentName,
@@ -201,31 +202,52 @@ const setParamsForEditSegmentModal = () => {
return {
countries,
filterTypes: contactFilterItems,
allCustomAttributes:
store.getters['attributes/getAttributesByModel']('contact_attribute'),
allCustomAttributes: useSnakeCase(contactAttributes.value),
};
};
const initializeSegmentToFilterModal = segment => {
const query = segment?.query?.payload;
const query = unref(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 newFilters = query.map(filter => {
const transformed = useCamelCase(filter);
const values = Array.isArray(transformed.values)
? generateValuesForEditCustomViews(
useSnakeCase(filter),
setParamsForEditSegmentModal()
)
: [];
return {
attributeKey: transformed.attributeKey,
attributeModel: transformed.attributeModel,
customAttributeType: transformed.customAttributeType,
filterOperator: transformed.filterOperator,
queryOperator: transformed.queryOperator ?? 'and',
values,
};
});
appliedFilter.value = [...appliedFilter.value, ...newFilters];
};
const onToggleFilters = () => {
appliedFilter.value = [];
if (hasActiveSegments.value) {
initializeSegmentToFilterModal(props.activeSegment);
} else {
appliedFilter.value = props.hasAppliedFilters
? [...appliedFilters.value]
: [
{
attributeKey: 'name',
filterOperator: 'equal_to',
values: '',
queryOperator: 'and',
attributeModel: 'standard',
},
];
}
showFiltersModal.value = true;
};
@@ -249,28 +271,25 @@ const onToggleFilters = () => {
@filter="onToggleFilters"
@create-segment="openCreateSegmentDialog"
@delete-segment="openDeleteSegmentDialog"
/>
>
<template #filter>
<ContactsFilter
v-if="showFiltersModal"
v-model="appliedFilter"
:segment-name="activeSegmentName"
:is-segment-view="hasActiveSegments"
class="absolute mt-1 ltr:right-0 rtl:left-0 top-full"
@apply-filter="onApplyFilter"
@update-segment="onUpdateSegment"
@close="closeAdvanceFiltersModal"
@clear-filters="clearFilters"
/>
</template>
</ContactsHeader>
<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>