From 4b50525a7b61cb39a03913571ddb8676bba48654 Mon Sep 17 00:00:00 2001 From: Zicklag Date: Sat, 14 Dec 2024 15:36:05 -0600 Subject: [PATCH] feat: add an order confirmation page when purchasing a subscription. --- package.json | 2 + pnpm-lock.yaml | 16 ++++ src/hooks.ts | 7 +- src/lib/billing.ts | 15 +++- src/routes/(app)/[username]/+layout.svelte | 2 +- .../(app)/order-confirmation/+page.svelte | 75 +++++++++++++++++++ .../(app)/order-confirmation/check/+server.ts | 14 ++++ 7 files changed, 127 insertions(+), 4 deletions(-) create mode 100644 src/routes/(app)/order-confirmation/+page.svelte create mode 100644 src/routes/(app)/order-confirmation/check/+server.ts diff --git a/package.json b/package.json index 45c37e5..898c2de 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "@sveltejs/vite-plugin-svelte": "4.0.0-next.6", "@tailwindcss/forms": "^0.5.9", "@tailwindcss/typography": "^0.5.15", + "@types/canvas-confetti": "^1.6.4", "@types/cookie": "^0.6.0", "@types/dns-packet": "^5.6.5", "@types/eslint": "^8.56.12", @@ -43,6 +44,7 @@ "@typescript-eslint/eslint-plugin": "^7.18.0", "@typescript-eslint/parser": "^7.18.0", "autoprefixer": "^10.4.20", + "canvas-confetti": "^1.9.3", "codemirror": "^6.0.1", "cookie": "^0.6.0", "date-fns": "^3.6.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b132f24..62e891d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -74,6 +74,9 @@ importers: '@tailwindcss/typography': specifier: ^0.5.15 version: 0.5.15(tailwindcss@3.4.15) + '@types/canvas-confetti': + specifier: ^1.6.4 + version: 1.6.4 '@types/cookie': specifier: ^0.6.0 version: 0.6.0 @@ -110,6 +113,9 @@ importers: autoprefixer: specifier: ^10.4.20 version: 10.4.20(postcss@8.4.49) + canvas-confetti: + specifier: ^1.9.3 + version: 1.9.3 codemirror: specifier: ^6.0.1 version: 6.0.1(@lezer/common@1.2.3) @@ -1255,6 +1261,9 @@ packages: '@tootallnate/quickjs-emscripten@0.23.0': resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} + '@types/canvas-confetti@1.6.4': + resolution: {integrity: sha512-fNyZ/Fdw/Y92X0vv7B+BD6ysHL4xVU5dJcgzgxLdGbn8O3PezZNIJpml44lKM0nsGur+o/6+NZbZeNTt00U1uA==} + '@types/cookie@0.6.0': resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} @@ -1559,6 +1568,9 @@ packages: caniuse-lite@1.0.30001684: resolution: {integrity: sha512-G1LRwLIQjBQoyq0ZJGqGIJUXzJ8irpbjHLpVRXDvBEScFJ9b17sgK6vlx0GAJFE21okD7zXl08rRRUfq6HdoEQ==} + canvas-confetti@1.9.3: + resolution: {integrity: sha512-rFfTURMvmVEX1gyXFgn5QMn81bYk70qa0HLzcIOSVEyl57n6o9ItHeBtUSWdvKAPY0xlvBHno4/v3QPrT83q9g==} + ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -4195,6 +4207,8 @@ snapshots: '@tootallnate/quickjs-emscripten@0.23.0': {} + '@types/canvas-confetti@1.6.4': {} + '@types/cookie@0.6.0': {} '@types/dns-packet@5.6.5': @@ -4513,6 +4527,8 @@ snapshots: caniuse-lite@1.0.30001684: {} + canvas-confetti@1.9.3: {} + ccount@2.0.1: {} chai@5.1.2: diff --git a/src/hooks.ts b/src/hooks.ts index 40f830b..7efb154 100644 --- a/src/hooks.ts +++ b/src/hooks.ts @@ -10,8 +10,11 @@ export const reroute: Reroute = ({ url }) => { return url.pathname; } - // If this is a lemonsqueezy webhook. - if (url.host == env.PUBLIC_POLAR_WEBHOOK_DOMAIN) { + // If this is a polar webhook. + if ( + url.host == env.PUBLIC_POLAR_WEBHOOK_DOMAIN && + url.pathname == '/__internal__/polar-webhook' + ) { return '/__internal__/polar-webhook'; } diff --git a/src/lib/billing.ts b/src/lib/billing.ts index 52824f7..230aa3c 100644 --- a/src/lib/billing.ts +++ b/src/lib/billing.ts @@ -60,7 +60,7 @@ class BillingEngine { }, allowDiscountCodes: true, discountId: env.POLAR_AUTO_DISCOUNT_ID, - successUrl: pubenv.PUBLIC_URL + '/my-profile' + successUrl: pubenv.PUBLIC_URL + `/order-confirmation` }); return checkout.url; @@ -197,6 +197,19 @@ class BillingEngine { const subscriptionInfo = await this.getSubscriptionInfo(rauthyId); await updateUserSubscriptionBenefits(rauthyId, subscriptionInfo.benefits); } + + /** Checks whether or not the subscription associated to a checkout has been received over the + * webhook. */ + async checkoutSubscriptionIsReady(checkoutId: string): Promise { + const checkout = await this.polar.checkouts.custom.get({ id: checkoutId }); + + const rauthyId = checkout.metadata.rauthyId; + if (typeof rauthyId != 'string') return false; + + const info = await this.getSubscriptionInfo(rauthyId); + + return !!info.subscriptions.find((s) => s.checkoutId == checkoutId); + } } export const billing = new BillingEngine(); diff --git a/src/routes/(app)/[username]/+layout.svelte b/src/routes/(app)/[username]/+layout.svelte index f4cebe7..4b82c68 100644 --- a/src/routes/(app)/[username]/+layout.svelte +++ b/src/routes/(app)/[username]/+layout.svelte @@ -51,7 +51,7 @@ }); -
+
{#if data.profileMatchesUserSession}