Merge pull request #95 from jcreek/76-add-pagination-for-stripe-orders-on-account-page

76 add pagination for stripe orders on account page
This commit is contained in:
Olly
2024-11-19 20:05:16 +00:00
committed by GitHub
3 changed files with 146 additions and 11 deletions
+19 -3
View File
@@ -590,7 +590,12 @@ const getUserSubscriptions = async (userId: string) => {
}
};
const getUserTransactions = async (userId: string) => {
const getUserTransactions = async (
userId: string,
perPage: number,
startingAfter: string | undefined = undefined,
endingBefore: string | undefined = undefined
) => {
try {
// Step 1: Retrieve the customer ID associated with the user
const { data, error } = await supabaseAdmin
@@ -610,10 +615,21 @@ const getUserTransactions = async (userId: string) => {
}
// Step 2: Fetch charge transactions from Stripe
const charges = await stripeClient.charges.list({ customer: customerId });
const params: stripe.ChargeListParams = {
customer: customerId,
limit: perPage
};
if (startingAfter) params.starting_after = startingAfter;
if (endingBefore) params.ending_before = endingBefore;
const charges = await stripeClient.charges.list(params);
const hasNextPage = charges.has_more;
// Step 3: Format transaction data
const transactions = charges.data.map((charge) => ({
id: charge.id,
amount: (charge.amount / 100).toFixed(2),
currency: charge.currency.toUpperCase(),
description: charge.description ?? 'No description provided',
@@ -626,7 +642,7 @@ const getUserTransactions = async (userId: string) => {
receipt_url: charge.receipt_url
}));
return transactions;
return { transactions, hasNextPage };
} catch (error) {
console.error('An error occurred while retrieving transactions:', error);
throw new Error('Could not retrieve transactions');
+54 -2
View File
@@ -4,6 +4,8 @@ import logger from '$lib/utils/logger/logger';
import { getUserSubscriptions, getUserTransactions } from '$lib/utils/supabase/admin';
import { requestAccountDeletion } from '$lib/utils/supabase/admin';
const transactionsPerPage = 5;
export const load: PageServerLoad = async ({ locals: { supabase, safeGetSession } }) => {
const { session } = await safeGetSession();
@@ -19,9 +21,21 @@ export const load: PageServerLoad = async ({ locals: { supabase, safeGetSession
const subscriptions = await getUserSubscriptions(session.user.id);
const transactions = await getUserTransactions(session.user.id);
const transactionsData = await getUserTransactions(session.user.id, transactionsPerPage);
return { session, user, subscriptions, transactions };
const transactions = transactionsData.transactions;
const firstTransactionId = transactions.length > 0 ? transactions[0].id : undefined;
const hasMoreThanOnePage = transactionsData.hasNextPage;
return {
session,
user,
subscriptions,
transactions,
firstTransactionId,
hasMoreThanOnePage,
pageSize: transactionsPerPage
};
};
export const actions: Actions = {
@@ -78,5 +92,43 @@ export const actions: Actions = {
return {
name
};
},
paginate: async ({ request, locals: { safeGetSession } }) => {
const formData = await request.formData();
const pageSize = transactionsPerPage;
let startingAfter = formData.get('startingAfter')?.toString() || undefined;
if (startingAfter === 'undefined') {
startingAfter = undefined;
}
let endingBefore = formData.get('endingBefore')?.toString() || undefined;
if (endingBefore === 'undefined') {
endingBefore = undefined;
}
const firstTransactionId = formData.get('firstTransactionId')?.toString();
const hasMoreThanOnePage = formData.get('hasMoreThanOnePage') === 'true';
const { session } = await safeGetSession();
if (!session) return fail(401, { error: 'Not authenticated' });
try {
const { transactions, hasNextPage } = await getUserTransactions(
session.user.id,
pageSize,
startingAfter,
endingBefore
);
const isFirstPage = transactions.length > 0 && transactions[0].id === firstTransactionId;
return {
transactions: JSON.stringify(transactions),
hasNextPage: hasNextPage || (isFirstPage && hasMoreThanOnePage),
isFirstPage
};
} catch (error) {
logger.error('Failed to fetch transactions', { userId: session.user.id, error });
return fail(500, { error: 'Failed to load transactions' });
}
}
};
+73 -6
View File
@@ -5,8 +5,8 @@
export let data;
export let form;
let { session, user, subscriptions, transactions } = data;
$: ({ session, supabase, user } = data);
let { session, user, subscriptions, transactions, firstTransactionId, hasMoreThanOnePage } = data;
$: ({ session, user, transactions, firstTransactionId, hasMoreThanOnePage } = data);
let profileForm: HTMLFormElement;
let loading = false;
@@ -39,6 +39,22 @@
loading = false;
};
};
let startingAfter: string | undefined = undefined;
let endingBefore: string | undefined = undefined;
let hasNextPage = hasMoreThanOnePage;
let hasPreviousPage = false;
const handlePaginationSubmit: SubmitFunction = () => {
loading = true;
return async ({ result }) => {
transactions = JSON.parse(result.data.transactions);
hasNextPage = result.data.hasNextPage;
hasPreviousPage = !result.data.isFirstPage;
loading = false;
};
};
</script>
<div
@@ -126,8 +142,9 @@
<!-- Billing History -->
<section class="space-y-4">
<h2 class="text-xl font-semibold">Billing History</h2>
<ul class="space-y-3">
{#if transactions}
{#if transactions && transactions.length > 0}
<ul class="space-y-3">
{#each transactions as transaction}
<li class="flex justify-between p-4 border border-gray-200 rounded-md">
<div>
@@ -146,8 +163,58 @@
{/if}
</li>
{/each}
{/if}
</ul>
</ul>
{:else}
<p class="text-gray-600">No transactions found.</p>
{/if}
<!-- Pagination Form -->
<form method="post" action="?/paginate" use:enhance={handlePaginationSubmit}>
<div
class="flex justify-center items-center space-x-2 mt-4"
role="navigation"
aria-label="Transactions pagination"
>
<input type="hidden" name="startingAfter" value={startingAfter} />
<input type="hidden" name="endingBefore" value={endingBefore} />
<input type="hidden" name="firstTransactionId" value={firstTransactionId} />
<input type="hidden" name="hasMoreThanOnePage" value={hasMoreThanOnePage} />
<button
type="submit"
name="direction"
value="previous"
class="btn btn-outline"
disabled={!hasPreviousPage || loading}
aria-label="View previous page of transactions"
on:click={() => {
if (transactions.length) {
endingBefore = transactions[0].id;
startingAfter = undefined;
}
}}
>
Previous
</button>
<button
type="submit"
name="direction"
value="next"
class="btn btn-outline"
disabled={!hasNextPage || loading}
aria-label="View next page of transactions"
on:click={() => {
if (transactions.length) {
startingAfter = transactions[transactions.length - 1].id;
endingBefore = undefined;
}
}}
>
Next
</button>
</div>
</form>
</section>
</div>