feat(ui): T5 — DynamicFilter sur Évaluations (mode client-side)
Recherche client/commentaire + chips Note (5★/3–4★/≤2★) + presets ('filter.evaluations'). Prouve le mode CLIENT-SIDE :
le computed `sorted` filtre (matchNote + recherche) puis trie ; réagit à filterState sans rechargement.
Build vert, leak 0.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
4d940eefc4
commit
7def94199c
|
|
@ -10,6 +10,10 @@
|
||||||
<q-btn flat round dense icon="refresh" color="grey-7" :loading="loading" @click="load"><q-tooltip>Rafraîchir</q-tooltip></q-btn>
|
<q-btn flat round dense icon="refresh" color="grey-7" :loading="loading" @click="load"><q-tooltip>Rafraîchir</q-tooltip></q-btn>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Filtre dynamique (client) : recherche client/commentaire + chips note + presets. Le computed `sorted` réagit à filterState. -->
|
||||||
|
<DynamicFilter v-model="filterState" search-placeholder="Client, commentaire…" :chip-groups="chipGroups"
|
||||||
|
preset-key="filter.evaluations" :filtered-count="sorted.length" :total-count="ratings.length" class="q-mb-md" />
|
||||||
|
|
||||||
<div v-if="loading && !ratings.length" class="flex flex-center q-pa-xl"><q-spinner size="36px" color="primary" /></div>
|
<div v-if="loading && !ratings.length" class="flex flex-center q-pa-xl"><q-spinner size="36px" color="primary" /></div>
|
||||||
<div v-else-if="!sorted.length" class="ops-card text-center text-grey-6 q-pa-xl" style="border-radius:12px">
|
<div v-else-if="!sorted.length" class="ops-card text-center text-grey-6 q-pa-xl" style="border-radius:12px">
|
||||||
<q-icon name="reviews" size="40px" color="grey-4" class="q-mb-sm" /><br>
|
<q-icon name="reviews" size="40px" color="grey-4" class="q-mb-sm" /><br>
|
||||||
|
|
@ -69,6 +73,7 @@ import { useQuasar } from 'quasar'
|
||||||
import { HUB_URL } from 'src/config/hub'
|
import { HUB_URL } from 'src/config/hub'
|
||||||
import { formatDateTime } from 'src/composables/useFormatters'
|
import { formatDateTime } from 'src/composables/useFormatters'
|
||||||
import { useConversations } from 'src/composables/useConversations'
|
import { useConversations } from 'src/composables/useConversations'
|
||||||
|
import DynamicFilter from 'src/components/shared/DynamicFilter.vue'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const $q = useQuasar()
|
const $q = useQuasar()
|
||||||
|
|
@ -83,9 +88,14 @@ const sortOptions = [
|
||||||
{ label: 'Étoiles ↓ (hautes d\'abord)', value: 'stars_desc' },
|
{ label: 'Étoiles ↓ (hautes d\'abord)', value: 'stars_desc' },
|
||||||
]
|
]
|
||||||
const dateOf = (r) => String(r.stars_ts || r.comment_ts || r.created || '')
|
const dateOf = (r) => String(r.stars_ts || r.comment_ts || r.created || '')
|
||||||
// Tout afficher (plus de distinction « à traiter ») + tri par date ou par nombre d'étoiles.
|
// Filtre dynamique (client) : recherche client/commentaire + chips note (5★ / 3–4★ / ≤2★).
|
||||||
|
const filterState = ref({ search: '', chips: {} })
|
||||||
|
const chipGroups = [{ key: 'note', label: 'Note', icon: 'star', color: 'amber-7', options: [{ value: '5', label: '5★' }, { value: '34', label: '3–4★' }, { value: '12', label: '≤2★' }] }]
|
||||||
|
function matchNote (r) { const n = filterState.value.chips.note; if (!n) return true; const s = r.stars; if (n === '5') return s >= 5; if (n === '34') return s === 3 || s === 4; if (n === '12') return s != null && s <= 2; return true }
|
||||||
|
// Tout afficher + FILTRE (recherche/note) puis tri (date ou étoiles).
|
||||||
const sorted = computed(() => {
|
const sorted = computed(() => {
|
||||||
const arr = [...ratings.value]
|
const q = (filterState.value.search || '').toLowerCase().trim()
|
||||||
|
const arr = ratings.value.filter(r => matchNote(r) && (!q || String(r.name || r.customerName || r.customer || r.email || '').toLowerCase().includes(q) || String(r.comment || '').toLowerCase().includes(q)))
|
||||||
if (sortKey.value === 'stars_asc') arr.sort((a, b) => (a.stars ?? 99) - (b.stars ?? 99) || dateOf(b).localeCompare(dateOf(a)))
|
if (sortKey.value === 'stars_asc') arr.sort((a, b) => (a.stars ?? 99) - (b.stars ?? 99) || dateOf(b).localeCompare(dateOf(a)))
|
||||||
else if (sortKey.value === 'stars_desc') arr.sort((a, b) => (b.stars ?? -1) - (a.stars ?? -1) || dateOf(b).localeCompare(dateOf(a)))
|
else if (sortKey.value === 'stars_desc') arr.sort((a, b) => (b.stars ?? -1) - (a.stars ?? -1) || dateOf(b).localeCompare(dateOf(a)))
|
||||||
else arr.sort((a, b) => dateOf(b).localeCompare(dateOf(a)))
|
else arr.sort((a, b) => dateOf(b).localeCompare(dateOf(a)))
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user