wikimedia/mediawiki-extensions-DonationInterface

View on GitHub
modules/js/ext.donationInterface.monthlyConvert.js

Summary

Maintainability
B
5 hrs
Test Coverage
( function ( $, mw ) {
    var mc = {},
        currency,
        originalAmount,
        // These config vars are set in GatewayPage::setClientVariables
        tyUrl = mw.config.get( 'wgDonationInterfaceThankYouUrl' ),
        // This is set to the ask amounts for the selected currency, or null
        // if there are no amounts set for it.
        convertAmounts = mw.config.get( 'wgDonationInterfaceMonthlyConvertAmounts' );

    mc.getConvertAsk = function ( amount ) {
        var i,
            numAmounts;
        if ( !convertAmounts ) {
            return 0;
        }
        numAmounts = convertAmounts.length;
        for ( i = 0; i < numAmounts; i++ ) {
            if ( amount <= convertAmounts[ i ][ 0 ] ) {
                return convertAmounts[ i ][ 1 ];
            }
        }
        return 0;
    };

    mc.setConvertAsk = function ( suggestedAmount, currency, locale ) {
        var convertAmountFormatted = mc.formatAmount(
            suggestedAmount, currency, locale
        );
        $( '.mc-convert-ask' ).text( convertAmountFormatted );
        $( '.mc-modal-screen' ).show();
    };

    mc.formatAmount = function ( amount, currency, locale ) {
        var formattedAmount;

        try {
            formattedAmount = amount.toLocaleString(
                locale,
                {
                    currency: currency,
                    style: 'currency'
                }
            );
        } catch ( e ) {
            // Assume a two decimal place currency for fallback
            formattedAmount = currency + ' ' + amount.toFixed( 2 );
        }
        return formattedAmount;
    };

    mc.getSendData = function ( amount ) {
        return {
            action: 'di_recurring_convert',
            format: 'json',
            gateway: $( '#gateway' ).val(),
            wmf_token: $( '#wmf_token' ).val(),
            amount: amount
        };
    };

    mc.postMonthlyConvertDonate = function ( amount, declineMonthlyConvert ) {
        var sendData = mc.getSendData( amount );
        if ( declineMonthlyConvert ) {
            sendData.declineMonthlyConvert = declineMonthlyConvert;
        }
        $.ajax( {
            url: mw.util.wikiScript( 'api' ),
            data: sendData,
            dataType: 'json',
            type: 'POST',
            success: function ( data ) {
                if ( data && !data.error && data.result && !data.result.errors ) {
                    var url = new URL( tyUrl, location.href );
                    if ( !declineMonthlyConvert ) {
                        url.searchParams.set( 'recurringConversion', 1 );
                    }
                    document.location.assign( url.toString() );
                } else {
                    // FIXME - alert sux. Not much donor can do at this point.
                    // We should let 'em know the recurring conversion failed
                    // but the initial donation worked, then show them the thank
                    // you page.
                    if ( !declineMonthlyConvert ) {
                        alert( mw.msg( 'donate_interface-monthly-convert-error' ) );
                    }
                    document.location.assign( tyUrl );
                }
            },
            error: function () {
                // FIXME too
                if ( !declineMonthlyConvert ) {
                    alert( mw.msg( 'donate_interface-monthly-convert-error' ) );
                }
                document.location.assign( tyUrl );
            }
        } );
    };

    mc.setSmallAmountMessageAndMinLocal = function ( currency, locale ) {
        var rates = mw.config.get( 'wgDonationInterfaceCurrencyRates' ),
            amountRules = mw.config.get( 'wgDonationInterfaceAmountRules' ),
            formattedMin,
            $smallAmountMessage = $( '#mc-error-smallamount' );

        if ( currency === amountRules.currency || ( typeof rates[ currency ] ) === 'undefined' ) {
            mc.minLocal = amountRules.min;
        } else {
            // Rates are all relative to USD, so we divide the configured minimum by its corresponding
            // rate to get the minimum in USD, then multiply by the rate of the donation currency to get
            // the minimum in the donation currency.
            mc.minLocal = amountRules.min / rates[ amountRules.currency ] * rates[ currency ];
        }
        formattedMin = mc.formatAmount(
            mc.minLocal, currency, locale
        );
        $smallAmountMessage.text(
            $smallAmountMessage.text().replace( '$1', formattedMin )
        );
    };

    // TODO Unify logic for determining whether or not to show monthly convert. This
    // is just a sanity check to see if the required DOM elements are there.
    mc.canShowModal = function () {
        return $( '.mc-modal-screen' ).length > 0;
    };

    mc.init = function () {
        var presetAmount,
            locale = $( '#language' ).val() + '-' + $( '#country' ).val();
        originalAmount = +$( '#amount' ).val();
        currency = $( '#currency' ).val();
        presetAmount = mc.presetAmount || mc.getConvertAsk( originalAmount );
        if ( presetAmount === 0 && tyUrl !== null ) {
            // They're donating in an unsupported currency, or are
            // outside of the range where it makes sense to ask for
            // a monthly donation. Just send them to the TY page.
            document.location.assign( tyUrl );
        } else {
            mc.presetAmount = presetAmount;
            mc.setConvertAsk(
                presetAmount,
                currency,
                locale
            );
            mc.setSmallAmountMessageAndMinLocal( currency, locale );
            $( '.mc-no-button, .mc-close' ).on( 'click keypress', function ( e ) {
                if ( e.which === 13 || e.type === 'click' ) {
                    mc.postMonthlyConvertDonate( presetAmount, true );
                }
            } );
            $( '.mc-yes-button' ).on( 'click keypress', function ( e ) {
                if ( e.which === 13 || e.type === 'click' ) {
                    mc.postMonthlyConvertDonate( presetAmount );
                }
            } );
            $( '.mc-donate-monthly-button' ).on( 'click keypress', function ( e ) {
                if ( e.which === 13 || e.type === 'click' ) {
                    var $otherAmountField = $( '#mc-other-amount-input' ),
                        otherAmount = +$otherAmountField.val(),
                        $smallAmountMessage = $( '#mc-error-smallamount' );

                    if ( otherAmount < mc.minLocal ) {
                        $otherAmountField.addClass( 'errorHighlight' );
                        $smallAmountMessage.show();
                    } else {
                        $smallAmountMessage.hide();
                        $otherAmountField.removeClass( 'errorHighlight' );
                        mc.postMonthlyConvertDonate( otherAmount );
                    }
                }
            } );
            /* eslint-disable no-jquery/no-fade */
            $( '.mc-diff-amount-link' ).on( 'click keypress', function ( e ) {
                if ( e.which === 13 || e.type === 'click' ) {
                    $( '.mc-choice' ).fadeOut( function () {
                        $( '.mc-edit-amount' ).fadeIn();
                        $( '.mc-back' ).fadeIn();
                        $( '.mc-other-amount-input' ).focus();
                    } );
                }
            } );
            $( '.mc-back' ).on( 'click keypress', function ( e ) {
                if ( e.which === 13 || e.type === 'click' ) {
                    $( '.mc-back' ).fadeOut();
                    $( '.mc-edit-amount' ).fadeOut( function () {
                        $( '.mc-choice' ).fadeIn();
                    } );
                }
            } );
            /* eslint-enable no-jquery/no-fade */
        }

    };
    $( function () {
        if ( mw.config.get( 'showMConStartup' ) ) {
            mc.init();
        }
    } );
    mw.monthlyConvert = mc;
} )( jQuery, mediaWiki );