diff --git a/.changeset/mighty-worms-watch.md b/.changeset/mighty-worms-watch.md
new file mode 100644
index 00000000000..b5118a50901
--- /dev/null
+++ b/.changeset/mighty-worms-watch.md
@@ -0,0 +1,5 @@
+---
+"@clerk/clerk-js": patch
+---
+
+Show a localized message for all errors returned from the backend if the user tries to perform an invalid plan change.
diff --git a/packages/clerk-js/bundlewatch.config.json b/packages/clerk-js/bundlewatch.config.json
index 72395d72abe..47b4a4fdd85 100644
--- a/packages/clerk-js/bundlewatch.config.json
+++ b/packages/clerk-js/bundlewatch.config.json
@@ -21,7 +21,7 @@
{ "path": "./dist/waitlist*.js", "maxSize": "1.3KB" },
{ "path": "./dist/keylessPrompt*.js", "maxSize": "6.5KB" },
{ "path": "./dist/pricingTable*.js", "maxSize": "4.02KB" },
- { "path": "./dist/checkout*.js", "maxSize": "5.2KB" },
+ { "path": "./dist/checkout*.js", "maxSize": "5.3KB" },
{ "path": "./dist/paymentSources*.js", "maxSize": "8.9KB" },
{ "path": "./dist/up-billing-page*.js", "maxSize": "2.4KB" },
{ "path": "./dist/op-billing-page*.js", "maxSize": "2.4KB" },
diff --git a/packages/clerk-js/src/ui/components/Checkout/CheckoutPage.tsx b/packages/clerk-js/src/ui/components/Checkout/CheckoutPage.tsx
index 3f888afc149..428b6faff75 100644
--- a/packages/clerk-js/src/ui/components/Checkout/CheckoutPage.tsx
+++ b/packages/clerk-js/src/ui/components/Checkout/CheckoutPage.tsx
@@ -1,7 +1,11 @@
-import type { __experimental_CheckoutProps, __experimental_CommerceCheckoutResource } from '@clerk/types';
+import type {
+ __experimental_CheckoutProps,
+ __experimental_CommerceCheckoutResource,
+ ClerkAPIError,
+} from '@clerk/types';
import { useEffect } from 'react';
-import { Alert, Box, localizationKeys, Spinner } from '../../customizables';
+import { Alert, Box, Flex, localizationKeys, Spinner, useLocalizations } from '../../customizables';
import { Drawer, useDrawerContext } from '../../elements';
import { useCheckout } from '../../hooks';
import { EmailForm } from '../UserProfile/EmailForm';
@@ -9,15 +13,18 @@ import { CheckoutComplete } from './CheckoutComplete';
import { CheckoutForm } from './CheckoutForm';
export const CheckoutPage = (props: __experimental_CheckoutProps) => {
+ const { translateError } = useLocalizations();
const { planId, planPeriod, subscriberType, onSubscriptionComplete } = props;
const { setIsOpen, isOpen } = useDrawerContext();
- const { checkout, isLoading, invalidate, revalidate, updateCheckout, isMissingPayerEmail } = useCheckout({
+ const { checkout, isLoading, invalidate, revalidate, updateCheckout, errors } = useCheckout({
planId,
planPeriod,
subscriberType,
});
+ const isMissingPayerEmail = !!errors?.some((e: ClerkAPIError) => e.code === 'missing_payer_email');
+
const onCheckoutComplete = (newCheckout: __experimental_CommerceCheckoutResource) => {
invalidate(); // invalidate the initial checkout on complete
updateCheckout(newCheckout);
@@ -74,16 +81,20 @@ export const CheckoutPage = (props: __experimental_CheckoutProps) => {
}
return (
- <>
- {/* TODO(@COMMERCE): needs localization */}
-
+ ({
+ height: '100%',
+ padding: t.space.$4,
+ fontSize: t.fontSizes.$md,
+ })}
>
- There was a problem, please try again later.
-
- >
+
+ {errors ? translateError(errors[0]) : 'There was a problem, please try again later.'}
+
+
+
);
};
diff --git a/packages/clerk-js/src/ui/hooks/useCheckout.ts b/packages/clerk-js/src/ui/hooks/useCheckout.ts
index 68e05ef6d2f..5dac8c76cb9 100644
--- a/packages/clerk-js/src/ui/hooks/useCheckout.ts
+++ b/packages/clerk-js/src/ui/hooks/useCheckout.ts
@@ -1,9 +1,6 @@
+import type { ClerkAPIResponseError } from '@clerk/shared/error';
import { useClerk, useOrganization, useUser } from '@clerk/shared/react';
-import type {
- __experimental_CheckoutProps,
- __experimental_CommerceCheckoutResource,
- ClerkAPIError,
-} from '@clerk/types';
+import type { __experimental_CheckoutProps, __experimental_CommerceCheckoutResource } from '@clerk/types';
import { useCallback, useEffect, useState } from 'react';
import { useFetch } from './useFetch';
@@ -20,7 +17,7 @@ export const useCheckout = (props: __experimental_CheckoutProps) => {
isLoading,
invalidate,
revalidate,
- error,
+ error: _error,
} = useFetch(
__experimental_commerce?.__experimental_billing.startCheckout,
{
@@ -32,6 +29,8 @@ export const useCheckout = (props: __experimental_CheckoutProps) => {
`commerce-checkout-${user?.id}`,
);
+ const error = _error as ClerkAPIResponseError | undefined;
+
const updateCheckout = useCallback((newCheckout: __experimental_CommerceCheckoutResource) => {
setCurrentCheckout(newCheckout);
}, []);
@@ -48,6 +47,6 @@ export const useCheckout = (props: __experimental_CheckoutProps) => {
isLoading,
invalidate,
revalidate,
- isMissingPayerEmail: error?.errors.some((e: ClerkAPIError) => e.code === 'missing_payer_email'),
+ errors: error?.errors,
};
};