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; }