Skip to content

Commit 2cf204c

Browse files
committed
feat(View):Implement client-side filtering for comments
1 parent 6f7b508 commit 2cf204c

File tree

2 files changed

+86
-63
lines changed

2 files changed

+86
-63
lines changed

src/components/comments/CommentsFilterForm.vue

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,26 @@ import { useModelRef } from '@/composables/model.composable';
33
import VForm from '../form/VForm.vue';
44
import VInput from '../form/VInput.vue';
55
import { t } from '@/services/language.service';
6+
import VSelect from '../form/VSelect.vue';
67
export default {
78
name: 'CommentsFilterForm',
89
setup() {
910
1011
11-
const filters = useModelRef('modelValue');
12+
const filters = useModelRef('modelValue');
1213
1314
const statusItems = [
1415
{
15-
key:'PENDING',
16-
text:t('Pending')
16+
key: 'PENDING',
17+
text: t('Pending')
1718
},
1819
{
19-
key:'REJECTED',
20-
text:t('Rejected')
20+
key: 'REJECTED',
21+
text: t('Rejected')
2122
},
2223
{
23-
key:'CONFIRMED',
24-
text:t('Confirmed')
24+
key: 'CONFIRMED',
25+
text: t('Confirmed')
2526
}
2627
]
2728
@@ -30,19 +31,33 @@ export default {
3031
statusItems
3132
}
3233
},
34+
props: {
35+
modelValue: {
36+
type: Object,
37+
required: true
38+
}
39+
},
3340
components: {
3441
VForm,
35-
VInput
42+
VInput,
43+
VSelect
3644
},
3745
emits: ['update:modelValue'],
3846
3947
}
4048
</script>
4149

4250
<template>
43-
<VForm class="flex">
51+
<VForm class="row">
4452
<div class="col-3">
4553
<VInput v-model="filters.searchQuery" :placeholder="$t('SearchInputPlaceholder')" id="searchQuery" />
4654
</div>
55+
<div class="col-3">
56+
<VInput v-model="filters.email" :placeholder="$t('EmailPlaceholder')" />
57+
</div>
58+
<div class="col-2">
59+
<VSelect v-model="filters.status" :items="statusItems" item-key="key" item-text="text"
60+
:placeholder="$t('Filter by status')" clearable />
61+
</div>
4762
</VForm>
4863
</template>

src/views/CommentsView.vue

Lines changed: 62 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,45 @@
11
<template>
2-
<div class="h3 mb-4">{{ $t('Comments') }}</div>
3-
<CommentsFilterForm class="mb-4" v-model="filters"/>
4-
<VTableServer :items="comments" :itemsLength="comments.length" :is-loading="commentsIsLoading">
5-
<VColumn :header="$t('Id')" field="id" />
6-
<VColumn :header="$t('Name')" field="name" />
7-
<VColumn :header="$t('Email')" field="email" />
8-
<VColumn :header="$t('Post')" field="postId">
9-
<template #body>
10-
<button class="btn btn-sm btn-outline-info" title="View Related Post">
11-
<i class="bi-eye" />
2+
<div class="h3 mb-4">{{ $t('Comments') }}</div>
3+
<CommentsFilterForm class="mb-4" v-model="filters" />
4+
<VTableServer :items="comments" :itemsLength="comments.length" :is-loading="commentsIsLoading">
5+
<VColumn :header="$t('Id')" field="id" />
6+
<VColumn :header="$t('Name')" field="name" />
7+
<VColumn :header="$t('Email')" field="email" />
8+
<VColumn :header="$t('Post')" field="postId">
9+
<template #body>
10+
<button class="btn btn-sm btn-outline-info" title="View Related Post">
11+
<i class="bi-eye" />
12+
</button>
13+
</template>
14+
</VColumn>
15+
<VColumn :header="$t('Text')" field="body" />
16+
<VColumn :header="$t('Status')" field="id">
17+
<template #body="{ item }">
18+
<span v-if="item.status === 'PENDING'">
19+
{{ $t('Pending') }}
20+
</span>
21+
<span v-if="item.status === 'CONFIRMED'">
22+
{{ $t('Confirmed') }}
23+
</span>
24+
<span v-if="item.status === 'REJECTED'">
25+
{{ $('Rejected') }}
26+
</span>
27+
</template>
28+
</VColumn>
29+
<VColumn :header="$t('Actions')" field="id">
30+
<template #body>
31+
<div class="d-flex gap-2">
32+
<button class="btn btn-danger btn-sm">
33+
<i class="bi-ban" />
1234
</button>
13-
</template>
14-
</VColumn>
15-
<VColumn :header="$t('Text')" field="body" />
16-
<VColumn :header="$t('Status')" field="id">
17-
<template #body="{ item }">
18-
<span v-if="item.status==='PENDING'">
19-
{{ $t('Pending') }}
20-
</span>
21-
<span v-if="item.status==='CONFIRMED'">
22-
{{$t('Confirmed')}}
23-
</span>
24-
<span v-if="item.status==='REJECTED'">
25-
{{ $('Rejected') }}
26-
</span>
27-
</template>
28-
</VColumn>
29-
<VColumn :header="$t('Actions')" field="id">
30-
<template #body>
31-
<div class="d-flex gap-2">
32-
<button class="btn btn-danger btn-sm">
33-
<i class="bi-ban" />
34-
</button>
35-
<button class="btn btn-success btn-sm z-3" data-bs-toggle="tooltip" data-bs-placement="top"
36-
data-bs-title="Tooltip on top">
37-
<i class="bi-check-circle" />
38-
</button>
39-
</div>
40-
</template>
41-
</VColumn>
42-
</VTableServer>
35+
<button class="btn btn-success btn-sm z-3" data-bs-toggle="tooltip" data-bs-placement="top"
36+
data-bs-title="Tooltip on top">
37+
<i class="bi-check-circle" />
38+
</button>
39+
</div>
40+
</template>
41+
</VColumn>
42+
</VTableServer>
4343
</template>
4444

4545
<script>
@@ -48,30 +48,38 @@ import VColumn from '@/components/data-table/VColumn.vue';
4848
import VTableServer from '@/components/data-table/VTableServer.vue';
4949
import { useFetchComments } from '@/composables/comments.composable';
5050
import { useApplyFilters } from '@/composables/filter.composable';
51-
import { watch } from 'vue';
51+
import { computed } from 'vue';
5252
5353
export default {
5454
name: 'CommentsView',
5555
setup() {
5656
const { comments, commentsIsLoading, fetchComments } = useFetchComments()
5757
58-
const filters = useApplyFilters({
59-
querySearch: undefined,
60-
status: undefined,
61-
email: undefined
62-
});
58+
fetchComments({})
6359
60+
const filters = useApplyFilters({
61+
searchQuery: undefined,
62+
status: undefined,
63+
email: undefined
64+
});
65+
66+
const filteredComments = computed(() => {
67+
const enteredEmail = filters?.email && filters.email.trim().toLowerCase();
68+
const query = filters?.searchQuery && isNaN(Number(filters.querySearch)) ? filters.searchQuery.trim().toLowerCase() : undefined;
69+
const status = filters?.status && filters.status.trim();
70+
71+
const matchesEmail = (email) => enteredEmail && email.trim().toLowerCase().includes(enteredEmail)
72+
const matchesQuery = (id,body,name)=> id=== Number(query) || body.trim().toLowerCase().includes(query) || name.trim().toLowerCase().includes(query)
73+
74+
return comments.value?.filter(comment => {
75+
if(!query && !enteredEmail && !status) return true;
76+
return matchesEmail(comment.email) || matchesQuery(comment.id, comment.body, comment.name) || status === comment.status;
77+
});
78+
});
6479
65-
function fetch() {
66-
const config = {}
67-
return fetchComments(config)
68-
}
69-
fetch()
70-
watch([], () => fetchComments())
7180
72-
7381
return {
74-
comments,
82+
comments: filteredComments,
7583
commentsIsLoading,
7684
filters
7785
}

0 commit comments

Comments
 (0)