from django_unicorn.components import UnicornView from django.db.models import Q from django.core.paginator import Paginator from apps.parks.models import Park class ParkSearchView(UnicornView): """ Reactive park search component that replaces HTMX functionality. Provides real-time search, filtering, and view mode switching. """ # Search and filter state search_query: str = "" view_mode: str = "grid" # "grid" or "list" # Results state parks = [] # Use list instead of QuerySet for caching compatibility total_results: int = 0 page: int = 1 per_page: int = 12 # Loading state is_loading: bool = False def mount(self): """Initialize component with all parks""" self.load_parks() def load_parks(self): """Load parks based on current search and filters""" self.is_loading = True # Start with all parks queryset = Park.objects.select_related( 'operator', 'property_owner', 'location' ).prefetch_related('photos') # Apply search filter if self.search_query.strip(): search_terms = self.search_query.strip().split() search_q = Q() for term in search_terms: term_q = ( Q(name__icontains=term) | Q(description__icontains=term) | Q(location__city__icontains=term) | Q(location__state__icontains=term) | Q(location__country__icontains=term) | Q(operator__name__icontains=term) ) search_q &= term_q queryset = queryset.filter(search_q) # Order by name queryset = queryset.order_by('name') # Get total count self.total_results = queryset.count() # Apply pagination paginator = Paginator(queryset, self.per_page) page_obj = paginator.get_page(self.page) # Convert to list for caching compatibility self.parks = list(page_obj.object_list) self.is_loading = False def updated_search_query(self, query): """Called when search query changes""" self.search_query = query self.page = 1 # Reset to first page self.load_parks() def set_view_mode(self, mode): """Switch between grid and list view modes""" if mode in ['grid', 'list']: self.view_mode = mode def clear_search(self): """Clear search query and reload all parks""" self.search_query = "" self.page = 1 self.load_parks() def next_page(self): """Go to next page""" if self.has_next_page(): self.page += 1 self.load_parks() def previous_page(self): """Go to previous page""" if self.has_previous_page(): self.page -= 1 self.load_parks() def go_to_page(self, page_num): """Go to specific page""" if 1 <= page_num <= self.total_pages(): self.page = page_num self.load_parks() def has_next_page(self): """Check if there's a next page""" return self.page < self.total_pages() def has_previous_page(self): """Check if there's a previous page""" return self.page > 1 def total_pages(self): """Calculate total number of pages""" if self.total_results == 0: return 1 return (self.total_results + self.per_page - 1) // self.per_page def get_page_range(self): """Get range of page numbers for pagination""" total = self.total_pages() current = self.page # Show 5 pages around current page start = max(1, current - 2) end = min(total, current + 2) # Adjust if we're near the beginning or end if end - start < 4: if start == 1: end = min(total, start + 4) else: start = max(1, end - 4) return list(range(start, end + 1))