mirror of
https://github.com/jcreek/SvelteKitSaasBoilerplate.git
synced 2026-07-14 19:43:55 +00:00
Merge pull request #39 from jcreek/32-set-up-separate-flow-where-subscriptions-are-done-with-a-button-directly-from-the-product-page-and-cannot-be-added-to-the-basket
feat(#32): Add separate flow for subscriptions
This commit is contained in:
@@ -0,0 +1,41 @@
|
|||||||
|
import { type RequestHandler, redirect } from '@sveltejs/kit';
|
||||||
|
import { stripe as stripeClient } from '$lib/utils/stripe';
|
||||||
|
|
||||||
|
// Create a subscription checkout session
|
||||||
|
export const POST: RequestHandler = async ({ request, cookies, locals: { safeGetSession } }) => {
|
||||||
|
const { session } = await safeGetSession();
|
||||||
|
|
||||||
|
if (!session) {
|
||||||
|
// If no session is found, the user isn't authenticated, so block the action
|
||||||
|
return new Response('Unauthorized', { status: 401 });
|
||||||
|
}
|
||||||
|
|
||||||
|
const userId = session.user.id;
|
||||||
|
|
||||||
|
// Get the price ID from the request body
|
||||||
|
const { priceId } = await request.json();
|
||||||
|
|
||||||
|
if (!priceId) {
|
||||||
|
return new Response('Price ID is required', { status: 400 });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a subscription checkout session with Stripe
|
||||||
|
const checkoutSession = await stripeClient.checkout.sessions.create({
|
||||||
|
line_items: [
|
||||||
|
{
|
||||||
|
price: priceId,
|
||||||
|
quantity: 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
mode: 'subscription',
|
||||||
|
success_url: `${request.headers.get('origin')}/checkout/success`,
|
||||||
|
cancel_url: `${request.headers.get('origin')}/checkout/cancelled`,
|
||||||
|
metadata: {
|
||||||
|
userId: userId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Store the checkout session.id for access from the frontend
|
||||||
|
cookies.set('checkout_session_id', checkoutSession.id, { path: '/' });
|
||||||
|
return redirect(303, checkoutSession.url as string);
|
||||||
|
};
|
||||||
@@ -44,6 +44,20 @@
|
|||||||
}, 5000);
|
}, 5000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function startSubscription() {
|
||||||
|
fetch('/api/subscribe', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ priceId: item.priceId })
|
||||||
|
})
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((data) => {
|
||||||
|
console.log(data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let item = {};
|
let item = {};
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
@@ -58,7 +72,8 @@
|
|||||||
imgSrc: product.images[0],
|
imgSrc: product.images[0],
|
||||||
price: 0,
|
price: 0,
|
||||||
priceId: product.default_price,
|
priceId: product.default_price,
|
||||||
quantity: 1
|
quantity: 1,
|
||||||
|
isSubscription: product.isSubscription
|
||||||
};
|
};
|
||||||
|
|
||||||
// Fetch the price of the product
|
// Fetch the price of the product
|
||||||
@@ -301,6 +316,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div> -->
|
</div> -->
|
||||||
|
|
||||||
|
{#if !item.isSubscription}
|
||||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3 py-8">
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3 py-8">
|
||||||
<div class="flex sm:items-center sm:justify-center w-full">
|
<div class="flex sm:items-center sm:justify-center w-full">
|
||||||
<button
|
<button
|
||||||
@@ -392,8 +408,9 @@
|
|||||||
Add to basket</button
|
Add to basket</button
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
{:else}
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
<button
|
<!-- <button
|
||||||
class="group transition-all duration-500 p-4 rounded-full bg-indigo-50 hover:bg-indigo-100 hover:shadow-sm hover:shadow-indigo-300"
|
class="group transition-all duration-500 p-4 rounded-full bg-indigo-50 hover:bg-indigo-100 hover:shadow-sm hover:shadow-indigo-300"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
@@ -412,13 +429,15 @@
|
|||||||
stroke-linejoin="round"
|
stroke-linejoin="round"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button> -->
|
||||||
<button
|
<button
|
||||||
class="text-center w-full px-5 py-4 rounded-[100px] bg-indigo-600 flex items-center justify-center font-semibold text-lg text-white shadow-sm transition-all duration-500 hover:bg-indigo-700 hover:shadow-indigo-400"
|
class="text-center w-full px-5 py-4 rounded-[100px] bg-indigo-600 flex items-center justify-center font-semibold text-lg text-white shadow-sm transition-all duration-500 hover:bg-indigo-700 hover:shadow-indigo-400"
|
||||||
|
on:click={startSubscription}
|
||||||
>
|
>
|
||||||
Buy Now
|
Subscribe
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
import { json } from '@sveltejs/kit';
|
import { json } from '@sveltejs/kit';
|
||||||
import { stripe as stripeClient } from '$lib/utils/stripe';
|
import { stripe as stripeClient } from '$lib/utils/stripe';
|
||||||
|
import Stripe from 'stripe';
|
||||||
|
|
||||||
export const GET = async ({ params }) => {
|
export const GET = async ({ params }) => {
|
||||||
const { productId } = params;
|
const { productId } = params;
|
||||||
const product = await stripeClient.products.retrieve(productId);
|
const product = await stripeClient.products.retrieve(productId);
|
||||||
|
|
||||||
|
const price = await stripeClient.prices.retrieve(product.default_price);
|
||||||
|
|
||||||
|
const isSubscription = price.type === ('recurring' as Stripe.Price.type);
|
||||||
|
product.isSubscription = isSubscription;
|
||||||
return json(product);
|
return json(product);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user