· 5 years ago · May 05, 2020, 06:28 AM
1<!DOCTYPE html>
2<html lang="en">
3 <head>
4 <meta charset="utf-8" />
5 <title>CHECKOUT</title>
6 <meta name="description" content="A demo of a card payment on Stripe" />
7 <meta name="viewport" content="width=device-width, initial-scale=1" />
8 <link rel="stylesheet" href="global.css" />
9 <script src="https://js.stripe.com/v3/"></script>
10 <script src="/client.js" defer></script>
11 <script>// A reference to Stripe.js initialized with your real test publishable API key.
12var stripe = Stripe("pk_test_jZ7dhI358i0PyN4SLawcndTI00t09Mj1Nb");
13// The items the customer wants to buy
14var purchase = {
15 items: [{ id: "xl-tshirt" }]
16};
17// Disable the button until we have Stripe set up on the page
18document.querySelector("button").disabled = true;
19fetch("/create-payment-intent", {
20 method: "POST",
21 headers: {
22 "Content-Type": "application/json"
23 },
24 body: JSON.stringify(purchase)
25})
26 .then(function(result) {
27 return result.json();
28 })
29 .then(function(data) {
30 var elements = stripe.elements();
31 var style = {
32 base: {
33 color: "#32325d",
34 fontFamily: 'Arial, sans-serif',
35 fontSmoothing: "antialiased",
36 fontSize: "16px",
37 "::placeholder": {
38 color: "#32325d"
39 }
40 },
41 invalid: {
42 fontFamily: 'Arial, sans-serif',
43 color: "#fa755a",
44 iconColor: "#fa755a"
45 }
46 };
47 var card = elements.create("card", { style: style });
48 // Stripe injects an iframe into the DOM
49 card.mount("#card-element");
50 card.on("change", function (event) {
51 // Disable the Pay button if there are no card details in the Element
52 document.querySelector("button").disabled = event.empty;
53 document.querySelector("#card-errors").textContent = event.error ? event.error.message : "";
54 });
55 var form = document.getElementById("payment-form");
56 form.addEventListener("submit", function(event) {
57 event.preventDefault();
58 // Complete payment when the submit button is clicked
59 payWithCard(stripe, card, data.clientSecret);
60 });
61 });
62// Calls stripe.confirmCardPayment
63// If the card requires authentication Stripe shows a pop-up modal to
64// prompt the user to enter authentication details without leaving your page.
65var payWithCard = function(stripe, card, clientSecret) {
66 loading(true);
67 stripe
68 .confirmCardPayment(clientSecret, {
69 payment_method: {
70 card: card
71 }
72 })
73 .then(function(result) {
74 if (result.error) {
75 // Show error to your customer
76 showError(result.error.message);
77 } else {
78 // The payment succeeded!
79 orderComplete(result.paymentIntent.id);
80 }
81 });
82};
83/* ------- UI helpers ------- */
84// Shows a success message when the payment is complete
85var orderComplete = function(paymentIntentId) {
86 loading(false);
87 document
88 .querySelector(".result-message a")
89 .setAttribute(
90 "href",
91 "https://dashboard.stripe.com/test/payments/" + paymentIntentId
92 );
93 document.querySelector(".result-message").classList.remove("hidden");
94 document.querySelector("button").disabled = true;
95};
96// Show the customer the error from Stripe if their card fails to charge
97var showError = function(errorMsgText) {
98 loading(false);
99 var errorMsg = document.querySelector("#card-errors");
100 errorMsg.textContent = errorMsgText;
101 setTimeout(function() {
102 errorMsg.textContent = "";
103 }, 4000);
104};
105// Show a spinner on payment submission
106var loading = function(isLoading) {
107 if (isLoading) {
108 // Disable the button and show a spinner
109 document.querySelector("button").disabled = true;
110 document.querySelector("#spinner").classList.remove("hidden");
111 document.querySelector("#button-text").classList.add("hidden");
112 } else {
113 document.querySelector("button").disabled = false;
114 document.querySelector("#spinner").classList.add("hidden");
115 document.querySelector("#button-text").classList.remove("hidden");
116 }
117};</script>
118<style>/* Variables */
119* {
120 box-sizing: border-box;
121}
122body {
123 font-family: -apple-system, BlinkMacSystemFont, sans-serif;
124 font-size: 16px;
125 -webkit-font-smoothing: antialiased;
126 display: flex;
127 justify-content: center;
128 align-content: center;
129 height: 100vh;
130 width: 100vw;
131}
132form {
133 width: 30vw;
134 min-width: 500px;
135 align-self: center;
136 box-shadow: 0px 0px 0px 0.5px rgba(50, 50, 93, 0.1),
137 0px 2px 5px 0px rgba(50, 50, 93, 0.1), 0px 1px 1.5px 0px rgba(0, 0, 0, 0.07);
138 border-radius: 7px;
139 padding: 40px;
140}
141input {
142 border-radius: 6px;
143 margin-bottom: 6px;
144 padding: 12px;
145 border: 1px solid rgba(50, 50, 93, 0.1);
146 height: 44px;
147 font-size: 16px;
148 width: 100%;
149 background: white;
150}
151.result-message {
152 line-height: 22px;
153 font-size: 16px;
154}
155.result-message a {
156 color: rgb(89, 111, 214);
157 font-weight: 600;
158 text-decoration: none;
159}
160.hidden {
161 display: none;
162}
163.card-error {
164 color: rgb(105, 115, 134);
165 text-align: left;
166 font-size: 13px;
167 line-height: 17px;
168 margin-top: 12px;
169}
170#card-element {
171 border-radius: 4px 4px 0 0 ;
172 padding: 12px;
173 border: 1px solid rgba(50, 50, 93, 0.1);
174 height: 44px;
175 width: 100%;
176 background: white;
177}
178#payment-request-button {
179 margin-bottom: 32px;
180}
181/* Buttons and links */
182button {
183 background: #5469d4;
184 color: #ffffff;
185 font-family: Arial, sans-serif;
186 border-radius: 0 0 4px 4px;
187 border: 0;
188 padding: 12px 16px;
189 font-size: 16px;
190 font-weight: 600;
191 cursor: pointer;
192 display: block;
193 transition: all 0.2s ease;
194 box-shadow: 0px 4px 5.5px 0px rgba(0, 0, 0, 0.07);
195 width: 100%;
196}
197button:hover {
198 filter: contrast(115%);
199}
200button:disabled {
201 opacity: 0.5;
202 cursor: default;
203}
204/* spinner/processing state, errors */
205.spinner,
206.spinner:before,
207.spinner:after {
208 border-radius: 50%;
209}
210.spinner {
211 color: #ffffff;
212 font-size: 22px;
213 text-indent: -99999px;
214 margin: 0px auto;
215 position: relative;
216 width: 20px;
217 height: 20px;
218 box-shadow: inset 0 0 0 2px;
219 -webkit-transform: translateZ(0);
220 -ms-transform: translateZ(0);
221 transform: translateZ(0);
222}
223.spinner:before,
224.spinner:after {
225 position: absolute;
226 content: "";
227}
228.spinner:before {
229 width: 10.4px;
230 height: 20.4px;
231 background: #5469d4;
232 border-radius: 20.4px 0 0 20.4px;
233 top: -0.2px;
234 left: -0.2px;
235 -webkit-transform-origin: 10.4px 10.2px;
236 transform-origin: 10.4px 10.2px;
237 -webkit-animation: loading 2s infinite ease 1.5s;
238 animation: loading 2s infinite ease 1.5s;
239}
240.spinner:after {
241 width: 10.4px;
242 height: 10.2px;
243 background: #5469d4;
244 border-radius: 0 10.2px 10.2px 0;
245 top: -0.1px;
246 left: 10.2px;
247 -webkit-transform-origin: 0px 10.2px;
248 transform-origin: 0px 10.2px;
249 -webkit-animation: loading 2s infinite ease;
250 animation: loading 2s infinite ease;
251}
252@-webkit-keyframes loading {
253 0% {
254 -webkit-transform: rotate(0deg);
255 transform: rotate(0deg);
256 }
257 100% {
258 -webkit-transform: rotate(360deg);
259 transform: rotate(360deg);
260 }
261}
262@keyframes loading {
263 0% {
264 -webkit-transform: rotate(0deg);
265 transform: rotate(0deg);
266 }
267 100% {
268 -webkit-transform: rotate(360deg);
269 transform: rotate(360deg);
270 }
271}
272@media only screen and (max-width: 600px) {
273 form {
274 width: 80vw;
275 }
276}</style>
277 </head>
278 <body>
279 <!-- Display a payment form -->
280 <form id="payment-form">
281 <div id="card-element"></div>
282 <script>
283 var style = {
284 base: {
285 color: "#32325d",
286 }
287};
288
289var card = elements.create("card", { style: style });
290card.mount("#card-element");
291</script>
292 <button id="submit">
293 <div class="spinner hidden" id="spinner"></div>
294 <span id="button-text">Pay</span>
295 </button>
296 <p id="card-errors" role="alert"></p>
297 <p class="result-message hidden">
298 Payment succeeded, see the result in your
299 <a href="" target="_blank">Stripe dashboard.</a> Refresh the page to pay again.
300 </p>
301 </form>
302 </body>
303</html>