diff --git a/donations/forms.py b/donations/forms.py
index 155693b39..dac5f9cdc 100644
--- a/donations/forms.py
+++ b/donations/forms.py
@@ -1,26 +1,33 @@
-import json
import base64
+import json
+
from django import forms
from django.utils.safestring import mark_safe
from .models import DonationCampaign
+
class DonateForm(forms.Form):
RADIO_CHOICES = []
donation_type = forms.ChoiceField(
- widget=forms.RadioSelect(), choices=RADIO_CHOICES,
- label=mark_safe('Please choose the name that will appear with the donation:'))
- name_option = forms.CharField(
- required=False, max_length=255, label=False)
+ widget=forms.RadioSelect(),
+ choices=RADIO_CHOICES,
+ label=mark_safe('Please choose the name that will appear with the donation:')
+ )
+ name_option = forms.CharField(required=False, max_length=255, label=False)
amount = forms.FloatField(
- initial=10.0, min_value=0., label=mark_safe('Donation amount (€):'))
- recurring = forms.BooleanField(required=False, initial=False,
- label='I want this to be a recurring monthly donation',)
- show_amount = forms.BooleanField(
- label='Make donated amount public',
- required=False,
- initial=True)
+ initial=10.0,
+ min_value=1,
+ max_value=999999.99, # https://stripe.com/docs/currencies#minimum-and-maximum-charge-amounts
+ label=mark_safe('Donation amount (€):')
+ )
+ recurring = forms.BooleanField(
+ required=False,
+ initial=False,
+ label='I want this to be a recurring monthly donation',
+ )
+ show_amount = forms.BooleanField(label='Make donated amount public', required=False, initial=True)
def __init__(self, *args, **kwargs):
user = kwargs.pop('user', None)
@@ -56,23 +63,14 @@ def __init__(self, *args, **kwargs):
def clean(self):
cleaned_data = super().clean()
- amount = cleaned_data.get('amount')
- try:
- if not amount or float(amount) < 1:
- raise forms.ValidationError('The amount must be more than 1')
- except ValueError:
- raise forms.ValidationError('The amount must be a valid number, use \'.\' for decimals')
campaign = DonationCampaign.objects.order_by('date_start').last()
- returned_data = {
- "campaign_id": campaign.id,
- "display_amount": cleaned_data.get('show_amount')
- }
+ returned_data = {"campaign_id": campaign.id, "display_amount": cleaned_data.get('show_amount')}
annon = cleaned_data.get('donation_type')
- # We store the user even if the donation is annonymous (but don't display the name)
- if self.user_id :
+ # We store the user even if the donation is anonymous (but don't display the name)
+ if self.user_id:
returned_data['user_id'] = self.user_id
if annon == '1':
@@ -82,6 +80,6 @@ def clean(self):
if returned_data['name'] == '':
raise forms.ValidationError('You have to enter a name to display')
- # Paypal gives only one field to add extra data so we send it as b64
+ # Paypal gives only one field to add extra data, so we send it as b64
self.encoded_data = base64.b64encode(json.dumps(returned_data).encode()).decode()
return cleaned_data
diff --git a/freesound/static/bw-frontend/src/pages/donate.js b/freesound/static/bw-frontend/src/pages/donate.js
index 9e09157f5..94b8f036f 100644
--- a/freesound/static/bw-frontend/src/pages/donate.js
+++ b/freesound/static/bw-frontend/src/pages/donate.js
@@ -24,14 +24,34 @@ nameOptionRadioButtons.forEach(element => {
// Disable credit card button if recurring option is checked
recurringCheckboxElement.addEventListener('change', () => {
- if (recurringCheckboxElement.checked) {
- donationButtonCreditCardElement.disabled = true;
- } else {
- donationButtonCreditCardElement.disabled = false;
- }
+ donationButtonCreditCardElement.disabled = !!recurringCheckboxElement.checked;
});
+function handleErrors(errors) {
+ Object.entries(errors).forEach(([key, values]) => {
+ const liElement = document.createElement("li");
+ liElement.innerText = key;
+ const newList = document.createElement("ul");
+ newList.classList.add("errorlist", "v-spacing-3");
+ values.forEach(error => {
+ const newLi = document.createElement("li");
+ newLi.innerText = error;
+ newList.appendChild(newLi);
+ });
+ // if we can find the element with the key as id, we add the error message to it
+ const elemError = document.getElementById(`id_${key}`);
+ if (elemError) {
+ // add an error message below the input field
+ elemError.insertAdjacentElement('afterend', newList);
+ } else {
+ // otherwise, we add it to the general error list (e.g., when key is '__all__')
+ formErrorlistElement.appendChild(liElement);
+ formErrorlistElement.appendChild(newList);
+ }
+ });
+}
+
// Add actions for donate credit card/paypal buttons
donationButtonPaypalElement.addEventListener('click', (event) => {
event.preventDefault(); // Stop propagation of submit event
@@ -43,12 +63,7 @@ donationButtonPaypalElement.addEventListener('click', (event) => {
if (req.status >= 200 && req.status < 300) {
const data = JSON.parse(req.responseText);
if (data.errors != null) {
- formErrorlistElement.innerHTML = '';
- data.errors['__all__'].forEach(error => {
- const liElement = document.createElement("li");
- liElement.innerText = error;
- formErrorlistElement.appendChild(liElement);
- });
+ handleErrors(data.errors);
} else {
const hiddenFormElement = document.createElement("form");
hiddenFormElement.setAttribute("action", data.url);
@@ -68,7 +83,7 @@ donationButtonPaypalElement.addEventListener('click', (event) => {
}
}
req.onerror = () => {
- // Unexpected errors happened while processing request: how error in toast
+ // Unexpected errors happened while processing request: show error in toast
showToast('Some errors occurred while processing the form. Please try again later.')
};
req.send(params); // Send request
@@ -87,12 +102,7 @@ donationButtonCreditCardElement.addEventListener('click', (event) => {
if (req.status >= 200 && req.status < 300) {
const data = JSON.parse(req.responseText);
if (data.errors != null) {
- formErrorlistElement.innerHTML = '';
- data.errors['__all__'].forEach(error => {
- const liElement = document.createElement("li");
- liElement.innerText = error;
- formErrorlistElement.appendChild(liElement);
- });
+ handleErrors(data.errors)
} else {
const session = data.session_id;
stripe.redirectToCheckout({
@@ -112,4 +122,3 @@ donationButtonCreditCardElement.addEventListener('click', (event) => {
};
req.send(params); // Send request
});
-