在 Braintree 中使用托管字段时获取信用卡品牌并显示错误消息

Getting credit card brand and show error message when using hosted fields in Braintree

我正在尝试使用 braintree 的托管字段创建支付页面。 我已经创建了沙盒帐户。

但我没有收到其他详细信息,例如卡片品牌、Drop in UI 等错误消息。 如何使用托管字段获得这些功能。

import React from 'react';

var braintree = require('braintree-web');


class BillingComponent extends React.Component {
    constructor(props) {
        super(props);
        this.clientDidCreate = this.clientDidCreate.bind(this);
        this.hostedFieldsDidCreate = this.hostedFieldsDidCreate.bind(this);
        this.submitHandler = this.submitHandler.bind(this);
        this.showPaymentPage = this.showPaymentPage.bind(this);
        this.state = {
            hostedFields: null,
            errorOccurred: false,
        };
    }

    componentDidCatch(error, info) {
        this.setState({errorOccurred: true});
    }


    componentDidMount() {
        this.showPaymentPage();
    }

    showPaymentPage() {
        braintree.client.create({
            authorization: 'sandbox_xxxxx_xxxxxxx'
        }, this.clientDidCreate);
    }


    clientDidCreate(err, client) {
        braintree.hostedFields.create({
            onFieldEvent: function (event) {console.log(JSON.stringify(event))},
            client: client,
            styles: {
                'input': {
                    'font-size': '16pt',
                    'color': '#020202'
                },

                '.number': {
                    'font-family': 'monospace'
                },

                '.valid': {
                    'color': 'green'
                }
            },
            fields: {
                number: {
                    selector: '#card-number',
                    'card-brand-id': true,
                    supportedCardBrands: 'visa'
                },
                cvv: {
                    selector: '#cvv',
                    type: 'password'
                },
                expirationDate: {
                    selector: '#expiration-date',
                    prefill: "12/21"
                }
            }
        }, this.hostedFieldsDidCreate);
    }

    hostedFieldsDidCreate(err, hostedFields) {
        let submitBtn = document.getElementById('my-submit');
        this.setState({hostedFields: hostedFields});
        submitBtn.addEventListener('click', this.submitHandler);
        submitBtn.removeAttribute('disabled');
    }

    submitHandler(event) {
        let submitBtn = document.getElementById('my-submit');

        event.preventDefault();
        submitBtn.setAttribute('disabled', 'disabled');

        this.state.hostedFields.tokenize(
            function (err, payload) {
            if (err) {
                submitBtn.removeAttribute('disabled');
                console.error(err);
            }
            else {
                let form = document.getElementById('my-sample-form');
                form['payment_method_nonce'].value = payload.nonce;
                alert(payload.nonce);
                // form.submit();
            }
        });
    }

    render() {
        return (
            <div className="user-prelogin">
                <div className="row gutter-reset">
                    <div className="col">
                        <div className="prelogin-container">
                            <form action="/" id="my-sample-form">
                                <input type="hidden" name="payment_method_nonce"/>
                                <label htmlFor="card-number">Card Number</label>
                                <div className="form-control" id="card-number"></div>

                                <label htmlFor="cvv">CVV</label>
                                <div className="form-control" id="cvv"></div>

                                <label htmlFor="expiration-date">Expiration Date</label>
                                <div className="form-control" id="expiration-date"></div>
                                <input id="my-submit" type="submit" value="Pay" disabled/>

                            </form>
                        </div>
                    </div>
                </div>
            </div>

        );
    }
}

export default BillingComponent;

我能够获得基本功能,例如从卡详细信息中获取随机数。但是我无法在页面中显示卡片品牌 image/error 消息,正如我们在 UI.

中显示的那样

如何使用托管字段显示卡片品牌形象和错误消息?

使用托管字段创建的页面:

已创建页面放入 UI - 显示错误消息

已创建页面放入 UI - 显示卡片品牌

虽然我们没有像 Drop in UI 那样得到准确的 UI,但我们可以通过在 cardTypeChange 上使用监听器来获取卡片类型并自己显示它。

hostedFieldsDidCreate(err, hostedFields) {
    this.setState({hostedFields: hostedFields});
    if (hostedFields !== undefined) {
        hostedFields.on('cardTypeChange', this.cardTypeProcessor);
        hostedFields.on('validityChange', this.cardValidator);
    }

    this.setState({load: false});
}


cardTypeProcessor(event) {
    if (event.cards.length === 1) {
        const cardType = event.cards[0].type;
        this.setState({cardType: cardType});
    } else {
        this.setState({cardType: null});
    }
}

cardValidator(event) {
    const fieldName = event.emittedBy;
    let field = event.fields[fieldName];
    let validCard = this.state.validCard;

    // Remove any previously applied error or warning classes
    $(field.container).removeClass('is-valid');
    $(field.container).removeClass('is-invalid');

    if (field.isValid) {
        validCard[fieldName] = true;
        $(field.container).addClass('is-valid');
    } else if (field.isPotentiallyValid) {
        // skip adding classes if the field is
        // not valid, but is potentially valid
    } else {
        $(field.container).addClass('is-invalid');
        validCard[fieldName] = false;
    }

    this.setState({validCard: validCard});
}

从 braintree 支持团队得到以下回复。

Hosted fields 样式可以在我们的开发人员文档中找到。关于logo,可以到卡种官网下载-

  1. Mastercard
  2. Visa
  3. AMEX
  4. Discover
  5. JCB

或从 other vendors.

在线

注意:Drop-In UI 将自动获取品牌徽标并提供验证错误,这与托管字段不同,因为它的可定制性较低。