feat: Enhance parks listing with view mode toggle and search functionality

- Implemented a consolidated search bar for parks with live search capabilities.
- Added view mode toggle between grid and list views for better user experience.
- Updated park listing template to support dynamic rendering based on selected view mode.
- Improved pagination controls with HTMX for seamless navigation.
- Fixed import paths in parks and rides API to resolve 501 errors, ensuring proper functionality.
- Documented changes and integration requirements for frontend compatibility.
This commit is contained in:
pacnpal
2025-08-31 11:39:14 -04:00
parent 5bf351fd2b
commit 91906e0d57
12 changed files with 654 additions and 140 deletions

View File

@@ -36,16 +36,15 @@ from apps.api.v1.serializers.rides import (
# Attempt to import model-level helpers; fall back gracefully if not present.
try:
from apps.rides.models import Ride, RideModel, Company as RideCompany # type: ignore
from apps.parks.models import Park, Company as ParkCompany # type: ignore
from apps.rides.models import Ride, RideModel
from apps.parks.models import Park, Company
MODELS_AVAILABLE = True
except Exception:
Ride = None # type: ignore
RideModel = None # type: ignore
RideCompany = None # type: ignore
Company = None # type: ignore
Park = None # type: ignore
ParkCompany = None # type: ignore
MODELS_AVAILABLE = False
# Attempt to import ModelChoices to return filter options
@@ -630,10 +629,10 @@ class RideDetailAPIView(APIView):
},
status=status.HTTP_501_NOT_IMPLEMENTED,
)
validated_data = serializer_in.validated_data
park_change_info = None
# Handle park change specially if park_id is being updated
if 'park_id' in validated_data:
new_park_id = validated_data.pop('park_id')
@@ -644,21 +643,21 @@ class RideDetailAPIView(APIView):
park_change_info = ride.move_to_park(new_park)
except Park.DoesNotExist: # type: ignore
raise NotFound("Target park not found")
# Apply other field updates
for key, value in validated_data.items():
setattr(ride, key, value)
ride.save()
# Prepare response data
serializer = RideDetailOutputSerializer(ride, context={"request": request})
response_data = serializer.data
# Add park change information to response if applicable
if park_change_info:
response_data['park_change_info'] = park_change_info
return Response(response_data)
def put(self, request: Request, pk: int) -> Response:
@@ -894,7 +893,7 @@ class CompanySearchAPIView(APIView):
if not q:
return Response([], status=status.HTTP_200_OK)
if RideCompany is None:
if Company is None:
# Provide helpful placeholder structure
return Response(
[
@@ -903,7 +902,7 @@ class CompanySearchAPIView(APIView):
]
)
qs = RideCompany.objects.filter(name__icontains=q)[:20] # type: ignore
qs = Company.objects.filter(name__icontains=q)[:20] # type: ignore
results = [
{"id": c.id, "name": c.name, "slug": getattr(c, "slug", "")} for c in qs
]