feat: Implement comprehensive ride filtering system with API integration

- Added `useRideFiltering` composable for managing ride filters and fetching rides from the API.
- Created `useParkRideFiltering` for park-specific ride filtering.
- Developed `useTheme` composable for theme management with localStorage support.
- Established `rideFiltering` Pinia store for centralized state management of ride filters and UI state.
- Defined enhanced filter types in `filters.ts` for better type safety and clarity.
- Built `RideFilteringPage.vue` to provide a user interface for filtering rides with responsive design.
- Integrated filter sidebar and ride list display components for a cohesive user experience.
- Added support for filter presets and search suggestions.
- Implemented computed properties for active filters, average ratings, and operating counts.
This commit is contained in:
pacnpal
2025-08-25 12:03:22 -04:00
parent dcf890a55c
commit bf7e0c0f40
37 changed files with 9350 additions and 143 deletions

View File

@@ -9,6 +9,8 @@ from django.db.models import Count
from .models.rides import Ride, RideModel, Categories
from .models.company import Company
from .forms import RideForm, RideSearchForm
from .forms.search import MasterFilterForm
from .services.search import RideSearchService
from apps.parks.models import Park
from apps.moderation.mixins import EditSubmissionMixin, HistoryMixin
from apps.moderation.models import EditSubmission
@@ -213,66 +215,81 @@ class RideUpdateView(
class RideListView(ListView):
"""View for displaying a list of rides"""
"""Enhanced view for displaying a list of rides with advanced filtering"""
model = Ride
template_name = "rides/ride_list.html"
context_object_name = "rides"
paginate_by = 24
def get_queryset(self):
"""Get filtered rides based on search and filters"""
queryset = (
Ride.objects.all()
.select_related("park", "ride_model", "ride_model__manufacturer")
.prefetch_related("photos")
)
"""Get filtered rides using the advanced search service"""
# Initialize search service
search_service = RideSearchService()
# Park filter
# Parse filters from request
filter_form = MasterFilterForm(self.request.GET)
# Apply park context if available
park = None
if "park_slug" in self.kwargs:
self.park = get_object_or_404(Park, slug=self.kwargs["park_slug"])
queryset = queryset.filter(park=self.park)
park = self.park
# Search term handling
search = self.request.GET.get("q", "").strip()
if search:
# Split search terms for more flexible matching
search_terms = search.split()
search_query = Q()
for term in search_terms:
term_query = (
Q(name__icontains=term)
| Q(park__name__icontains=term)
| Q(description__icontains=term)
)
search_query &= term_query
queryset = queryset.filter(search_query)
# Category filter
category = self.request.GET.get("category")
if category and category != "all":
queryset = queryset.filter(category=category)
# Operating status filter
if self.request.GET.get("operating") == "true":
queryset = queryset.filter(status="operating")
if filter_form.is_valid():
# Use advanced search service
queryset = search_service.search_rides(
filters=filter_form.get_filter_dict(), park=park
)
else:
# Fallback to basic queryset with park filter
queryset = (
Ride.objects.all()
.select_related("park", "ride_model", "ride_model__manufacturer")
.prefetch_related("photos")
)
if park:
queryset = queryset.filter(park=park)
return queryset
def get_template_names(self):
"""Return appropriate template based on request type"""
if self.request.htmx:
if hasattr(self.request, "htmx") and self.request.htmx:
return ["rides/partials/ride_list_results.html"]
return [self.template_name]
def get_context_data(self, **kwargs):
"""Add park and category choices to context"""
"""Add filter form and context data"""
context = super().get_context_data(**kwargs)
# Add park context
if hasattr(self, "park"):
context["park"] = self.park
context["park_slug"] = self.kwargs["park_slug"]
# Add filter form
filter_form = MasterFilterForm(self.request.GET)
context["filter_form"] = filter_form
context["category_choices"] = Categories
# Add filter summary for display
if filter_form.is_valid():
context["active_filters"] = filter_form.get_filter_summary()
context["has_filters"] = filter_form.has_active_filters()
else:
context["active_filters"] = {}
context["has_filters"] = False
# Add total count before filtering (for display purposes)
if hasattr(self, "park"):
context["total_rides"] = Ride.objects.filter(park=self.park).count()
else:
context["total_rides"] = Ride.objects.count()
# Add filtered count
context["filtered_count"] = self.get_queryset().count()
return context
@@ -457,7 +474,7 @@ class RideSearchView(ListView):
class RideRankingsView(ListView):
"""View for displaying ride rankings using the Internet Roller Coaster Poll algorithm."""
"""View for displaying ride rankings using the Internet Roller Coaster Poll."""
model = RideRanking
template_name = "rides/rankings.html"