Coding the Checkout Process
Learn how to code the application’s checkout process with Stripe.
We'll cover the following
InitPayment
in Stripe
This lesson walks through the application’s checkout process. Take a look at the <ShoppingCart/>
component inside imports/ui/Shoppingcart.jsx
. On lines 195–203, we should notice that we’re pushing the user to the /init_payment
route. This route renders the <InitPayment/>
component.
Open the imports/ui/InitPayment.jsx
file. This is the component that’s rendered after clicking the “Checkout” button. The InitPayment component is used to make a Meteor call to the server, which, in turn, makes an API request to Stripe to create a paymentIntent
.
The component receives the authenticated and user
object props. We want to display two input textboxes for users that are authenticated so that we can collect their names
and email
addresses. This is done in lines 93–121. The total number of books in the cart is calculated by the sumItems
function. Remember that the cart
is stored in React context, so we have access to it on our component.
On lines 141–149, there’s a “submit” button that submits the form. Take a look at the onSubmit
form function called handlePaymentCheckout
. We prevent the default action of a form, which is to submit the content of the form, thereby refreshing the page. On line 22, we set the loading state by using the setLoading
function. This is done to prevent the user from clicking the “submit” button again. The disabled
attribute of the form button is equated to the loading
state. So, if loading
is true
, the form button is disabled and a spinner is shown, preventing double submission.
We have a try catch
block in which we build up the books purchased. If the user is authenticated, we retrieve the username
and email
from the user
prop. If they’re not authenticated, we get the value entered by them from the customerEmail
and customerName
states.
We create a bookObject
from the books contained in the cart on lines 46–51 inside the imports/ui/InitPayment.jsx
file. The created object is modeled in the same shape as the BookSale
collection schema. Open imports/api/bookSales/bookSales.js
to view the schema. The bookObjects
are added into an array named booksBoughtArray
.
In line 59, we create a Promise
object. We can await
the Promise
execution because the handlePaymentCheckout
is marked as async
. When we await
a Promise
, it makes the execution feel as though it’s synchronous, even though a Promise
is asynchronous.
Inside the Promise
body, we have a call to a Meteor Method called stripe.initPayment
. We pass in the amount and the buyDetails
, which contain an object in the shape of what the BooksSaleCollection
is expecting. The Meteor Method call returns, and if successful, the Promise is resolved with the result from the call. Remember that the return value of the Meteor Method, stripe.initPayment
, is the clientSecret
that’s returned from Stripe.
If the call fails, we can call the setErrorMessage
function that sets the errorMessage
state and reject the Promise
. In line 74, we set the loading state to false
. In line 75, we use the setClientSecret
function, which is destructured from the useStripeContext
on line 14. This saves the clientSecret
inside the StripeContext
. We also save the clientSecret
on local storage in line 76. On line 77, we push the user to the component where they’ll make the payment.
Updating the clientSecret
Open the App.jsx
file and notice that line 62 is where we extract the clientSecret
from the useStripeContext
. We check if we have a clientSecret
and, if we don’t have one, we retrieve the clientSecret
stored in local storage.
const { clientSecret } = useStripeContext();
let clientSecretFromStorage;
if (!clientSecret) {
//get it from the local storage
clientSecretFromStorage = localStorage.getItem("client_secret");
}
A ternary operation is performed in line 70. If there’s no clientSecret
present, we retrieve the clientSecret
stored on the browser’s local storage.
stripe.initPayment
Method
The Meteor Method, stripe.initPayment
, is defined in the imports/server/startup/stripe.js
file. Let’s walk through this file’s functions once more. The function accepts an amount and the saleDetails
object that comes from the client. A check is performed on the input variables. The salesDetails.dateOfPurchase
value is set to use the server date instead of the date coming from the client.
The salesDetails
is saved inside the BookSalesCollection
and the returned _id
is saved in a variable called orderId
. An asynchronous call is made to Stripe API using our secret key. We multiply the amount by a factor of 100
because Stripe saves the collected amount in the smallest denomination of a currency.
We define payment_method_types
as a card. Here, we can set other accepted payment methods. View the Stripe documentation for other payment methods allowed. The metadata is an object that we can attach here for Stripe to display on our dashboard. This helps to attach a payment on the dashboard to a document in our BookSaleCollection
.
We await
the call to Stripe and, if we’re successful, we update the BookSaleCollection
with the returned client_secret
and return the client_secret
to the caller of the Meteor Method. If the call to Stripe fails, we throw an Error in line 26.
We pick up the Method call on the client by saving the returned value in local storage. Open the imports/ui/InitPayment.jsx
file. Take a look at line 76. This is where the returned result from the server method is saved to local storage. On line 77, the user is pushed to the /make_payment
route to complete the payment.
Task
Run the application, buy some books, and click the “Checkout” button to take you to the initPayment
component. Fill in the details on the form, and click the “initiate payment” button.
Get hands-on with 1400+ tech skills courses.