from django import forms from django.utils import timezone from .models import Event, Registration class EventSearchForm(forms.Form): q = forms.CharField( required=False, max_length=80, label='Search', widget=forms.TextInput( attrs={ 'placeholder': 'Search by title, venue, or keyword', 'class': 'form-control form-control-lg', } ), ) class RegistrationForm(forms.ModelForm): class Meta: model = Registration fields = ['full_name', 'email', 'company', 'notes'] widgets = { 'full_name': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Jordan Lee'}), 'email': forms.EmailInput(attrs={'class': 'form-control', 'placeholder': 'you@example.com'}), 'company': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Studio North'}), 'notes': forms.Textarea(attrs={'class': 'form-control', 'rows': 4, 'placeholder': 'Accessibility needs, dietary notes, or questions'}), } def __init__(self, *args, event=None, **kwargs): self.event = event super().__init__(*args, **kwargs) for field in self.fields.values(): css = field.widget.attrs.get('class', '') if 'form-control' not in css: field.widget.attrs['class'] = f'{css} form-control'.strip() def clean_email(self): email = self.cleaned_data['email'].strip().lower() if self.event and Registration.objects.filter(event=self.event, email__iexact=email).exists(): raise forms.ValidationError('This email is already registered for this event.') return email class OrganizerEventForm(forms.ModelForm): datetime_format = '%Y-%m-%dT%H:%M' class Meta: model = Event fields = [ 'title', 'summary', 'description', 'venue', 'start_at', 'end_at', 'capacity', 'is_published', 'registration_opens', 'registration_closes', ] widgets = { 'title': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Spring Product Launch'}), 'summary': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'A short one-line overview for the catalog card.'}), 'description': forms.Textarea(attrs={'class': 'form-control', 'rows': 6, 'placeholder': 'Describe the agenda, audience, and what attendees should expect.'}), 'venue': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Northstar Studio, Austin'}), 'start_at': forms.DateTimeInput(format='%Y-%m-%dT%H:%M', attrs={'class': 'form-control', 'type': 'datetime-local'}), 'end_at': forms.DateTimeInput(format='%Y-%m-%dT%H:%M', attrs={'class': 'form-control', 'type': 'datetime-local'}), 'capacity': forms.NumberInput(attrs={'class': 'form-control', 'placeholder': 'Optional'}), 'is_published': forms.CheckboxInput(attrs={'class': 'form-check-input'}), 'registration_opens': forms.DateTimeInput(format='%Y-%m-%dT%H:%M', attrs={'class': 'form-control', 'type': 'datetime-local'}), 'registration_closes': forms.DateTimeInput(format='%Y-%m-%dT%H:%M', attrs={'class': 'form-control', 'type': 'datetime-local'}), } def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) for field_name in ('start_at', 'end_at', 'registration_opens', 'registration_closes'): self.fields[field_name].input_formats = [self.datetime_format] value = self.initial.get(field_name) if value: self.initial[field_name] = timezone.localtime(value).strftime(self.datetime_format) for field in self.fields.values(): css = field.widget.attrs.get('class', '') if isinstance(field.widget, forms.CheckboxInput): field.widget.attrs['class'] = 'form-check-input' elif 'form-control' not in css: field.widget.attrs['class'] = f'{css} form-control'.strip() self.fields['capacity'].required = False self.fields['registration_opens'].required = False self.fields['registration_closes'].required = False self.fields['is_published'].required = False def clean(self): cleaned_data = super().clean() start_at = cleaned_data.get('start_at') end_at = cleaned_data.get('end_at') registration_opens = cleaned_data.get('registration_opens') registration_closes = cleaned_data.get('registration_closes') capacity = cleaned_data.get('capacity') if start_at and end_at and end_at <= start_at: self.add_error('end_at', 'End time must be after the event start time.') if registration_opens and start_at and registration_opens > start_at: self.add_error('registration_opens', 'Registration should open before the event begins.') if registration_closes and start_at and registration_closes > start_at: self.add_error('registration_closes', 'Registration should close before the event begins.') if registration_opens and registration_closes and registration_closes <= registration_opens: self.add_error('registration_closes', 'Registration close must be after registration open.') if capacity is not None and capacity < 1: self.add_error('capacity', 'Capacity must be at least 1 when provided.') return cleaned_data