diff --git a/.changeset/eighty-breads-knock.md b/.changeset/eighty-breads-knock.md
new file mode 100644
index 00000000000..0a0d866c029
--- /dev/null
+++ b/.changeset/eighty-breads-knock.md
@@ -0,0 +1,5 @@
+---
+'@clerk/clerk-js': patch
+---
+
+Display alert on plan details error
diff --git a/packages/clerk-js/src/ui/components/Plans/PlanDetails.tsx b/packages/clerk-js/src/ui/components/Plans/PlanDetails.tsx
index 97e4dd8feb1..b10f6685aaa 100644
--- a/packages/clerk-js/src/ui/components/Plans/PlanDetails.tsx
+++ b/packages/clerk-js/src/ui/components/Plans/PlanDetails.tsx
@@ -1,15 +1,32 @@
import { useClerk } from '@clerk/shared/react';
-import type { __internal_PlanDetailsProps, CommercePlanResource, CommerceSubscriptionPlanPeriod } from '@clerk/types';
+import type {
+ __internal_PlanDetailsProps,
+ ClerkAPIResponseError,
+ CommercePlanResource,
+ CommerceSubscriptionPlanPeriod,
+} from '@clerk/types';
import * as React from 'react';
import { useMemo, useState } from 'react';
import useSWR from 'swr';
+import { Alert } from '@/ui/elements/Alert';
import { Avatar } from '@/ui/elements/Avatar';
import { Drawer } from '@/ui/elements/Drawer';
import { Switch } from '@/ui/elements/Switch';
import { SubscriberTypeContext } from '../../contexts';
-import { Box, Col, descriptors, Flex, Heading, localizationKeys, Span, Spinner, Text } from '../../customizables';
+import {
+ Box,
+ Col,
+ descriptors,
+ Flex,
+ Heading,
+ localizationKeys,
+ Span,
+ Spinner,
+ Text,
+ useLocalizations,
+} from '../../customizables';
export const PlanDetails = (props: __internal_PlanDetailsProps) => {
return (
@@ -19,6 +36,39 @@ export const PlanDetails = (props: __internal_PlanDetailsProps) => {
);
};
+const BodyFiller = ({ children }: { children: React.ReactNode }) => {
+ return (
+ ({
+ display: 'flex',
+ flexDirection: 'column',
+ alignItems: 'center',
+ justifyContent: 'center',
+ flex: 1,
+ overflowY: 'auto',
+ padding: t.space.$4,
+ gap: t.space.$4,
+ })}
+ >
+ {children}
+
+ );
+};
+
+const PlanDetailsError = ({ error }: { error: ClerkAPIResponseError }) => {
+ const { translateError } = useLocalizations();
+ return (
+
+
+ {translateError(error.errors[0])}
+
+
+ );
+};
+
const PlanDetailsInternal = ({
planId,
plan: initialPlan,
@@ -27,29 +77,34 @@ const PlanDetailsInternal = ({
const clerk = useClerk();
const [planPeriod, setPlanPeriod] = useState(initialPlanPeriod);
- const { data: plan, isLoading } = useSWR(
+ const {
+ data: plan,
+ isLoading,
+ error,
+ } = useSWR(
planId || initialPlan ? { type: 'plan', id: planId || initialPlan?.id } : null,
// @ts-expect-error we are handling it above
() => clerk.billing.getPlan({ id: planId || initialPlan?.id }),
{
fallbackData: initialPlan,
+ revalidateOnFocus: false,
+ shouldRetryOnError: false,
+ keepPreviousData: true,
},
);
if (isLoading && !initialPlan) {
return (
-
+
-
+
);
}
+ if (!plan && error) {
+ return ;
+ }
+
if (!plan) {
return null;
}