feat: extract and consolidate common UI patterns across market module

## Component Extraction
  - Create MarketSearchBar component with dual-mode support (enhanced/simple)
    - Enhanced mode: suggestions, keyboard shortcuts, category filters
    - Simple mode: basic search functionality
    - Dynamic imports for performance optimization
  - Extract LoadingErrorState component for consistent loading/error handling
    - Configurable compact/full modes with custom messages
    - Built-in retry functionality
    - Standardized spinner and error displays
  - Consolidate CartButton component (already extracted in previous commit)

  ## UI Standardization
  - Replace inline category badges in StallView with CategoryFilterBar component
  - Add missing state management for category filtering (filterMode, setFilterMode)
  - Ensure consistent filtering UI between MarketPage and StallView
  - Standardize loading states across MarketPage, ProductGrid, and MerchantStore

  ## Code Organization
  - MarketPage: Uses enhanced MarketSearchBar with full feature set
  - StallView: Uses simple MarketSearchBar for cleaner stall-specific search
  - Both views now share CategoryFilterBar, CartButton, and ProductGrid
  - LoadingErrorState provides unified loading/error UX patterns

  ## Technical Improvements
  - Eliminate code duplication following DRY principles
  - Improve maintainability with single source of truth for UI patterns
  - Optimize performance with conditional feature loading
  - Enhance accessibility with consistent keyboard shortcuts and ARIA labels
  - Ensure mobile-responsive designs with unified behavior

  BREAKING CHANGE: MarketFuzzySearch component replaced by MarketSearchBar
This commit is contained in:
padreug 2025-09-27 09:45:33 +02:00
parent 8821f604be
commit c8860dc937
6 changed files with 586 additions and 94 deletions

View file

@ -58,35 +58,33 @@
</Badge>
</div>
<!-- Categories (Enhanced) -->
<div v-if="stallCategories.length > 0" class="flex flex-wrap gap-1">
<Badge
v-for="category in stallCategories"
:key="category"
:variant="selectedCategories.includes(category) ? 'default' : 'secondary'"
class="text-xs px-2 py-0.5 cursor-pointer transition-all duration-200 hover:scale-105 hover:shadow-sm"
:class="{
'bg-gradient-to-r from-primary to-primary/90 text-primary-foreground shadow-md': selectedCategories.includes(category),
'hover:bg-primary/10 hover:border-primary/50': !selectedCategories.includes(category)
}"
@click="toggleCategoryFilter(category)"
>
{{ category }}
</Badge>
</div>
</div>
</div>
</div>
</Card>
</div>
<!-- Category Filter Bar -->
<CategoryFilterBar
v-if="stallCategories.length > 0"
:categories="stallCategories"
:selected-categories="selectedCategories"
:filter-mode="filterMode"
title="Categories"
@toggle-category="toggleCategoryFilter"
@set-filter-mode="setFilterMode"
@clear-filters="clearCategoryFilters"
class="mb-4 sm:mb-6"
/>
<!-- Search and Filter Bar -->
<div class="mb-4 sm:mb-6 flex flex-col sm:flex-row gap-2 sm:gap-4">
<div class="flex-1">
<FuzzySearch
<MarketSearchBar
:data="stallProducts"
:options="searchOptions"
placeholder="Search products in this stall..."
:show-enhancements="false"
@results="handleSearchResults"
class="w-full"
/>
@ -151,9 +149,10 @@ import {
SelectValue,
} from '@/components/ui/select'
import { ArrowLeft, Store, X } from 'lucide-vue-next'
import FuzzySearch from '@/components/ui/fuzzy-search/FuzzySearch.vue'
import MarketSearchBar from '../components/MarketSearchBar.vue'
import ProductGrid from '../components/ProductGrid.vue'
import CartButton from '../components/CartButton.vue'
import CategoryFilterBar from '../components/CategoryFilterBar.vue'
import type { Product, Stall } from '../types/market'
import type { FuzzySearchOptions } from '@/composables/useFuzzySearch'
@ -167,6 +166,7 @@ const searchResults = ref<Product[]>([])
const searchQuery = ref('')
const sortBy = ref('name')
const selectedCategories = ref<string[]>([])
const filterMode = ref<'any' | 'all'>('any')
const logoError = ref(false)
// Fuzzy search configuration for stall products
@ -260,6 +260,14 @@ const toggleCategoryFilter = (category: string) => {
}
}
const setFilterMode = (mode: 'any' | 'all') => {
filterMode.value = mode
}
const clearCategoryFilters = () => {
selectedCategories.value = []
}
const clearFilters = () => {
selectedCategories.value = []
searchResults.value = []