1scss:
2 form {
3 margin: auto;
4 max-width: 40em;
5 text-align: center;
6
7 fieldset {
8 max-width: 25em;
9 margin: 2em auto;
10 label { display: block; }
11 input[type=number] { max-width: 3em; }
12 small { display: block; }
13 }
14
15 button {
16 display: block;
17 width: 10em;
18 margin: auto;
19 }
20
21 }
22
23form method="post" action=""
24 #braintree
25 | Unfortunately, our credit card processor requires JavaScript.
26
27 fieldset
28 legend Auto top-up when account balance is low?
29 label
30 | When balance drops below $5, add $
31 input type="number" name="auto_top_up_amount" min="15" value=auto_top_up
32 small Leave blank for no auto top-up.
33
34 input type="hidden" name="customer_id" value=customer_id
35 input type="hidden" name="braintree_nonce"
36
37script src="https://js.braintreegateway.com/web/dropin/1.33.0/js/dropin.js"
38javascript:
39 document.querySelector("#braintree").innerHTML = "";
40
41 var button = document.createElement("button");
42 button.innerHTML = "Save";
43 document.querySelector("form").appendChild(button);
44 braintree.dropin.create({
45 authorization: #{{token.to_json}},
46 container: "#braintree",
47 card: { vault: { vaultCard: false } },
48 vaultManager: true,
49 threeDSecure: true,
50 translations: {
51 payWithCard: "Add a Card",
52 payingWith: "Default payment source",
53 chooseAnotherWayToPay: "Add a different payment source"
54 }
55 }, function (createErr, instance) {
56 if(createErr) console.log(createErr);
57
58 document.querySelector("form").addEventListener("submit", function(e) {
59 e.preventDefault();
60 instance._mainView.hideSheetError();
61
62 instance.requestPaymentMethod({
63 threeDSecure: {
64 amount: "0.0",
65 requireChallenge: true
66 }
67 }, function(err, payload) {
68 if(err) {
69 console.log(err);
70 } else {
71 instance._mainView.showLoadingIndicator();
72 e.target.braintree_nonce.value = payload.nonce;
73 fetch("", {
74 "method": "POST",
75 "body": new FormData(e.target)
76 }).then(function(response) {
77 instance._mainView.hideLoadingIndicator();
78
79 if(response.status !== 200) {
80 return Promise.reject(response);
81 }
82 }).catch(function(err) {
83 console.log(err);
84 err.text().then(function(msg) {
85 instance._mainView.hideLoadingIndicator();
86 instance.clearSelectedPaymentMethod();
87 instance._mainView.showSheetError(msg);
88 });
89 }).catch(function(err) {
90 console.log(err);
91 instance._mainView.hideLoadingIndicator();
92 instance.clearSelectedPaymentMethod();
93 instance._mainView.showSheetError();
94 });
95 }
96 });
97 });
98 });