feat(client): refine payment handling and improve type safety in components

This commit is contained in:
Stevan Freeborn
2026-01-04 21:44:05 -06:00
parent 4f485644eb
commit 74b50f120b
7 changed files with 40 additions and 40 deletions
+2 -2
View File
@@ -7,7 +7,7 @@ import PaymentForm from './PaymentForm';
import PaymentConfirmationCard from './PaymentConfirmationCard';
import PreviousPaymentsList from './PreviousPaymentsList';
const stripe = loadStripe(import.meta.env.VITE_STRIPE_API_KEY);
const stripe = loadStripe(import.meta.env.VITE_STRIPE_API_KEY as string);
function App() {
const queryParams = new URLSearchParams(window.location.search);
@@ -44,7 +44,7 @@ function App() {
return;
}
const data = await res.json();
const data = await res.json() as { clientSecret: string };
setSecret(data.clientSecret);
} catch (err) {
console.error(err);
@@ -32,7 +32,7 @@ export default function CheckoutForm() {
}
return (
<form onSubmit={handleSubmit}>
<form onSubmit={e => void handleSubmit(e)}>
<PaymentElement
id='payment-element'
options={{ layout: 'accordion' }}
@@ -58,7 +58,7 @@ export default function PaymentConfirmationCard({ clientSecret }: PaymentConfirm
}
}
fetchPaymentIntent();
void fetchPaymentIntent();
return () => {
isMounted = false;
@@ -1,7 +1,7 @@
import { useState, useRef } from 'react';
type DonationFormProps = {
onValidSubmit: (data: { name: string; amount: number; message?: string; email?: string }) => void;
onValidSubmit: (data: { name: string; amount: number; message?: string; email?: string }) => Promise<void> | void;
isSubmitting?: boolean;
};
@@ -98,12 +98,12 @@ export default function PaymentForm({ onValidSubmit, isSubmitting }: DonationFor
throw new Error('amount after validation should never be an empty string');
}
onValidSubmit({ name, amount, message, email });
await onValidSubmit({ name, amount, message, email });
}
return (
<form
onSubmit={handleSubmit}
onSubmit={e => void handleSubmit(e)}
noValidate
>
<div className='group'>
@@ -45,7 +45,7 @@ export default function PreviousPaymentsList() {
setPaymentData({ status: 'error', message: 'Failed to fetch payments' });
}
const data = await res.json();
const data = await res.json() as PaymentPage;
setPaymentData({ status: 'success', pages: [data] });
} catch (err) {
@@ -58,7 +58,7 @@ export default function PreviousPaymentsList() {
}
}
fetchPayments();
void fetchPayments();
return () => {
isMounted = false;
@@ -84,7 +84,7 @@ export default function PreviousPaymentsList() {
return;
}
const data = await res.json();
const data = await res.json() as PaymentPage;
setPaymentData({
status: 'success',
@@ -117,7 +117,7 @@ export default function PreviousPaymentsList() {
<button
className='load-more-button'
type='button'
onClick={handleLoadMoreButtonClick}
onClick={() => void handleLoadMoreButtonClick()}
disabled={currentPageNumber >= totalNumberOfPages || isLoadingMore}
>
Load More
+3 -2
View File
@@ -1,7 +1,8 @@
@font-face {
font-family: 'CaskaydiaCove NFM';
src: url('/CaskaydiaCoveNFM-Regular.eot');
src: url('/CaskaydiaCoveNFM-Regular.eot?#iefix') format('embedded-opentype'),
src:
url('/CaskaydiaCoveNFM-Regular.eot?#iefix') format('embedded-opentype'),
url('/CaskaydiaCoveNFM-Regular.woff2') format('woff2'),
url('/CaskaydiaCoveNFM-Regular.woff') format('woff'),
url('/CaskaydiaCoveNFM-Regular.svg#CaskaydiaCoveNFM-Regular') format('svg');
@@ -56,7 +57,7 @@ table {
:root {
--bg-color: #323232;
--text-color: #E4E4E4;
--text-color: #e4e4e4;
font-size: 16px;
font-family: 'CaskaydiaCove NFM', monospace;
@@ -31,11 +31,11 @@ describe('form', () => {
user = userEvent.setup();
vi.stubGlobal('fetch', mockFetch);
mockFetch.mockImplementation(async (url: URL) => {
mockFetch.mockImplementation((url: URL) => {
if (url.toString().endsWith('/payments/create-intent')) {
return {
ok: true,
json: async () => ({
json: () => ({
clientSecret: 'test_client_secret',
}),
};
@@ -44,7 +44,7 @@ describe('form', () => {
if (url.toString().endsWith('/payments')) {
return {
ok: true,
json: async () => ({
json: () => ({
payments: [],
}),
};
@@ -118,7 +118,6 @@ describe('form', () => {
await user.type(amountInput, '10');
await user.click(submitButton);
});
test('it should validate email if provided', async () => {