update webhook and doc links

This commit is contained in:
vincanger 2023-10-12 17:54:15 +02:00
parent 90566cf5d3
commit aade090e33
6 changed files with 66 additions and 17 deletions

View File

@ -1,6 +1,7 @@
# NOTE: if you setup your DB using `wasp start db` then you DO NOT need to add a DATABASE_URL env.
# DATABASE_URL=
# for testing, go to https://dashboard.stripe.com/test/apikeys and get a test stripe key that starts with "sk_test_..."
STRIPE_KEY=
SUBSCRIPTION_PRICE_ID=

View File

@ -1,6 +1,6 @@
app SaaSTemplate {
wasp: {
version: "^0.11.1"
version: "^0.11.6"
},
title: "My SaaS App",
head: [
@ -10,7 +10,7 @@ app SaaSTemplate {
"<meta property='og:image' content='src/client/static/image.png' />",
// you can put your google analytics script here, too!
],
// 🔐 Auth out of the box! https://wasp-lang.dev/docs/language/features#authentication--authorization
// 🔐 Auth out of the box! https://wasp-lang.dev/docs/auth/overview
auth: {
userEntity: User,
externalAuthEntity: SocialLogin,
@ -30,7 +30,7 @@ app SaaSTemplate {
getEmailContentFn: import { getPasswordResetEmailContent } from "@server/auth/email.js",
},
},
google: { // Guide for setting up Auth via Google https://wasp-lang.dev/docs/integrations/google
google: { // Guide for setting up Auth via Google https://wasp-lang.dev/docs/auth/social-auth/overview
getUserFieldsFn: import { getUserFields } from "@server/auth/google.js",
configFn: import { config } from "@server/auth/google.js",
},
@ -60,13 +60,13 @@ app SaaSTemplate {
("request-ip", "3.3.0"),
("@types/request-ip", "0.0.37"),
("node-fetch", "3.3.0"),
("react-hook-form", "7.43.1"),
("react-hook-form", "^7.45.4"),
("stripe", "11.15.0"),
],
}
/* 💽 Wasp defines DB entities via Prisma Database Models:
* https://wasp-lang.dev/docs/language/features#entity
* https://wasp-lang.dev/docs/data-model/entities
*/
entity User {=psl
@ -80,6 +80,7 @@ entity User {=psl
checkoutSessionId String?
hasPaid Boolean @default(false)
sendEmail Boolean @default(false)
subscriptionStatus String?
datePaid DateTime?
credits Int @default(3)
relatedObject RelatedObject[]
@ -108,7 +109,7 @@ psl=}
/* 📡 These are the Wasp Routes (You can protect them easily w/ 'authRequired: true');
* https://wasp-lang.dev/docs/language/features#route
* https://wasp-lang.dev/docs/tutorial/pages
*/
route RootRoute { path: "/", to: MainPage }
@ -164,7 +165,7 @@ page CheckoutPage {
}
/* ⛑ These are the Wasp Operations, which allow the client and server to interact:
* https://wasp-lang.dev/docs/language/features#queries-and-actions-aka-operations
* https://wasp-lang.dev/docs/data-model/operations/overview
*/
// 📝 Actions aka Mutations
@ -198,7 +199,7 @@ query getRelatedObjects {
/*
* 📡 These are custom Wasp API Endpoints. Use them for callbacks, webhooks, etc.
* https://wasp-lang.dev/docs/language/features#apis
* https://wasp-lang.dev/docs/advanced/apis
*/
api stripeWebhook {
@ -208,7 +209,7 @@ api stripeWebhook {
}
/* 🕵️‍♂️ These are the Wasp Cron Jobs. Use them to set up recurring tasks and/or queues:
* https://wasp-lang.dev/docs/language/features#jobs
* https://wasp-lang.dev/docs/advanced/jobs
*/
job emailChecker {

View File

@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "User" ADD COLUMN "subscriptionStatus" TEXT;

View File

@ -70,12 +70,18 @@ export default function Example({ user }: { user: User }) {
function BuyMoreButton({ isLoading, setIsLoading }: { isLoading: boolean, setIsLoading: Dispatch<SetStateAction<boolean>> }) {
const handleClick = async () => {
setIsLoading(true);
const stripeResults = await stripePayment();
if (stripeResults?.sessionUrl) {
window.open(stripeResults.sessionUrl, '_self');
try {
setIsLoading(true);
const stripeResults = await stripePayment();
if (stripeResults?.sessionUrl) {
window.open(stripeResults.sessionUrl, '_self');
}
} catch (error: any) {
alert(error?.message ?? 'Something went wrong.')
} finally {
setIsLoading(false);
}
setIsLoading(false);
};
return (

View File

@ -16,6 +16,7 @@ export const stripePayment: StripePayment<void, StripePaymentResult> = async (_a
if (!context.user) {
throw new HttpError(401);
}
let customer: Stripe.Customer;
const stripeCustomers = await stripe.customers.list({
email: context.user.email!,

View File

@ -24,7 +24,6 @@ const stripe = new Stripe(process.env.STRIPE_KEY!, {
});
export const stripeWebhook: StripeWebhook = async (request, response, context) => {
if (process.env.NODE_ENV === 'production') {
const detectedIp = requestIp.getClientIp(request) as string;
const isStripeIP = STRIPE_WEBHOOK_IPS.includes(detectedIp);
@ -42,6 +41,7 @@ export const stripeWebhook: StripeWebhook = async (request, response, context) =
event = request.body;
if (event.type === 'checkout.session.completed') {
console.log('Checkout session completed');
const session = event.data.object as Stripe.Checkout.Session;
userStripeId = session.customer as string;
@ -59,13 +59,14 @@ export const stripeWebhook: StripeWebhook = async (request, response, context) =
},
data: {
hasPaid: true,
datePaid: new Date(),
},
});
}
/**
* and here is an example of handling a different type of product
* make sure to configure it in the Stripe dashboard first!
* make sure to configure it in the Stripe dashboard first!
*/
// if (line_items?.data[0]?.price?.id === process.env.CREDITS_PRICE_ID) {
@ -81,10 +82,47 @@ export const stripeWebhook: StripeWebhook = async (request, response, context) =
// },
// });
// }
} else if (event.type === 'invoice.paid') {
console.log('>>>> invoice.paid: ', userStripeId);
const invoice = event.data.object as Stripe.Invoice;
const periodStart = new Date(invoice.period_start * 1000);
await context.entities.User.updateMany({
where: {
stripeId: userStripeId,
},
data: {
hasPaid: true,
datePaid: periodStart,
},
});
} else if (event.type === 'customer.subscription.updated') {
const subscription = event.data.object as Stripe.Subscription;
userStripeId = subscription.customer as string;
if (subscription.status === 'active') {
console.log('Subscription active ', userStripeId);
await context.entities.User.updateMany({
where: {
stripeId: userStripeId,
},
data: {
subscriptionStatus: 'active',
},
});
}
// you'll want to make a check on the front end to see if the subscription is past due
// and then prompt the user to update their payment method
// this is useful if the user's card expires or is canceled and automatic subscription renewal fails
if (subscription.status === 'past_due') {
console.log('Subscription past due: ', userStripeId);
await context.entities.User.updateMany({
where: {
stripeId: userStripeId,
},
data: {
subscriptionStatus: 'past_due',
},
});
}
/**
* Stripe will send a subscription.updated event when a subscription is canceled
* but the subscription is still active until the end of the period.