from django import forms from django.utils.safestring import mark_safe from django.urls import reverse from .models import SustainerOrder MONTH_MINIMUM = 10 YEAR_MINIMUM = 120 class SustainerFormRenderer(forms.renderers.DjangoTemplates): # Customised layout with labels on own row field_template_name = 'supporters/field.html' class ButtonRadioSelect(forms.widgets.RadioSelect): """Radio button styled like a button. BYO CSS.""" # Extra wrappers to support CSS option_template_name = 'supporters/buttonradio_option.html' use_fieldset = False class Media: css = { 'all': ['css/buttonradio.css'], } def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.attrs['class'] = 'button-select' class SustainerForm(forms.ModelForm): # Used to pre-fill the price selector amount_option = forms.CharField(required=False) template_name = 'supporters/sustainer_form.html' class Meta: model = SustainerOrder fields = [ 'recurring', 'amount', 'name', 'email', 'acknowledge_publicly', 'add_to_mailing_list', 'tshirt_size', 'street', 'city', 'state', 'zip_code', 'country', ] widgets = { 'recurring': ButtonRadioSelect(attrs={ 'x-model': 'recurring', # Reset the amount field and option when changing monthly/annually. 'x-on:change': '$refs.amount.value = null; amount_option = null', }), } def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.renderer = SustainerFormRenderer() self.fields['recurring'].label = '' # So we can write to this field easily from Alpine JS. self.fields['amount'].widget.attrs['x-ref'] = 'amount' self.fields['amount'].widget.attrs['style'] = 'width: 5rem' self.fields['email'].help_text = 'For your payment receipt' self.fields['tshirt_size'].help_text = mark_safe("""Sizing chart: Women's, Men's""") self.fields['tshirt_size'].widget.attrs['x-model'] = 'tshirt_size' def clean(self): super().clean() recurring = self.cleaned_data.get('recurring', '') amount = self.cleaned_data.get('amount', 0) minimum = MONTH_MINIMUM if recurring == 'month' else YEAR_MINIMUM donate_url = reverse('donate') if amount < minimum: self.add_error( '', mark_safe(f'${minimum:d} is a minimum for Conservancy Sustainers. Donate smaller amounts here.') ) tshirt_size = self.cleaned_data.get('tshirt_size') if tshirt_size and not all([ self.cleaned_data.get('street'), self.cleaned_data.get('city'), self.cleaned_data.get('country') ]): self.add_error( 'street', 'No address provided' )