feat: Add assistant filter support to documents page (#10697)
This PR introduces support for an assistant filter on the documents page. - Moved the existing assistant filter functionality to a standalone, reusable component. - Updated the documents page and responses page to use the component
This commit is contained in:
@@ -6,11 +6,12 @@ class CaptainDocument extends ApiClient {
|
||||
super('captain/documents', { accountScoped: true });
|
||||
}
|
||||
|
||||
get({ page = 1, searchKey } = {}) {
|
||||
get({ page = 1, searchKey, assistantId } = {}) {
|
||||
return axios.get(this.url, {
|
||||
params: {
|
||||
page,
|
||||
searchKey,
|
||||
assistant_id: assistantId,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
<script setup>
|
||||
import { computed, ref } from 'vue';
|
||||
import { useMapGetter } from 'dashboard/composables/store';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { OnClickOutside } from '@vueuse/components';
|
||||
import Button from 'dashboard/components-next/button/Button.vue';
|
||||
import DropdownMenu from 'dashboard/components-next/dropdown-menu/DropdownMenu.vue';
|
||||
|
||||
const props = defineProps({
|
||||
assistantId: {
|
||||
type: [String, Number],
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update']);
|
||||
const { t } = useI18n();
|
||||
const isFilterOpen = ref(false);
|
||||
|
||||
const assistants = useMapGetter('captainAssistants/getRecords');
|
||||
const assistantOptions = computed(() => [
|
||||
{
|
||||
label: t(`CAPTAIN.RESPONSES.FILTER.ALL_ASSISTANTS`),
|
||||
value: 'all',
|
||||
action: 'filter',
|
||||
},
|
||||
...assistants.value.map(assistant => ({
|
||||
value: assistant.id,
|
||||
label: assistant.name,
|
||||
action: 'filter',
|
||||
})),
|
||||
]);
|
||||
|
||||
const selectedAssistantLabel = computed(() => {
|
||||
const assistant = assistantOptions.value.find(
|
||||
option => option.value === props.assistantId
|
||||
);
|
||||
return t('CAPTAIN.RESPONSES.FILTER.ASSISTANT', {
|
||||
selected: assistant ? assistant.label : '',
|
||||
});
|
||||
});
|
||||
|
||||
const handleAssistantFilterChange = ({ value }) => {
|
||||
isFilterOpen.value = false;
|
||||
emit('update', value);
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<OnClickOutside @trigger="isFilterOpen = false">
|
||||
<Button
|
||||
:label="selectedAssistantLabel"
|
||||
icon="i-lucide-chevron-down"
|
||||
size="sm"
|
||||
color="slate"
|
||||
trailing-icon
|
||||
class="max-w-48"
|
||||
@click="isFilterOpen = !isFilterOpen"
|
||||
/>
|
||||
|
||||
<DropdownMenu
|
||||
v-if="isFilterOpen"
|
||||
:menu-items="assistantOptions"
|
||||
class="mt-2"
|
||||
@action="handleAssistantFilterChange"
|
||||
/>
|
||||
</OnClickOutside>
|
||||
</template>
|
||||
@@ -7,7 +7,8 @@ import DocumentCard from 'dashboard/components-next/captain/assistant/DocumentCa
|
||||
import PageLayout from 'dashboard/components-next/captain/PageLayout.vue';
|
||||
import Spinner from 'dashboard/components-next/spinner/Spinner.vue';
|
||||
import RelatedResponses from 'dashboard/components-next/captain/pageComponents/document/RelatedResponses.vue';
|
||||
import CreateDocumentDialog from '../../../../components-next/captain/pageComponents/document/CreateDocumentDialog.vue';
|
||||
import CreateDocumentDialog from 'dashboard/components-next/captain/pageComponents/document/CreateDocumentDialog.vue';
|
||||
import AssistantSelector from 'dashboard/components-next/captain/pageComponents/AssistantSelector.vue';
|
||||
const store = useStore();
|
||||
|
||||
const uiFlags = useMapGetter('captainDocuments/getUIFlags');
|
||||
@@ -15,6 +16,7 @@ const documents = useMapGetter('captainDocuments/getRecords');
|
||||
const assistants = useMapGetter('captainAssistants/getRecords');
|
||||
const isFetching = computed(() => uiFlags.value.fetchingList);
|
||||
const documentsMeta = useMapGetter('captainDocuments/getMeta');
|
||||
const selectedAssistant = ref('all');
|
||||
|
||||
const selectedDocument = ref(null);
|
||||
const deleteDocumentDialog = ref(null);
|
||||
@@ -60,7 +62,17 @@ const handleAction = ({ action, id }) => {
|
||||
};
|
||||
|
||||
const fetchDocuments = (page = 1) => {
|
||||
store.dispatch('captainDocuments/get', { page });
|
||||
const filterParams = { page };
|
||||
|
||||
if (selectedAssistant.value !== 'all') {
|
||||
filterParams.assistantId = selectedAssistant.value;
|
||||
}
|
||||
store.dispatch('captainDocuments/get', filterParams);
|
||||
};
|
||||
|
||||
const handleAssistantFilterChange = assistant => {
|
||||
selectedAssistant.value = assistant;
|
||||
fetchDocuments();
|
||||
};
|
||||
|
||||
const onPageChange = page => fetchDocuments(page);
|
||||
@@ -83,6 +95,12 @@ onMounted(() => {
|
||||
@update:current-page="onPageChange"
|
||||
@click="handleCreateDocument"
|
||||
>
|
||||
<div v-if="!isFetching" class="mb-4 -mt-3 flex gap-3">
|
||||
<AssistantSelector
|
||||
:assistant-id="selectedAssistant"
|
||||
@update="handleAssistantFilterChange"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="isFetching"
|
||||
class="flex items-center justify-center py-10 text-n-slate-11"
|
||||
|
||||
@@ -9,6 +9,7 @@ import DropdownMenu from 'dashboard/components-next/dropdown-menu/DropdownMenu.v
|
||||
|
||||
import DeleteDialog from 'dashboard/components-next/captain/pageComponents/DeleteDialog.vue';
|
||||
import PageLayout from 'dashboard/components-next/captain/PageLayout.vue';
|
||||
import AssistantSelector from 'dashboard/components-next/captain/pageComponents/AssistantSelector.vue';
|
||||
import ResponseCard from 'dashboard/components-next/captain/assistant/ResponseCard.vue';
|
||||
import Spinner from 'dashboard/components-next/spinner/Spinner.vue';
|
||||
import CreateResponseDialog from 'dashboard/components-next/captain/pageComponents/response/CreateResponseDialog.vue';
|
||||
@@ -30,7 +31,6 @@ const { t } = useI18n();
|
||||
const createDialog = ref(null);
|
||||
|
||||
const isStatusFilterOpen = ref(false);
|
||||
const isAssistantFilterOpen = ref(false);
|
||||
|
||||
const statusOptions = computed(() =>
|
||||
['all', 'pending', 'approved'].map(key => ({
|
||||
@@ -49,29 +49,6 @@ const selectedStatusLabel = computed(() => {
|
||||
});
|
||||
});
|
||||
|
||||
const assistants = useMapGetter('captainAssistants/getRecords');
|
||||
const assistantOptions = computed(() => [
|
||||
{
|
||||
label: t(`CAPTAIN.RESPONSES.FILTER.ALL_ASSISTANTS`),
|
||||
value: 'all',
|
||||
action: 'filter',
|
||||
},
|
||||
...assistants.value.map(assistant => ({
|
||||
value: assistant.id,
|
||||
label: assistant.name,
|
||||
action: 'filter',
|
||||
})),
|
||||
]);
|
||||
|
||||
const selectedAssistantLabel = computed(() => {
|
||||
const assistant = assistantOptions.value.find(
|
||||
option => option.value === selectedAssistant.value
|
||||
);
|
||||
return t('CAPTAIN.RESPONSES.FILTER.ASSISTANT', {
|
||||
selected: assistant ? assistant.label : '',
|
||||
});
|
||||
});
|
||||
|
||||
const handleDelete = () => {
|
||||
deleteDialog.value.dialogRef.open();
|
||||
};
|
||||
@@ -122,14 +99,14 @@ const handleCreateClose = () => {
|
||||
};
|
||||
|
||||
const fetchResponses = (page = 1) => {
|
||||
const filterParams = {};
|
||||
const filterParams = { page };
|
||||
if (selectedStatus.value !== 'all') {
|
||||
filterParams.status = selectedStatus.value;
|
||||
}
|
||||
if (selectedAssistant.value !== 'all') {
|
||||
filterParams.assistantId = selectedAssistant.value;
|
||||
}
|
||||
store.dispatch('captainResponses/get', { page, ...filterParams });
|
||||
store.dispatch('captainResponses/get', page);
|
||||
};
|
||||
|
||||
const onPageChange = page => fetchResponses(page);
|
||||
@@ -140,9 +117,8 @@ const handleStatusFilterChange = ({ value }) => {
|
||||
fetchResponses();
|
||||
};
|
||||
|
||||
const handleAssistantFilterChange = ({ value }) => {
|
||||
selectedAssistant.value = value;
|
||||
isAssistantFilterOpen.value = false;
|
||||
const handleAssistantFilterChange = assistant => {
|
||||
selectedAssistant.value = assistant;
|
||||
fetchResponses();
|
||||
};
|
||||
|
||||
@@ -181,25 +157,10 @@ onMounted(() => {
|
||||
@action="handleStatusFilterChange"
|
||||
/>
|
||||
</OnClickOutside>
|
||||
|
||||
<OnClickOutside @trigger="isAssistantFilterOpen = false">
|
||||
<Button
|
||||
:label="selectedAssistantLabel"
|
||||
icon="i-lucide-chevron-down"
|
||||
size="sm"
|
||||
color="slate"
|
||||
trailing-icon
|
||||
class="max-w-48"
|
||||
@click="isAssistantFilterOpen = !isAssistantFilterOpen"
|
||||
/>
|
||||
|
||||
<DropdownMenu
|
||||
v-if="isAssistantFilterOpen"
|
||||
:menu-items="assistantOptions"
|
||||
class="mt-2"
|
||||
@action="handleAssistantFilterChange"
|
||||
/>
|
||||
</OnClickOutside>
|
||||
<AssistantSelector
|
||||
:assistant-id="selectedAssistant"
|
||||
@update="handleAssistantFilterChange"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="isFetching"
|
||||
|
||||
Reference in New Issue
Block a user