@billing-js/react-billing-js
v1.1.34
Published
A powerful, low-code react component library to quickly integrate Stripe into your React app, with customizable pricing page and customer portal, support for shared subscriptions and much more.
Downloads
278
Maintainers
Readme
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 = (
// Wrap your app with the billing provider with your stripe account id
<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 () => {
// use the useAuth hook to get the current user
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()
// fetch the hmac now or retrieve it from the the app state, then sign in the user
// follow the steps in the [billingjs.com](https://billingjs.com) documentation to get the HMAC
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() // optional, if you are using react-router
// Billing.js useProducts hook
const {
loading, // loading state
products: [premiumPlan], // list of the products fetched
activeSubscriptions, // list of active subscriptions of the user
pricingFilter: {
currency: {
selectedCurrency, // current currency (USD by default)
availableCurrencies, // list of the available currencies
setCurrency // function to set the desired currency
},
recurrence: {
selectedRecurrence, // current recurrence
availableRecurrences, // list of the available recurrences
setRecurrence // function to set the desired recurrence
}
}
} = useProducts(["prod_..."], {
modal: {
maskClassName: "bg-white opacity-75" // modal mask class name
},
normalizePriceOnRecurrence: "monthly", // Normalize price on recurrence
defaultCurrency: "usd", // Default currency
defaultRecurrence: "Yearly", // Default recurrence
signIn: () => history.push("/login"), // Function to sign in the user
onPaymentSuccessful: () => console.log(`Payment successful`), // Callback when payment is successful
onPaymentError: (error) => console.log(`Payment error`, error) // Callback when payment is unsuccessful
})
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>
)
}