Enhance category filtering in MarketPage and market store
- Added a new function `clearCategoryFilters` in the market store to reset selected category filters. - Updated MarketPage to include an enhanced category filter UI with a clear all button, active filters summary, and improved badge styling for selected categories. - Introduced computed properties for tracking selected categories and their count, improving user experience in managing filters. These changes provide a more intuitive and user-friendly interface for category filtering in the market module.
This commit is contained in:
parent
8aa575ffb1
commit
526caa2689
2 changed files with 93 additions and 9 deletions
|
|
@ -804,6 +804,10 @@ export const useMarketStore = defineStore('market', () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const clearCategoryFilters = () => {
|
||||||
|
filterData.value.categories = []
|
||||||
|
}
|
||||||
|
|
||||||
const updateSortOptions = (field: string, order: 'asc' | 'desc' = 'asc') => {
|
const updateSortOptions = (field: string, order: 'asc' | 'desc' = 'asc') => {
|
||||||
sortOptions.value = { field, order }
|
sortOptions.value = { field, order }
|
||||||
}
|
}
|
||||||
|
|
@ -881,6 +885,7 @@ export const useMarketStore = defineStore('market', () => {
|
||||||
updateFilterData,
|
updateFilterData,
|
||||||
clearFilters,
|
clearFilters,
|
||||||
toggleCategoryFilter,
|
toggleCategoryFilter,
|
||||||
|
clearCategoryFilters,
|
||||||
updateSortOptions,
|
updateSortOptions,
|
||||||
formatPrice,
|
formatPrice,
|
||||||
addToStallCart,
|
addToStallCart,
|
||||||
|
|
|
||||||
|
|
@ -52,19 +52,84 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Category Filters -->
|
<!-- Enhanced Category Filters -->
|
||||||
<div v-if="marketStore.allCategories.length > 0" class="mb-6">
|
<div v-if="marketStore.allCategories.length > 0" class="mb-6">
|
||||||
<div class="flex flex-wrap gap-2">
|
<div class="flex items-center justify-between mb-3">
|
||||||
<Badge
|
<h3 class="text-lg font-semibold text-gray-700">Browse by Category</h3>
|
||||||
|
<Button
|
||||||
|
v-if="selectedCategoriesCount > 0"
|
||||||
|
@click="clearAllCategoryFilters"
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
class="text-sm"
|
||||||
|
>
|
||||||
|
Clear All ({{ selectedCategoriesCount }})
|
||||||
|
<X class="w-4 h-4 ml-1" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-wrap gap-3">
|
||||||
|
<div
|
||||||
v-for="category in marketStore.allCategories"
|
v-for="category in marketStore.allCategories"
|
||||||
:key="category.category"
|
:key="category.category"
|
||||||
:variant="category.selected ? 'default' : 'secondary'"
|
|
||||||
class="cursor-pointer hover:bg-blue-100"
|
|
||||||
@click="marketStore.toggleCategoryFilter(category.category)"
|
@click="marketStore.toggleCategoryFilter(category.category)"
|
||||||
|
class="group relative cursor-pointer transition-all duration-200 hover:scale-105"
|
||||||
>
|
>
|
||||||
{{ category.category }}
|
<Badge
|
||||||
<span class="ml-1 text-xs">({{ category.count }})</span>
|
:variant="category.selected ? 'default' : 'outline'"
|
||||||
|
class="px-4 py-2 text-sm font-medium transition-all duration-200"
|
||||||
|
:class="{
|
||||||
|
'bg-primary text-primary-foreground shadow-md': category.selected,
|
||||||
|
'hover:bg-primary/10 hover:border-primary': !category.selected,
|
||||||
|
'ring-2 ring-primary ring-offset-1': category.selected
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<span>{{ category.category }}</span>
|
||||||
|
<div
|
||||||
|
class="px-2 py-0.5 rounded-full text-xs font-bold transition-colors"
|
||||||
|
:class="category.selected
|
||||||
|
? 'bg-primary-foreground/20 text-primary-foreground'
|
||||||
|
: 'bg-secondary text-secondary-foreground'"
|
||||||
|
>
|
||||||
|
{{ category.count }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</Badge>
|
</Badge>
|
||||||
|
|
||||||
|
<!-- Selection indicator -->
|
||||||
|
<div
|
||||||
|
v-if="category.selected"
|
||||||
|
class="absolute -top-1 -right-1 w-3 h-3 bg-green-500 rounded-full border-2 border-white shadow-sm"
|
||||||
|
>
|
||||||
|
<Check class="w-2 h-2 text-white absolute top-0.5 left-0.5" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Active Filters Summary -->
|
||||||
|
<div v-if="selectedCategoriesCount > 0" class="mt-4 p-3 bg-blue-50 rounded-lg border border-blue-200">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<Filter class="w-4 h-4 text-blue-600" />
|
||||||
|
<span class="text-sm font-medium text-blue-800">
|
||||||
|
Active Filters:
|
||||||
|
</span>
|
||||||
|
<div class="flex gap-1">
|
||||||
|
<Badge
|
||||||
|
v-for="category in selectedCategories"
|
||||||
|
:key="category"
|
||||||
|
variant="secondary"
|
||||||
|
class="text-xs"
|
||||||
|
>
|
||||||
|
{{ category }}
|
||||||
|
</Badge>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-sm text-blue-600">
|
||||||
|
{{ productsToDisplay.length }} products found
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -107,7 +172,7 @@ import { config } from '@/lib/config'
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
import { Badge } from '@/components/ui/badge'
|
import { Badge } from '@/components/ui/badge'
|
||||||
import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/avatar'
|
import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/avatar'
|
||||||
import { ShoppingCart } from 'lucide-vue-next'
|
import { ShoppingCart, X, Check, Filter } from 'lucide-vue-next'
|
||||||
import MarketFuzzySearch from '../components/MarketFuzzySearch.vue'
|
import MarketFuzzySearch from '../components/MarketFuzzySearch.vue'
|
||||||
import ProductCard from '../components/ProductCard.vue'
|
import ProductCard from '../components/ProductCard.vue'
|
||||||
import type { Product } from '../types/market'
|
import type { Product } from '../types/market'
|
||||||
|
|
@ -232,6 +297,20 @@ const handleCategoryFilter = (category: string) => {
|
||||||
marketStore.toggleCategoryFilter(category)
|
marketStore.toggleCategoryFilter(category)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Computed properties for enhanced category filtering
|
||||||
|
const selectedCategoriesCount = computed(() => {
|
||||||
|
return marketStore.filterData.categories.length
|
||||||
|
})
|
||||||
|
|
||||||
|
const selectedCategories = computed(() => {
|
||||||
|
return marketStore.filterData.categories
|
||||||
|
})
|
||||||
|
|
||||||
|
// Clear all category filters
|
||||||
|
const clearAllCategoryFilters = () => {
|
||||||
|
marketStore.clearCategoryFilters()
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// Only load market if it hasn't been preloaded
|
// Only load market if it hasn't been preloaded
|
||||||
if (needsToLoadMarket.value) {
|
if (needsToLoadMarket.value) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue