Skip to content

Commit

Permalink
Add stripe webhook setup
Browse files Browse the repository at this point in the history
  • Loading branch information
wileymc committed Feb 9, 2024
1 parent 31f0402 commit f3bd336
Show file tree
Hide file tree
Showing 9 changed files with 414 additions and 127 deletions.
74 changes: 0 additions & 74 deletions components/Auth.tsx

This file was deleted.

9 changes: 6 additions & 3 deletions components/Nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { Dialog, DialogPanel, Text, Title } from "@tremor/react";
import { useTheme } from "next-themes";
import Image from "next/image";
import Script from "next/script";
import { Auth } from "./Auth";

export function Nav() {
const { creditsMenuOpen, setCreditsMenuOpen } = useDialogueStore((state) => ({
Expand Down Expand Up @@ -47,8 +46,12 @@ export function Nav() {
You have <span className="text-teal-300">{creditsRemaining}</span>{" "}
credits remaining. Please register or sign in to add more credits.
</Text>
<small>Coming soon...</small>
{/* <Auth handleClose={() => setCreditsMenuOpen(false)} /> */}
<Script async src="https://js.stripe.com/v3/pricing-table.js" />
{/* @ts-ignore */}
<stripe-pricing-table
pricing-table-id="prctbl_1Of7V1BDS22igUDjektIuC5m"
publishable-key="pk_live_51Of6RkBDS22igUDjuGhhLqxihN37zQn3G4FCXpcy8z1z9WnPjVPvPGKo8DscXAF9BQ9EadMj6f9555VvumHrVLfA0088T8vn7Y"
/>
</DialogPanel>
</Dialog>
<div className="flex justify-end items-center gap-2">
Expand Down
10 changes: 8 additions & 2 deletions lib/supabase.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { createClient } from "@supabase/supabase-js";

const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL ?? "";
const supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_SERVICE_ROLE_KEY ?? "";
const supabaseUrl =
process.env.NODE_ENV === "development"
? "http://127.0.0.1:54321"
: process.env.NEXT_PUBLIC_SUPABASE_URL ?? "";
const supabaseKey =
(process.env.NODE_ENV === "development"
? process.env.LOCAL_SUPABASE_SERVICE_ROLE_KEY
: process.env.NEXT_PUBLIC_SUPABASE_SERVICE_ROLE_KEY) ?? "";

export const supabase = createClient(supabaseUrl, supabaseKey);
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,17 @@
"@supabase/supabase-js": "^2.39.3",
"@tremor/react": "^3.13.4",
"@vercel/analytics": "^1.1.2",
"micro": "^10.0.1",
"midi-writer-js": "^3.1.1",
"next": "14.1.0",
"next-themes": "^0.2.1",
"openai": "^4.26.0",
"random-word-slugs": "^0.1.7",
"react": "^18",
"react-dom": "^18",
"react-spinners": "^0.13.8",
"react-toastify": "^10.0.4",
"stripe": "^14.16.0",
"zustand": "^4.5.0"
},
"devDependencies": {
Expand Down
100 changes: 98 additions & 2 deletions pages/api/webhook.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,105 @@
import { NextApiRequest, NextApiResponse } from "next";
import Stripe from "stripe";
import { supabase } from "../../lib/supabase";
import { buffer } from "micro";
import { RandomWordOptions, generateSlug } from "random-word-slugs";

const randomWordOptions: RandomWordOptions<4> = {
format: "title",
partsOfSpeech: ["adjective", "adjective", "noun", "noun"],
}; // 9752352516 unique combinations

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
apiVersion: "2023-10-16",
});

const webhookSecret =
process.env.LOCAL_STRIPE_WEBHOOK_SECRET ??
process.env.STRIPE_WEBHOOK_SECRET ??
"";

export const config = {
api: {
bodyParser: false,
},
};

export default async function webhookHandler(
req: NextApiRequest,
res: NextApiResponse
) {
console.log(req.body);
res.status(200).json({ message: "Webhook received" });
if (req.method === "POST") {
let event: Stripe.Event;
const sig = req.headers["stripe-signature"]!;
const buf = await buffer(req);

try {
const rawBody = await buffer(req);
event = stripe.webhooks.constructEvent(rawBody, sig, webhookSecret);
} catch (err) {
const errorMessage = err instanceof Error ? err.message : "Unknown error";
console.log(`❌ Error: ${errorMessage}`);
res.status(400).send(`Webhook Error: ${errorMessage}`);
return;
}

console.log("✅ Success:", event.id);

switch (event.type) {
case "charge.succeeded":
const charge = event.data.object as Stripe.Charge;
console.log(`💵 Charge id: ${charge.id}`);

const userEmail = charge.billing_details.email;

console.log(charge.billing_details);
// credit_amount follows SQL naming convention in this case to comply with Supabase Stored Procedures
let credits = 0;

// @ts-ignore
switch (charge.amount) {
case 500:
credits = 25;
break;
case 2000:
credits = 100;
break;
case 8000:
credits = 500;
break;
}

const { data: insertCodeData } = await supabase
.from("credit_codes")
.insert([
{
code: generateSlug(4, randomWordOptions),
credits,
},
])
.select();

await supabase.from("transactions").insert([
{
user_email: userEmail,
credit_code_id: insertCodeData?.[0].id,
stripe_charge_id: charge.id,
amount: charge.amount,
},
]);
break;
case "payment_intent.payment_failed":
const paymentIntent = event.data.object as Stripe.PaymentIntent;
console.log(
`❌ Payment failed: ${paymentIntent.last_payment_error?.message}`
);
default:
console.log(`Unhandled event type ${event.type}`);
}

res.json({ received: true });
} else {
res.setHeader("Allow", "POST");
res.status(405).end("Method Not Allowed");
}
}
Loading

0 comments on commit f3bd336

Please sign in to comment.