client/components/mma/paymentUpdate/PaymentDetailUpdateCheckoutSessionReturn.tsx (122 lines of code) (raw):
import * as Sentry from '@sentry/browser';
import { useCallback, useContext, useEffect } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';
import { getStripeKeyByProduct } from '@/client/utilities/stripe';
import { STRIPE_PUBLIC_KEY_HEADER } from '@/shared/stripeSetupIntent';
import { DefaultLoadingView } from '../shared/asyncComponents/DefaultLoadingView';
import {
type StripeCheckoutSession,
StripeCheckoutSessionPaymentMethodType,
} from './card/StripeCheckoutSessionButton';
import type { PaymentUpdateContextInterface } from './PaymentDetailUpdateContainer';
import { PaymentUpdateContext } from './PaymentDetailUpdateContainer';
export const PaymentDetailUpdateCheckoutSessionReturn = () => {
const { productDetail } = useContext(
PaymentUpdateContext,
) as PaymentUpdateContextInterface;
const navigate = useNavigate();
const location = useLocation();
// Parse the query parameters
const queryParams = new URLSearchParams(location.search);
const sessionId = queryParams.get('id'); // Read the 'session_id' query parameter
const paymentMethodType = queryParams.get('paymentMethodType'); // Read the 'paymentMethodType' query parameter
const getNewPaymentMethodDetailFriendlyNameFromPaymentMethodType =
useCallback((): string => {
switch (paymentMethodType) {
case StripeCheckoutSessionPaymentMethodType.Card:
return 'Credit Card';
default:
// A default designation that fits the current copywriting
return 'Payment Method';
}
}, [paymentMethodType]);
const navigateToFailedPage = useCallback(() => {
navigate('../failed', {
state: {
newPaymentMethodDetailFriendlyName:
getNewPaymentMethodDetailFriendlyNameFromPaymentMethodType(),
productDetail,
},
});
}, [
navigate,
getNewPaymentMethodDetailFriendlyNameFromPaymentMethodType,
productDetail,
]);
const obtainCheckoutSessionDetails = useCallback(
async (id: string): Promise<StripeCheckoutSession> => {
const checkoutSessionResponse = await fetch(
`/api/payment/checkout-session/${id}`,
{
method: 'GET',
credentials: 'include',
headers: {
[STRIPE_PUBLIC_KEY_HEADER]:
getStripeKeyByProduct(productDetail) ?? '',
},
},
);
return checkoutSessionResponse.json();
},
[productDetail],
);
useEffect(() => {
if (sessionId) {
obtainCheckoutSessionDetails(sessionId)
.then((checkoutSession: StripeCheckoutSession) => {
// Validate Checkout Session Payment Method
if (!checkoutSession.setup_intent?.payment_method) {
Sentry.captureException(
'Failed to load Payment Method Details',
{
extra: {
sessionId,
},
},
);
navigateToFailedPage();
}
// Validate Payment Method Type
if (
!Object.values(
StripeCheckoutSessionPaymentMethodType,
).includes(
paymentMethodType as StripeCheckoutSessionPaymentMethodType,
)
) {
Sentry.captureException('Invalid Payment Method Type', {
extra: {
paymentMethodType,
},
});
navigateToFailedPage();
}
// Execute Payment Update
navigate('../', {
state: {
paymentMethodInfo:
checkoutSession?.setup_intent?.payment_method,
paymentMethodType,
productDetail,
},
});
})
.catch(() => {
Sentry.captureException(
'Failed to load Checkout Session Details',
{
extra: {
sessionId,
},
},
);
navigateToFailedPage();
});
} else {
navigateToFailedPage();
}
}, [
sessionId,
paymentMethodType,
productDetail,
navigate,
navigateToFailedPage,
obtainCheckoutSessionDetails,
]);
return sessionId && paymentMethodType ? (
<DefaultLoadingView loadingMessage="Obtaining payment method information..." />
) : null;
};