React Billing.js
Setup pricing page and a customer portal by copy pasting code snippets.
Install
Using NPM:
npm i @billing-js/react-billing-js
Using Yarn:
yarn add @billing-js/react-billing-js
Stripe account Id
Get your Billing.js Stripe account id on billingjs.com.
Billing.js is using Stripe Connect on the background to access your products and manage the subscriptions for you.
Documentation
Checkout the full Billing.js documentation on docs.billingjs.com.
Usage
Wrap your App with the BillingProvider
component to give it access to the billing context.
index.tsx - Root component of your react app
import React from "react"
import { render } from "react-dom"
import { BillingProvider } from "react-billing-js"
import YourApp from "./YourApp"
const ReactApp = (
<BillingProvider
stripeAccount={"acct_..."} // Your stripe account id that you can find in the billing.js dashboard (https://billingjs.com)
options={{ termsAndConditionsUrl: "/terms", productPageUrl: "/pricing" }} // Optional
onError={(error) => {}} // Optional for error handling
>
<YourApp />
</BillingProvider>
)
render(<ReactApp />, document.getElementById("root"))
Authentication
Set your router to require authentication when accessing the customer portal.
App.tsx - Root component
import { useAuth, CustomerPortal } from "react-billing-js"
import { Switch, Route, Redirect, BrowserRouter as Router } from "react-router-dom"
import Pricing from "./Pricing"
export default () => {
const { loading, user, signOut } = useAuth()
const renderPrivateRoute = (Component, redirect = "/login") => () => {
if (user) {
return React.isValidElement(Component) ? Component : <Component />
}
return <Redirect to={redirect} />
}
if (loading) {
return <div>loading...</div>
}
<Router>
<Switch>
<Route exact={true} path="/subscription" render={renderPrivateRoute(CustomerPortal)} />
<Route exact={true} path="/pricing" component={Pricing} />
<Route exact={true} path="/login" component={Login} />
<Redirect to="/pricing" />
</Switch>
</Router>
)
Fetch the HMAC signature from your server to authenticate the user on the Billing.js module.
Login.tsx - Login page component
import { useAuth } from "react-billing-js"
const { loading, user, signIn } = useAuth()
const onSignIn = () => fetch("/URL_TO_GET_THE_HMAC").then((res) => signIn({ hmac: res?.data?.hmac, email: user.email }))
if (loading) {
return <div>loading...</div>
}
if (user) {
return <div>Signed in!</div>
}
return (
<div>
<button onClick={onSignIn}>Sign in</button>
</div>
)
Pricing page
Show the pricing of the products of your choices to the user.
Pricing.tsx - Pricing page component
import { useProducts, PaymentModal } from "react-billing-js"
import { useHistory } from "react-router-dom"
export default () => {
const history = useHistory()
const {
loading,
products: [premiumPlan],
activeSubscriptions,
pricingFilter: {
currency: {
selectedCurrency,
availableCurrencies,
setCurrency
},
recurrence: {
selectedRecurrence,
availableRecurrences,
setRecurrence
}
}
} = useProducts(["prod_..."], {
modal: {
maskClassName: "bg-white opacity-75"
},
normalizePriceOnRecurrence: "monthly",
defaultCurrency: "usd",
defaultRecurrence: "Yearly",
signIn: () => history.push("/login"),
onPaymentSuccessful: () => console.log(`Payment successful`),
onPaymentError: (error) => console.log(`Payment error`, error)
})
return (
<div>
{/*Payment modal that will open when a pricing is selected*/}
<PaymentModal />
{/*Plan description and price*/}
<h3>{premiumPlan.name}</h3>
<h2>
{selectedCurrency.symbol} {premiumPlan.selectedPricing.priceInteger}.
{premiumPlan.selectedPricing.priceDecimal}/{premiumPlan.selectedPricing.pricingRecurrence}
</h2>
{/* Payment button */}
{loading ||
activeSubscriptions.find(
(subscription) => subscription.items?.data[0]?.price?.id === premiumPlan.selectedPricing.id
) ? ( // If the user has an active subscription to this product
<button disabled={true}>{loading ? "Loading..." : "Current plan"}</button>
) : (
// If the user does not have an active subscription to this product
<button onClick={premiumPlan.selectedPricing.onSelectPricing}>
{
activeSubscriptions.length > 0
? "Switch plan" // If the user has an active subscription to another product
: premiumPlan.selectedPricing?.recurring?.trial_period_days
? "Start your trial" // If the product has a trial period
: "Get started" // If the product is billed immediately
}
</button>
)}
</div>
)
}
Sponsored by Qualtir