from parks.models import Park, ParkArea from django import forms from django.forms import ModelChoiceField from django.urls import reverse_lazy from .models.company import Company from .models.rides import Ride, RideModel Manufacturer = Company Designer = Company class RideForm(forms.ModelForm): park_search = forms.CharField( label="Park *", required=True, widget=forms.TextInput( attrs={ "class": ( "w-full border-gray-300 rounded-lg form-input " "dark:border-gray-600 dark:bg-gray-700 dark:text-white" ), "placeholder": "Search for a park...", "hx-get": "/parks/search/", "hx-trigger": "click, input delay:200ms", "hx-target": "#park-search-results", "name": "q", "autocomplete": "off", } ), ) manufacturer_search = forms.CharField( label="Manufacturer", required=False, widget=forms.TextInput( attrs={ "class": ( "w-full border-gray-300 rounded-lg form-input " "dark:border-gray-600 dark:bg-gray-700 dark:text-white" ), "placeholder": "Search for a manufacturer...", "hx-get": reverse_lazy("rides:search_companies"), "hx-trigger": "click, input delay:200ms", "hx-target": "#manufacturer-search-results", "name": "q", "autocomplete": "off", } ), ) designer_search = forms.CharField( label="Designer", required=False, widget=forms.TextInput( attrs={ "class": ( "w-full border-gray-300 rounded-lg form-input " "dark:border-gray-600 dark:bg-gray-700 dark:text-white" ), "placeholder": "Search for a designer...", "hx-get": reverse_lazy("rides:search_companies"), "hx-trigger": "click, input delay:200ms", "hx-target": "#designer-search-results", "name": "q", "autocomplete": "off", } ), ) ride_model_search = forms.CharField( label="Ride Model", required=False, widget=forms.TextInput( attrs={ "class": ( "w-full border-gray-300 rounded-lg form-input " "dark:border-gray-600 dark:bg-gray-700 dark:text-white" ), "placeholder": "Search for a ride model...", "hx-get": reverse_lazy("rides:search_ride_models"), "hx-trigger": "click, input delay:200ms", "hx-target": "#ride-model-search-results", "hx-include": "[name='manufacturer']", "name": "q", "autocomplete": "off", } ), ) park = forms.ModelChoiceField( queryset=Park.objects.all(), required=True, label="", widget=forms.HiddenInput(), ) manufacturer = forms.ModelChoiceField( queryset=Manufacturer.objects.all(), required=False, label="", widget=forms.HiddenInput(), ) designer = forms.ModelChoiceField( queryset=Designer.objects.all(), required=False, label="", widget=forms.HiddenInput(), ) ride_model = forms.ModelChoiceField( queryset=RideModel.objects.all(), required=False, label="", widget=forms.HiddenInput(), ) park_area = ModelChoiceField( queryset=ParkArea.objects.none(), required=False, widget=forms.Select( attrs={ "class": ( "w-full border-gray-300 rounded-lg form-select " "dark:border-gray-600 dark:bg-gray-700 dark:text-white" ), "placeholder": "Select an area within the park...", } ), ) class Meta: model = Ride fields = [ "name", "category", "manufacturer", "designer", "ride_model", "status", "post_closing_status", "opening_date", "closing_date", "status_since", "min_height_in", "max_height_in", "capacity_per_hour", "ride_duration_seconds", "description", ] widgets = { "name": forms.TextInput( attrs={ "class": ( "w-full border-gray-300 rounded-lg form-input " "dark:border-gray-600 dark:bg-gray-700 dark:text-white" ), "placeholder": "Official name of the ride", } ), "category": forms.Select( attrs={ "class": ( "w-full border-gray-300 rounded-lg form-select " "dark:border-gray-600 dark:bg-gray-700 dark:text-white" ), "hx-get": reverse_lazy("rides:coaster_fields"), "hx-target": "#coaster-fields", "hx-trigger": "change", "hx-include": "this", "hx-swap": "innerHTML", } ), "status": forms.Select( attrs={ "class": ( "w-full border-gray-300 rounded-lg form-select " "dark:border-gray-600 dark:bg-gray-700 dark:text-white" ), "placeholder": "Current operational status", "x-model": "status", "@change": "handleStatusChange", } ), "post_closing_status": forms.Select( attrs={ "class": ( "w-full border-gray-300 rounded-lg form-select " "dark:border-gray-600 dark:bg-gray-700 dark:text-white" ), "placeholder": "Status after closing", "x-show": "status === 'CLOSING'", } ), "opening_date": forms.DateInput( attrs={ "type": "date", "class": ( "w-full border-gray-300 rounded-lg form-input " "dark:border-gray-600 dark:bg-gray-700 dark:text-white" ), "placeholder": "Date when ride first opened", } ), "closing_date": forms.DateInput( attrs={ "type": "date", "class": ( "w-full border-gray-300 rounded-lg form-input " "dark:border-gray-600 dark:bg-gray-700 dark:text-white" ), "placeholder": "Date when ride will close", "x-show": "['CLOSING', 'SBNO', 'CLOSED_PERM', 'DEMOLISHED', 'RELOCATED'].includes(status)", ":required": "status === 'CLOSING'", } ), "status_since": forms.DateInput( attrs={ "type": "date", "class": ( "w-full border-gray-300 rounded-lg form-input " "dark:border-gray-600 dark:bg-gray-700 dark:text-white" ), "placeholder": "Date when current status took effect", } ), "min_height_in": forms.NumberInput( attrs={ "class": ( "w-full border-gray-300 rounded-lg form-input " "dark:border-gray-600 dark:bg-gray-700 dark:text-white" ), "min": "0", "placeholder": "Minimum height requirement in inches", } ), "max_height_in": forms.NumberInput( attrs={ "class": ( "w-full border-gray-300 rounded-lg form-input " "dark:border-gray-600 dark:bg-gray-700 dark:text-white" ), "min": "0", "placeholder": "Maximum height limit in inches (if applicable)", } ), "capacity_per_hour": forms.NumberInput( attrs={ "class": ( "w-full border-gray-300 rounded-lg form-input " "dark:border-gray-600 dark:bg-gray-700 dark:text-white" ), "min": "0", "placeholder": "Theoretical hourly ride capacity", } ), "ride_duration_seconds": forms.NumberInput( attrs={ "class": ( "w-full border-gray-300 rounded-lg form-input " "dark:border-gray-600 dark:bg-gray-700 dark:text-white" ), "min": "0", "placeholder": "Total duration of one ride cycle in seconds", } ), "description": forms.Textarea( attrs={ "rows": 4, "class": ( "w-full border-gray-300 rounded-lg form-textarea " "dark:border-gray-600 dark:bg-gray-700 dark:text-white" ), "placeholder": "General description and notable features of the ride", } ), } def __init__(self, *args, **kwargs): park = kwargs.pop("park", None) super().__init__(*args, **kwargs) # Make category required self.fields["category"].required = True # Clear any default values for date fields self.fields["opening_date"].initial = None self.fields["closing_date"].initial = None self.fields["status_since"].initial = None # Move fields to the beginning in desired order field_order = [ "park_search", "park", "park_area", "name", "manufacturer_search", "manufacturer", "designer_search", "designer", "ride_model_search", "ride_model", "category", "status", "post_closing_status", "opening_date", "closing_date", "status_since", "min_height_in", "max_height_in", "capacity_per_hour", "ride_duration_seconds", "description", ] self.order_fields(field_order) if park: # If park is provided, set it as the initial value self.fields["park"].initial = park # Hide the park search field since we know the park del self.fields["park_search"] # Create new park_area field with park's areas self.fields["park_area"] = forms.ModelChoiceField( queryset=park.areas.all(), required=False, widget=forms.Select( attrs={ "class": ( "w-full border-gray-300 rounded-lg form-select " "dark:border-gray-600 dark:bg-gray-700 dark:text-white" ), "placeholder": "Select an area within the park...", } ), ) else: # If no park provided, show park search and disable park_area until # park is selected self.fields["park_area"].widget.attrs["disabled"] = True # Initialize park search with current park name if editing if self.instance and self.instance.pk and self.instance.park: self.fields["park_search"].initial = self.instance.park.name self.fields["park"].initial = self.instance.park # Initialize manufacturer, designer, and ride model search fields if # editing if self.instance and self.instance.pk: if self.instance.manufacturer: self.fields["manufacturer_search"].initial = ( self.instance.manufacturer.name ) self.fields["manufacturer"].initial = self.instance.manufacturer if self.instance.designer: self.fields["designer_search"].initial = self.instance.designer.name self.fields["designer"].initial = self.instance.designer if self.instance.ride_model: self.fields["ride_model_search"].initial = self.instance.ride_model.name self.fields["ride_model"].initial = self.instance.ride_model class RideSearchForm(forms.Form): """Form for searching rides with HTMX autocomplete.""" ride = forms.ModelChoiceField( queryset=Ride.objects.all(), label="Find a ride", required=False, widget=forms.Select( attrs={ "class": ( "w-full border-gray-300 rounded-lg form-input " "dark:border-gray-600 dark:bg-gray-700 dark:text-white" ), "hx-get": reverse_lazy("rides:search"), "hx-trigger": "change", "hx-target": "#ride-search-results", } ), )