#deme-checkout-metadata
1 messages · Page 1 of 1 (latest)
Here's the tRPC router for reference
createCheckoutSession: publicProcedure
.input(
z.object({
priceId: z.string(),
// metadata: z.object({}),
})
)
.mutation(async ({ ctx, input }) => {
const { stripe, userId, prisma, req } = ctx;
if (!userId) {
throw new Error("No user id");
}
const customerId = await getOrCreateStripeCustomerIdForUser({
prisma,
stripe,
userId,
});
console.log(customerId, "customerId");
if (!customerId) {
throw new Error("Could not create customer");
}
// the base url is different depending on if we are in development or production
const baseUrl =
env.NODE_ENV === "development"
? `http://${req.headers.host ?? "localhost:3000"}`
: `https://${req.headers.host ?? env.NEXTAUTH_URL}`;
// Stripe Checkout Session
const checkoutSession = await stripe.checkout.sessions.create({
customer: customerId as string,
client_reference_id: userId!,
payment_method_types: ["card"],
mode: "payment",
// if using subscriptions
// mode: "subscription",
line_items: [
{
// price: env.STRIPE_PRICE_ID,
price: input.priceId,
quantity: 1,
},
],
// metadata: input.metadata,
success_url: `${baseUrl}/store/orderSuccessful`,
// redirect the user back to the item page if they cancel the purchase
cancel_url: `${baseUrl}/store`,
// if using subscriptions
// subscription_data: {
// metadata: {
// userId: userId,
// },
// },
});
if (!checkoutSession) {
throw new Error("Could not create checkout session");
}
return { checkoutUrl: checkoutSession.url };
}),
deme-checkout-metadata
<button
className="btn-primary btn bg-primary"
onClick={async () => {
if (!user.isSignedIn) {
handleBuyNow();
} else if (user.isSignedIn) {
// create a checkout session
const { checkoutUrl } = await createCheckoutSession({
priceId: product.default_price,
// metadata: {
// downloadUrl: product.metadata,
// },
});
if (checkoutUrl) {
void push(checkoutUrl);
}
}
}}
>
That's the button that initiates it all
On the redirect page, you're supposed to know who the customer is since you sent them to Checkout. So when they came back you know who they are, find their Checkout Session you created for them, fetch it from the API and look at its metadata
Is there a way to access the session using the api in on the page component?
I don't know what "on the page component" could mean
We do have an API to retrieve a Checkout Session yes: https://stripe.com/docs/api/checkout/sessions/retrieve
As the developer you write code to call this based on which Session you want, based on which Customer/cookie is back
//pages/store/orderSuccessful.tsx
import React from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faCheckCircle } from "@fortawesome/free-solid-svg-icons";
import { useRouter } from "next/router";
import { GetStaticProps } from "next";
import { generateSSGHelper } from "~/server/helpers/ssgHelper";
import { api } from "~/utils/api";
import { usePathname } from "next/navigation";
import { stripe } from "~/server/helpers/stripe/client";
const OrderSuccessful = () => {
const pathname = usePathname();
// I want everything after the /`${baseUrl}/store/orderSuccessful
const path = pathname.split("/").pop();
console.log(path, "path");
// get the stripe session metadata
const { data: downloadUrls } = api.store.getS3DownloadUrl.useQuery();
console.log(downloadUrls, "s3BucketDownloadLink");
// const postPurchaseDownloadLink = downloadUrls;
const router = useRouter();
return (
<div className="flex min-h-screen flex-col justify-center bg-gray-100 py-6 sm:py-12">
<div className="relative mx-auto py-3 text-center sm:max-w-xl">
<span className="text-6xl text-green-500">
<FontAwesomeIcon icon={faCheckCircle} />
</span>
<h1 className="text-2xl font-semibold text-gray-900">
Purchase Successful!
</h1>
<p className="text-gray-500">
Thank you for your order. We hope you enjoy your purchase!
</p>
<p>Here's your download link: {url}</p>
<div className="mt-6">
<button
onClick={() => {
router.push("/");
}}
className="btn-primary btn mx-2"
>
Back to Home
</button>
<button
onClick={() => {
router.push("/store");
}}
className="btn-secondary btn mx-2"
>
Continue Shopping
</button>
</div>
</div>
<div className="mt-12">
<h2 className="mb-4 text-center text-xl font-semibold text-gray-900">
Other users also bought:
</h2>
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
{mappedProducts.map((product) => (
<div key={product.id} className="rounded-lg bg-white p-4 shadow-md">
<img
className="mb-4 h-48 w-full rounded object-cover"
src={product.images}
alt={product.title}
/>
<h3 className="text-lg font-semibold text-gray-900">
{product.name}
</h3>
</div>
))}
</div>
</div>
</div>
);
};
export default OrderSuccessful;
export const getStaticProps: GetStaticProps = async ({ req, res }: any) => {
// use SSG to get the data from the server
const ssg = generateSSGHelper(req, res);
// get recent store activities for the carousel's top news
await ssg.homePage.getRecentStoreActivities.prefetch();
// return the props
return {
props: {
trpcState: ssg.dehydrate(),
},
};
};
Thanks I will read into this
in theory you have a Customer with an account on your app/website. They signed up or you have a cookie or something, so server-side you identify who they are when they come back from Checkout to your success URL and then you can retrieve the Checkout Session (or really have the S3 link in your own database and such)
Ah okay, I remember now. I have the stripe customer id on the user in the db.
I thought the id would change constantly so I wasn't sure if that was a reliable way to track the user forever.
So I can use that customer id to retrieve their session, then I can see what they bought, then I can present the metadata link?
yes
you can use https://stripe.com/docs/api/checkout/sessions/list + customer: 'cus_123' for example (or store that in your database)