This is what we did to get the payment buttons to display when the payment value is $0.
The logic is borrowed from CiviDiscount
CiviDiscount apply button refreshes the page, there are 2 processes
- Person fills out the form and applies the code. The page is refreshed and we check the state to determine whether the register button is shown
- The code is applied before the form is filled out completely. We wait for a form valid state.
The conditions to show the buttons are
- If payment form is hidden
- The value is $0
- A discount code is specified
- The form is valid
In conclusion the following is the code. The apply discount button does a page refresh so we can check the value and whether a discount has been applied on page load.There is a watch on this as the inline script that hides the buttons runs after the other scripts. There is also an observer to check whether the form is valid.
CRM.$(function ($) {
'use strict';
function interlatedIsTotalZero() {
var zero = false;
$('.price-set-option-content input').each(function () {
var currentTotal = $(this).data('amount').replace(/[^\/\d]/g, '');
if ($(this).is(':checked') && Number(currentTotal) === 0) {
zero = true;
}
});
return zero;
}
function interlatedCheckFormValid() {
var form = $('#billing-payment-block').closest('form');
return form.valid();
}
// The whole page is reloaded on discount code
function interlatedShowSubmitButtons() {
// Is the payment form shown?
var paymentInformation = document.getElementById('payment_information');
var paymentInformationShown = paymentInformation.style.display;
var submitButtons = $('.crm-submit-buttons', $('#billing-payment-block').closest('form'));
if (interlatedCheckFormValid() && paymentInformationShown === 'none' && $('#discountcode').length > 0 && interlatedIsTotalZero()) {
submitButtons.show();
return true;
}
// Form is not valid or similar.
submitButtons.hide();
return false;
}
// Discount code reloads the whole page. Not a mutation.
interlatedShowSubmitButtons();
// Timing of the jquery to hide the buttons is unpredictable
const buttonsDetectShow = function (mutationsList, observer) {
for (let mutation of mutationsList) {
if (mutation.type !== 'attributes') {
return;
}
var buttonsBlockShown = mutation.target.style.display;
if (buttonsBlockShown === 'none') {
interlatedShowSubmitButtons();
}
}
}
function addObserverIfButtonsAvailable() {
var buttonsEl = $('.crm-submit-buttons', $('#billing-payment-block').closest('form'))[0];
if (!buttonsEl) {
window.setTimeout(addObserverIfButtonsAvailable, 500);
return;
}
interlatedShowSubmitButtons();
observerButtons.observe(buttonsEl, {attributes: true});
}
const observerButtons = new MutationObserver(buttonsDetectShow);
addObserverIfButtonsAvailable();
var recentMutation = new Date().getTime();
// What happens if we show the button but then the form becomes invalid
const formErrorsDetect = function (mutationsList, observer) {
var now = new Date().getTime();
if ((now - recentMutation) < 200) {
return
}
recentMutation = now;
var mutation = mutationsList[0];
if (mutation.type !== 'childList') {
return;
}
if (mutation.target.classList.contains("error")) {
// Show or hide the buttons depending on whether the form is valid
interlatedShowSubmitButtons();
}
}
function addObserverFormErrors() {
$('.crm-profile .crm-section .content ', $('#billing-payment-block').closest('form')).each(function () {
var formEl = $(this)[0];
observerFormErrors.observe(formEl, {childList: true, subtree: true});
});
}
const observerFormErrors = new MutationObserver(formErrorsDetect);
addObserverFormErrors();
});