diff --git a/src/lib/components/checkout/OrderConfirmationItem.svelte b/src/lib/components/checkout/OrderConfirmationItem.svelte
index abdca69..2a9bb5a 100644
--- a/src/lib/components/checkout/OrderConfirmationItem.svelte
+++ b/src/lib/components/checkout/OrderConfirmationItem.svelte
@@ -1,10 +1,12 @@
@@ -18,17 +20,17 @@
{itemName}
-
{itemCategoryDescription}
-
+ -->
- £ {price.toFixed(2)}
+ { formatCurrency(price, currency) }
Qty: {quantity}
@@ -43,7 +45,7 @@
- £{(price * quantity).toFixed(2)}
+ { formatCurrency(price, currency) }
diff --git a/src/lib/utils/currency.ts b/src/lib/utils/currency.ts
new file mode 100644
index 0000000..952be19
--- /dev/null
+++ b/src/lib/utils/currency.ts
@@ -0,0 +1,6 @@
+export function formatCurrency(amount: number, currency: string): string {
+ return new Intl.NumberFormat('en-GB', {
+ style: 'currency',
+ currency: currency,
+ }).format(amount);
+}
\ No newline at end of file
diff --git a/src/routes/api/checkout/+server.ts b/src/routes/api/checkout/+server.ts
index 8b6c306..28f0a8d 100644
--- a/src/routes/api/checkout/+server.ts
+++ b/src/routes/api/checkout/+server.ts
@@ -5,7 +5,7 @@ import stripe from 'stripe';
const stripeClient = new stripe(PUBLIC_STRIPE_SECRET_KEY);
// Create a checkout session
-export const POST: RequestHandler = async ({ request }) => {
+export const POST: RequestHandler = async ({ request, cookies }) => {
const formData = new URLSearchParams(await request.text());
const items: { priceId: string; quantity: number }[] = [];
@@ -26,8 +26,7 @@ export const POST: RequestHandler = async ({ request }) => {
cancel_url: `${request.headers.get('origin')}/checkout/cancelled`
});
- // TODO - Store the checkout session.id for access from the frontend
- // https://docs.stripe.com/api/checkout/sessions/retrieve
-
+ // Store the checkout session.id for access from the frontend
+ cookies.set('checkout_session_id', session.id, { path: '/' });
return redirect(303, session.url as string);
};
diff --git a/src/routes/api/checkout/status/+server.ts b/src/routes/api/checkout/status/+server.ts
new file mode 100644
index 0000000..dde7781
--- /dev/null
+++ b/src/routes/api/checkout/status/+server.ts
@@ -0,0 +1,21 @@
+import { json } from '@sveltejs/kit';
+import { PUBLIC_STRIPE_SECRET_KEY } from '$env/static/public';
+import stripe from 'stripe';
+import type { RequestHandler } from './$types';
+const stripeClient = new stripe(PUBLIC_STRIPE_SECRET_KEY);
+
+export const GET: RequestHandler = async ({ cookies }) => {
+ const sessionId = cookies.get('checkout_session_id');
+ if (!sessionId) {
+ return json({ error: 'No checkout session found' }, { status: 400 });
+ }
+ const checkoutSession = await stripeClient.checkout.sessions.retrieve(sessionId, { expand: ['line_items'] });
+
+ const statusResponse = {
+ checkoutSession: checkoutSession,
+ paymentStatus: checkoutSession.payment_status,
+ lineItems: checkoutSession.line_items
+ };
+
+ return json(statusResponse);
+};
diff --git a/src/routes/checkout/success/+page.svelte b/src/routes/checkout/success/+page.svelte
index cd8fab6..45d89b7 100644
--- a/src/routes/checkout/success/+page.svelte
+++ b/src/routes/checkout/success/+page.svelte
@@ -2,19 +2,27 @@
import { onMount, onDestroy } from 'svelte';
import { basket, type Basket, type Item } from '$lib/stores/basket.js';
import OrderConfirmationItem from '$lib/components/checkout/OrderConfirmationItem.svelte';
+ import { formatCurrency } from '$lib/utils/currency';
+ import type { PageData } from './$types';
- let orderConfirmationBasket: Basket;
+ export let data: PageData;
let localBasket: Basket;
const unsubscribe = basket.subscribe((value) => {
localBasket = value;
});
+
+ let {
+ checkoutSession,
+ lineItems,
+ paymentStatus
+ } = data;
+
onDestroy(unsubscribe);
onMount(() => {
calculateSubtotal();
- // Create a deep copy of the basket to store the order confirmation then clear the basket
- orderConfirmationBasket = JSON.parse(JSON.stringify(localBasket));
+ // Clear the basket
localBasket = { items: [], subtotal: 0 };
basket.set(localBasket);
unsubscribe();
@@ -60,19 +68,17 @@
>
-->
- {#if orderConfirmationBasket == undefined}
+ {#if lineItems.length == 0}
No items in the basket
{:else}
- {#each orderConfirmationBasket.items as item (item.id)}
+ {#each lineItems as item (item.id)}
{/each}
{/if}
@@ -82,7 +88,9 @@
>
- Total Price: $xx.xx
+ {#if checkoutSession?.amount_total != null}
+ Total Price: {formatCurrency(checkoutSession?.amount_total / 100, checkoutSession?.currency ?? 'gbp')}
+ {/if}
diff --git a/src/routes/checkout/success/+page.ts b/src/routes/checkout/success/+page.ts
new file mode 100644
index 0000000..82c4ce4
--- /dev/null
+++ b/src/routes/checkout/success/+page.ts
@@ -0,0 +1,27 @@
+import type { PageLoad } from './$types';
+import { redirect } from '@sveltejs/kit';
+import Stripe from 'stripe';
+
+export const load: PageLoad = async ({fetch}) => {
+ const response = await fetch('/api/checkout/status');
+ if (!response.ok) {
+ console.error('Failed to fetch checkout status');
+ return;
+ }
+
+ const responseJson = await response.json();
+ const checkoutSession: Stripe.Checkout.Session = responseJson.checkoutSession;
+ const lineItems: Stripe.LineItem[] = responseJson.lineItems.data;
+ const paymentStatus: Stripe.Checkout.Session.PaymentStatus = responseJson.paymentStatus;
+
+ if (paymentStatus == 'unpaid') {
+ throw redirect(303, '/checkout/cancelled');
+ }
+
+ return {
+ checkoutSession,
+ lineItems,
+ paymentStatus
+ };
+};
+