fix: Approved FAQ not disappearing from pending list after filtering (#11909)
# Pull Request Template ## Description This PR fixes an issue where approved FAQs were not removed from the list when filtered by `pending` status. **Fix:** Implemented real-time client-side filtering using a `filteredResponses` computed property in `Index.vue`, updated all list and selection logic to use it, and also hide the card toggle dropdown button when the bulk action checkbox is selected. ## Type of change - [x] Bug fix (non-breaking change which fixes an issue) ## How Has This Been Tested? ### Loom video https://www.loom.com/share/216221a4910c44ebb1d49ab9e34c820c?sid=98c9c239-54eb-4bd9-b04d-aeccc55bfb3a ## Checklist: - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my code - [ ] I have commented on my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] Any dependent changes have been merged and published in downstream modules --------- Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
This commit is contained in:
@@ -55,6 +55,10 @@ const props = defineProps({
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
showMenu: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits(['action', 'navigate', 'select', 'hover']);
|
const emit = defineEmits(['action', 'navigate', 'select', 'hover']);
|
||||||
@@ -130,7 +134,7 @@ const handleDocumentableClick = () => {
|
|||||||
<span class="text-base text-n-slate-12 line-clamp-1">
|
<span class="text-base text-n-slate-12 line-clamp-1">
|
||||||
{{ question }}
|
{{ question }}
|
||||||
</span>
|
</span>
|
||||||
<div v-if="!compact" class="flex items-center gap-2">
|
<div v-if="!compact && showMenu" class="flex items-center gap-2">
|
||||||
<Policy
|
<Policy
|
||||||
v-on-clickaway="() => toggleDropdown(false)"
|
v-on-clickaway="() => toggleDropdown(false)"
|
||||||
:permissions="['administrator']"
|
:permissions="['administrator']"
|
||||||
|
|||||||
@@ -55,6 +55,12 @@ const statusOptions = computed(() =>
|
|||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const filteredResponses = computed(() => {
|
||||||
|
return selectedStatus.value === 'pending'
|
||||||
|
? responses.value.filter(r => r.status === 'pending')
|
||||||
|
: responses.value;
|
||||||
|
});
|
||||||
|
|
||||||
const selectedStatusLabel = computed(() => {
|
const selectedStatusLabel = computed(() => {
|
||||||
const status = statusOptions.value.find(
|
const status = statusOptions.value.find(
|
||||||
option => option.value === selectedStatus.value
|
option => option.value === selectedStatus.value
|
||||||
@@ -94,7 +100,9 @@ const handleEdit = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleAction = ({ action, id }) => {
|
const handleAction = ({ action, id }) => {
|
||||||
selectedResponse.value = responses.value.find(response => id === response.id);
|
selectedResponse.value = filteredResponses.value.find(
|
||||||
|
response => id === response.id
|
||||||
|
);
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
if (action === 'delete') {
|
if (action === 'delete') {
|
||||||
handleDelete();
|
handleDelete();
|
||||||
@@ -139,7 +147,7 @@ const hoveredCard = ref(null);
|
|||||||
|
|
||||||
const bulkSelectionState = computed(() => {
|
const bulkSelectionState = computed(() => {
|
||||||
const selectedCount = bulkSelectedIds.value.size;
|
const selectedCount = bulkSelectedIds.value.size;
|
||||||
const totalCount = responses.value?.length || 0;
|
const totalCount = filteredResponses.value?.length || 0;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
hasSelected: selectedCount > 0,
|
hasSelected: selectedCount > 0,
|
||||||
@@ -152,13 +160,13 @@ const bulkCheckbox = computed({
|
|||||||
get: () => bulkSelectionState.value.allSelected,
|
get: () => bulkSelectionState.value.allSelected,
|
||||||
set: value => {
|
set: value => {
|
||||||
bulkSelectedIds.value = value
|
bulkSelectedIds.value = value
|
||||||
? new Set(responses.value.map(r => r.id))
|
? new Set(filteredResponses.value.map(r => r.id))
|
||||||
: new Set();
|
: new Set();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const buildSelectedCountLabel = computed(() => {
|
const buildSelectedCountLabel = computed(() => {
|
||||||
const count = responses.value?.length || 0;
|
const count = filteredResponses.value?.length || 0;
|
||||||
return bulkSelectionState.value.allSelected
|
return bulkSelectionState.value.allSelected
|
||||||
? t('CAPTAIN.RESPONSES.UNSELECT_ALL', { count })
|
? t('CAPTAIN.RESPONSES.UNSELECT_ALL', { count })
|
||||||
: t('CAPTAIN.RESPONSES.SELECT_ALL', { count });
|
: t('CAPTAIN.RESPONSES.SELECT_ALL', { count });
|
||||||
@@ -174,6 +182,24 @@ const handleCardSelect = id => {
|
|||||||
bulkSelectedIds.value = selected;
|
bulkSelectedIds.value = selected;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const fetchResponseAfterBulkAction = () => {
|
||||||
|
const hasNoResponsesLeft = filteredResponses.value?.length === 0;
|
||||||
|
const currentPage = responseMeta.value?.page;
|
||||||
|
|
||||||
|
if (hasNoResponsesLeft) {
|
||||||
|
// Page is now empty after bulk action.
|
||||||
|
// Fetch the previous page if not already on the first page.
|
||||||
|
const pageToFetch = currentPage > 1 ? currentPage - 1 : currentPage;
|
||||||
|
fetchResponses(pageToFetch);
|
||||||
|
} else {
|
||||||
|
// Page still has responses left, re-fetch the same page.
|
||||||
|
fetchResponses(currentPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear selection
|
||||||
|
bulkSelectedIds.value = new Set();
|
||||||
|
};
|
||||||
|
|
||||||
const handleBulkApprove = async () => {
|
const handleBulkApprove = async () => {
|
||||||
try {
|
try {
|
||||||
await store.dispatch(
|
await store.dispatch(
|
||||||
@@ -181,8 +207,7 @@ const handleBulkApprove = async () => {
|
|||||||
Array.from(bulkSelectedIds.value)
|
Array.from(bulkSelectedIds.value)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Clear selection
|
fetchResponseAfterBulkAction();
|
||||||
bulkSelectedIds.value = new Set();
|
|
||||||
useAlert(t('CAPTAIN.RESPONSES.BULK_APPROVE.SUCCESS_MESSAGE'));
|
useAlert(t('CAPTAIN.RESPONSES.BULK_APPROVE.SUCCESS_MESSAGE'));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
useAlert(
|
useAlert(
|
||||||
@@ -205,23 +230,13 @@ const onPageChange = page => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onDeleteSuccess = () => {
|
const onDeleteSuccess = () => {
|
||||||
if (responses.value?.length === 0 && responseMeta.value?.page > 1) {
|
if (filteredResponses.value?.length === 0 && responseMeta.value?.page > 1) {
|
||||||
onPageChange(responseMeta.value.page - 1);
|
onPageChange(responseMeta.value.page - 1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onBulkDeleteSuccess = () => {
|
const onBulkDeleteSuccess = () => {
|
||||||
// Only fetch if no records left
|
fetchResponseAfterBulkAction();
|
||||||
if (responses.value?.length === 0) {
|
|
||||||
const page =
|
|
||||||
responseMeta.value?.page > 1
|
|
||||||
? responseMeta.value.page - 1
|
|
||||||
: responseMeta.value.page;
|
|
||||||
fetchResponses(page);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear selection
|
|
||||||
bulkSelectedIds.value = new Set();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleStatusFilterChange = ({ value }) => {
|
const handleStatusFilterChange = ({ value }) => {
|
||||||
@@ -249,8 +264,8 @@ onMounted(() => {
|
|||||||
:header-title="$t('CAPTAIN.RESPONSES.HEADER')"
|
:header-title="$t('CAPTAIN.RESPONSES.HEADER')"
|
||||||
:button-label="$t('CAPTAIN.RESPONSES.ADD_NEW')"
|
:button-label="$t('CAPTAIN.RESPONSES.ADD_NEW')"
|
||||||
:is-fetching="isFetching"
|
:is-fetching="isFetching"
|
||||||
:is-empty="!responses.length"
|
:is-empty="!filteredResponses.length"
|
||||||
:show-pagination-footer="!isFetching && !!responses.length"
|
:show-pagination-footer="!isFetching && !!filteredResponses.length"
|
||||||
:feature-flag="FEATURE_FLAGS.CAPTAIN"
|
:feature-flag="FEATURE_FLAGS.CAPTAIN"
|
||||||
@update:current-page="onPageChange"
|
@update:current-page="onPageChange"
|
||||||
@click="handleCreate"
|
@click="handleCreate"
|
||||||
@@ -368,7 +383,7 @@ onMounted(() => {
|
|||||||
|
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<ResponseCard
|
<ResponseCard
|
||||||
v-for="response in responses"
|
v-for="response in filteredResponses"
|
||||||
:id="response.id"
|
:id="response.id"
|
||||||
:key="response.id"
|
:key="response.id"
|
||||||
:question="response.question"
|
:question="response.question"
|
||||||
@@ -380,6 +395,7 @@ onMounted(() => {
|
|||||||
:updated-at="response.updated_at"
|
:updated-at="response.updated_at"
|
||||||
:is-selected="bulkSelectedIds.has(response.id)"
|
:is-selected="bulkSelectedIds.has(response.id)"
|
||||||
:selectable="hoveredCard === response.id || bulkSelectedIds.size > 0"
|
:selectable="hoveredCard === response.id || bulkSelectedIds.size > 0"
|
||||||
|
:show-menu="!bulkSelectedIds.has(response.id)"
|
||||||
@action="handleAction"
|
@action="handleAction"
|
||||||
@navigate="handleNavigationAction"
|
@navigate="handleNavigationAction"
|
||||||
@select="handleCardSelect"
|
@select="handleCardSelect"
|
||||||
|
|||||||
Reference in New Issue
Block a user