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 label#amount style="#{'display:none;' unless params['amount']}"
28 div Amount of initial deposit (minimum $15)
29 input type="number" name="amount" min="15" value="#{params.fetch('amount', '')}"
30
31 fieldset
32 legend Auto top-up when account balance is low?
33 label
34 | When balance drops below $5, add $
35 input type="number" name="auto_top_up_amount" min="15" max="35" value=auto_top_up
36 small Leave blank for no auto top-up.
37
38 input type="hidden" name="customer_id" value=customer_id
39 input type="hidden" name="atfd" value=antifraud
40 input type="hidden" name="braintree_nonce"
41
42script src="https://js.braintreegateway.com/web/dropin/1.33.0/js/dropin.js"
43javascript:
44 document.querySelector("#braintree").innerHTML = "";
45
46 if(window.localStorage) {
47 var atfd = localStorage.getItem("atfd");
48 if(!atfd) {
49 atfd = "#{antifraud}";
50 localStorage.setItem("atfd", atfd);
51 }
52 document.querySelector("input[name=atfd]").value = atfd;
53 }
54
55 var button = document.createElement("button");
56 button.innerHTML = "Save";
57 document.querySelector("form").appendChild(button);
58
59 if (window.xmpp_xep0050) {
60 xmpp_xep0050.preventDefault();
61
62 window.addEventListener("message", (ev) => {
63 if (ev.data === "xmpp_xep0050/next" && !button.disabled) {
64 document.querySelector("form").requestSubmit();
65 }
66 if (ev.data === "xmpp_xep0050/cancel") {
67 window.xmpp_xep0050.execute("cancel");
68 }
69 if (ev.data === "xmpp_xep0050/prev") {
70 window.xmpp_xep0050.execute("prev");
71 }
72 if (ev.data === "xmpp_xep0050/complete") {
73 window.xmpp_xep0050.execute("complete");
74 }
75 });
76 }
77
78 braintree.dropin.create({
79 authorization: #{{token.to_json}},
80 container: "#braintree",
81 card: { vault: { vaultCard: false } },
82 vaultManager: true,
83 threeDSecure: true,
84 translations: {
85 payWithCard: "Add a Card",
86 payingWith: "Default payment source",
87 chooseAnotherWayToPay: "Add a different payment source"
88 }
89 }, function (createErr, instance) {
90 if(createErr) {
91 console.log(createErr);
92 Sentry.captureException(createErr);
93 }
94
95 document.querySelector("form").addEventListener("submit", function(e) {
96 button.disabled = true;
97 button.style.display = "none";
98 e.preventDefault();
99 instance._mainView.hideSheetError();
100
101 instance.requestPaymentMethod({
102 threeDSecure: {
103 amount: document.querySelector("input[name=amount]").value || "0.0",
104 requireChallenge: true
105 }
106 }, function(err, payload) {
107 if(err) {
108 console.log(err);
109 button.disabled = false;
110 button.style.display = "block";
111 } else {
112 instance._mainView.showLoadingIndicator();
113 e.target.braintree_nonce.value = payload.nonce;
114 fetch("", {
115 "method": "POST",
116 "body": new FormData(e.target)
117 }).then(function(response) {
118 button.disabled = false;
119 button.style.display = "block";
120 instance._mainView.hideLoadingIndicator();
121
122 if(response.status === 200) {
123 if (window.xmpp_xep0050) window.xmpp_xep0050.execute();
124 } else {
125 return Promise.reject(response);
126 }
127 }).catch(function(err) {
128 button.disabled = false;
129 button.style.display = "block";
130 if(!(err instanceof Response)) return Promise.reject(err);
131
132 return err.text().then(function(msg) {
133 console.log(msg);
134 instance._mainView.hideLoadingIndicator();
135 instance.clearSelectedPaymentMethod();
136 instance._mainView.showSheetError(msg);
137 var errEl = instance._mainView.sheetErrorText;
138 if(errEl.innerHTML === instance._mainView.strings.genericError) {
139 errEl.innerHTML = "Card Issuer Says: " + msg;
140 }
141 });
142 }).catch(function(err) {
143 button.disabled = false;
144 button.style.display = "block";
145 console.log(err);
146 instance._mainView.hideLoadingIndicator();
147 instance.clearSelectedPaymentMethod();
148 instance._mainView.showSheetError();
149 Sentry.captureException(err);
150 });
151 }
152 });
153 });
154 });