Skip to content

Commit

Permalink
content: embedded checkout
Browse files Browse the repository at this point in the history
  • Loading branch information
codediodeio committed Apr 3, 2024
1 parent d8ba708 commit f6cbb49
Show file tree
Hide file tree
Showing 2 changed files with 154 additions and 6 deletions.
4 changes: 2 additions & 2 deletions content/courses/stripe-saas/_index.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
lastmod: 2024-03-24T11:11:30-09:00
lastmod: 2024-04-01T11:11:30-09:00
title: Stripe for SaaS
description: Accept Payments in your Software-as-a-Service Product with Stripe
weight: 0
Expand Down Expand Up @@ -47,7 +47,7 @@ This course is intermediate level 🟦 and expects some familiarity with JavaScr

## When was the course last updated?

<span class="tag tag-sm tag-pro">Updated March 26th, 2024</span> <span class="tag tag-sm tag-svelte">Next.js 14</span> <span class="tag tag-sm tag-firebase">Supabase.js 2+</span>
<span class="tag tag-sm tag-pro">Updated April 3rd, 2024</span> <span class="tag tag-sm tag-svelte">Next.js 14</span> <span class="tag tag-sm tag-firebase">Supabase.js 2+</span>

## How do I enroll?

Expand Down
156 changes: 152 additions & 4 deletions content/courses/stripe-saas/bonus-embedded-checkout.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,160 @@ description: Create an embedded stripe checkout page
weight: 40
lastmod: 2024-03-22T10:23:30-09:00
draft: false
vimeo:
youtube: 7WFXl4-aCxs
emoji: 🎊
video_length: 3:00
video_length: 6:02
chapter_start: Bonus Round
free: true
---

### Coming Soon...
### Commands

This video is in develpment and will be available soon. Stay tuned!
Refer to the [Stripe React Documentation](https://docs.stripe.com/stripe-js/react)

```bash
npm i @stripe/react-stripe-js @stripe/stripe-js
```


### Code


Create an API rotue for the checkout session.

{{< file "ts" "app/api/embedded-checkout/route.ts" >}}
```typescript
import { NextResponse } from 'next/server';
import { stripe } from '@/utils/stripe';

export async function POST(request: Request) {
try {
const { priceId } = await request.json();

const session = await stripe.checkout.sessions.create({
ui_mode: 'embedded',
payment_method_types: ['card'],
line_items: [
{
price: priceId,
},
],
mode: 'subscription',
return_url: `${request.headers.get('origin')}/return?session_id={CHECKOUT_SESSION_ID}`,
});

return NextResponse.json({ id: session.id, client_secret: session.client_secret });
} catch (error: any) {
console.error(error);
return NextResponse.json({ message: error.message }, { status: 500 });
}
}
```

Create a client component to display the checkout form.

{{< file "react" "app/EmbeddedCheckoutForm.tsx" >}}
```tsx
"use client";
import { loadStripe } from "@stripe/stripe-js";
import {
EmbeddedCheckoutProvider,
EmbeddedCheckout,
} from "@stripe/react-stripe-js";
import { useCallback, useRef, useState } from "react";

export default function EmbeddedCheckoutButton() {
const stripePromise = loadStripe(
process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!
);
const [showCheckout, setShowCheckout] = useState(false);
const modalRef = useRef<HTMLDialogElement>(null);

const fetchClientSecret = useCallback(() => {
// Create a Checkout Session
return fetch("/api/embedded-checkout", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ priceId: "price_1OtHkdBF7AptWZlcIjbBpS8r" }),
})
.then((res) => res.json())
.then((data) => data.client_secret);
}, []);

const options = { fetchClientSecret };

const handleCheckoutClick = () => {
setShowCheckout(true);
modalRef.current?.showModal();
};

const handleCloseModal = () => {
setShowCheckout(false);
modalRef.current?.close();
};

return (
<div id="checkout" className="my-4">
<button className="btn" onClick={handleCheckoutClick}>
Open Modal with Embedded Checkout
</button>
<dialog ref={modalRef} className="modal">
<div className="modal-box w-100 max-w-screen-2xl">
<h3 className="font-bold text-lg">Embedded Checkout</h3>
<div className="py-4">
{showCheckout && (
<EmbeddedCheckoutProvider stripe={stripePromise} options={options}>
<EmbeddedCheckout />
</EmbeddedCheckoutProvider>
)}
</div>
<div className="modal-action">
<form method="dialog">
<button className="btn" onClick={handleCloseModal}>
Close
</button>
</form>
</div>
</div>
</dialog>
</div>
);
}
```


Create a server component page to handle the return URL.

{{< file "react" "app/return/page.tsx" >}}
```tsx
import { stripe } from "@/utils/stripe";

async function getSession(sessionId: string) {
const session = await stripe.checkout.sessions.retrieve(sessionId!);
return session;
}

export default async function CheckoutReturn({ searchParams }) {
const sessionId = searchParams.session_id;
const session = await getSession(sessionId);

console.log(session);

if (session?.status === "open") {
return <p>Payment did not work.</p>;
}

if (session?.status === "complete") {
return (
<h3>
We appreciate your business! Your Stripe customer ID is:
{(session.customer as string)}.
</h3>
);
}

return null;
}
```

0 comments on commit f6cbb49

Please sign in to comment.