website/conservancy/supporters/forms.py

107 lines
3.4 KiB
Python
Raw Normal View History

from django import forms
from django.utils.safestring import mark_safe
from django.urls import reverse
from .models import SustainerOrder
2024-10-23 07:16:47 +00:00
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."""
2024-10-23 07:16:47 +00:00
# Extra <span> 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'
MONTH_OPTIONS = [12, 23, 45, 87]
YEAR_OPTIONS = [128, 256, 512, 1024]
MONTH_MINIMUM = 10
YEAR_MINIMUM = 120
class Meta:
model = SustainerOrder
fields = [
'recurring',
'amount',
'name',
'email',
'acknowledge_publicly',
'add_to_mailing_list',
'tshirt_size',
'street',
'city',
'state',
'zip_code',
'country',
]
widgets = {
2024-10-23 07:16:47 +00:00
'recurring': ButtonRadioSelect(
attrs={
'x-model': 'recurring',
# Reset the amount field and option when changing monthly/annually.
'x-on:change': 'amount = ""; amount_option = null',
}
),
'amount': forms.widgets.NumberInput(
# Keeping default widget, just neater to add many attrs here.
attrs={
# So we can update the amount field from the amount_option selected.
'x-model': 'amount',
'x-bind:min': 'amount_minimum',
'onblur': 'this.reportValidity()',
'style': 'width: 5rem',
2024-10-23 07:16:47 +00:00
}
),
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.renderer = SustainerFormRenderer()
self.fields['recurring'].label = ''
self.fields['amount'].initial = self.YEAR_OPTIONS[0]
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 = self.MONTH_MINIMUM if recurring == 'month' else self.YEAR_MINIMUM
donate_url = reverse('donate')
if amount < minimum:
self.add_error(
'',
2024-10-23 07:16:47 +00:00
mark_safe(
f'${minimum:d} is a minimum for Conservancy Sustainers. <a href="{donate_url}">Donate smaller amounts here</a>.'
),
)
tshirt_size = self.cleaned_data.get('tshirt_size')
2024-10-23 07:16:47 +00:00
if tshirt_size and not all(
[
self.cleaned_data.get('street'),
self.cleaned_data.get('city'),
2024-10-23 07:16:47 +00:00
self.cleaned_data.get('country'),
]
):
self.add_error('street', 'No address provided')