credit_cards.slim

 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	});