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:
Sivin Varghese
2025-07-12 10:06:30 +05:30
committed by GitHub
parent 5b9f997fa0
commit 1b02ebec68
2 changed files with 42 additions and 22 deletions

View File

@@ -55,6 +55,10 @@ const props = defineProps({
type: Boolean,
default: false,
},
showMenu: {
type: Boolean,
default: true,
},
});
const emit = defineEmits(['action', 'navigate', 'select', 'hover']);
@@ -130,7 +134,7 @@ const handleDocumentableClick = () => {
<span class="text-base text-n-slate-12 line-clamp-1">
{{ question }}
</span>
<div v-if="!compact" class="flex items-center gap-2">
<div v-if="!compact && showMenu" class="flex items-center gap-2">
<Policy
v-on-clickaway="() => toggleDropdown(false)"
:permissions="['administrator']"

View File

@@ -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 status = statusOptions.value.find(
option => option.value === selectedStatus.value
@@ -94,7 +100,9 @@ const handleEdit = () => {
};
const handleAction = ({ action, id }) => {
selectedResponse.value = responses.value.find(response => id === response.id);
selectedResponse.value = filteredResponses.value.find(
response => id === response.id
);
nextTick(() => {
if (action === 'delete') {
handleDelete();
@@ -139,7 +147,7 @@ const hoveredCard = ref(null);
const bulkSelectionState = computed(() => {
const selectedCount = bulkSelectedIds.value.size;
const totalCount = responses.value?.length || 0;
const totalCount = filteredResponses.value?.length || 0;
return {
hasSelected: selectedCount > 0,
@@ -152,13 +160,13 @@ const bulkCheckbox = computed({
get: () => bulkSelectionState.value.allSelected,
set: value => {
bulkSelectedIds.value = value
? new Set(responses.value.map(r => r.id))
? new Set(filteredResponses.value.map(r => r.id))
: new Set();
},
});
const buildSelectedCountLabel = computed(() => {
const count = responses.value?.length || 0;
const count = filteredResponses.value?.length || 0;
return bulkSelectionState.value.allSelected
? t('CAPTAIN.RESPONSES.UNSELECT_ALL', { count })
: t('CAPTAIN.RESPONSES.SELECT_ALL', { count });
@@ -174,6 +182,24 @@ const handleCardSelect = id => {
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 () => {
try {
await store.dispatch(
@@ -181,8 +207,7 @@ const handleBulkApprove = async () => {
Array.from(bulkSelectedIds.value)
);
// Clear selection
bulkSelectedIds.value = new Set();
fetchResponseAfterBulkAction();
useAlert(t('CAPTAIN.RESPONSES.BULK_APPROVE.SUCCESS_MESSAGE'));
} catch (error) {
useAlert(
@@ -205,23 +230,13 @@ const onPageChange = page => {
};
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);
}
};
const onBulkDeleteSuccess = () => {
// Only fetch if no records left
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();
fetchResponseAfterBulkAction();
};
const handleStatusFilterChange = ({ value }) => {
@@ -249,8 +264,8 @@ onMounted(() => {
:header-title="$t('CAPTAIN.RESPONSES.HEADER')"
:button-label="$t('CAPTAIN.RESPONSES.ADD_NEW')"
:is-fetching="isFetching"
:is-empty="!responses.length"
:show-pagination-footer="!isFetching && !!responses.length"
:is-empty="!filteredResponses.length"
:show-pagination-footer="!isFetching && !!filteredResponses.length"
:feature-flag="FEATURE_FLAGS.CAPTAIN"
@update:current-page="onPageChange"
@click="handleCreate"
@@ -368,7 +383,7 @@ onMounted(() => {
<div class="flex flex-col gap-4">
<ResponseCard
v-for="response in responses"
v-for="response in filteredResponses"
:id="response.id"
:key="response.id"
:question="response.question"
@@ -380,6 +395,7 @@ onMounted(() => {
:updated-at="response.updated_at"
:is-selected="bulkSelectedIds.has(response.id)"
:selectable="hoveredCard === response.id || bulkSelectedIds.size > 0"
:show-menu="!bulkSelectedIds.has(response.id)"
@action="handleAction"
@navigate="handleNavigationAction"
@select="handleCardSelect"