diff --git a/src/pages/PlanPage/PlanPage.jsx b/src/pages/PlanPage/PlanPage.tsx similarity index 68% rename from src/pages/PlanPage/PlanPage.jsx rename to src/pages/PlanPage/PlanPage.tsx index 97ce11ffae..e8af792058 100644 --- a/src/pages/PlanPage/PlanPage.jsx +++ b/src/pages/PlanPage/PlanPage.tsx @@ -8,7 +8,11 @@ import config from 'config' import { SentryRoute } from 'sentry' +import { useAccountDetails } from 'services/account' +import { Provider } from 'shared/api/helpers' import { Theme, useThemeContext } from 'shared/ThemeContext' +import A from 'ui/A' +import { Alert } from 'ui/Alert' import LoadingLogo from 'ui/LoadingLogo' import { PlanProvider } from './context' @@ -35,17 +39,29 @@ const Loader = () => ( ) +interface URLParams { + owner: string + provider: Provider +} + function PlanPage() { - const { owner, provider } = useParams() + const { owner, provider } = useParams() const { data: ownerData } = useSuspenseQueryV5( PlanPageDataQueryOpts({ owner, provider }) ) + const { data: accountDetails } = useAccountDetails({ + provider, + owner, + }) + const { theme } = useThemeContext() const isDarkMode = theme !== Theme.LIGHT if (config.IS_SELF_HOSTED || !ownerData?.isCurrentUserPartOfOrg) { return } + const hasUnverifiedPaymentMethods = + accountDetails?.unverifiedPaymentMethods?.length return (
@@ -61,6 +77,14 @@ function PlanPage() { > + {hasUnverifiedPaymentMethods ? ( + + ) : null} }> @@ -90,4 +114,27 @@ function PlanPage() { ) } +const UnverifiedPaymentMethodAlert = ({ url }: { url?: string }) => { + return ( + <> + + New Payment Method Awaiting Verification + + Your new payment method requires verification.{' '} + + Click here + {' '} + to complete the verification process. + + +
+ + ) +} + export default PlanPage diff --git a/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/PaymentCard.jsx b/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/PaymentCard.jsx index c5b2e9f14d..51bddbedfe 100644 --- a/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/PaymentCard.jsx +++ b/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/PaymentCard.jsx @@ -63,7 +63,7 @@ function PaymentCard({ accountDetails, provider, owner }) { variant="primary" onClick={() => setIsFormOpen(true)} > - Set card + Set payment method
diff --git a/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/PaymentMethodForm.tsx b/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/PaymentMethodForm.tsx index 5804b9ad77..c69af50d96 100644 --- a/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/PaymentMethodForm.tsx +++ b/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/PaymentMethodForm.tsx @@ -4,8 +4,14 @@ import cs from 'classnames' import { z } from 'zod' import { AccountDetailsSchema, BillingDetailsSchema } from 'services/account' -import { useUpdatePaymentMethod } from 'services/account/useUpdatePaymentMethod' +import { + MissingAddressError, + MissingEmailError, + MissingNameError, + useUpdatePaymentMethod, +} from 'services/account/useUpdatePaymentMethod' import { Provider } from 'shared/api/helpers' +import A from 'ui/A' import Button from 'ui/Button' interface PaymentMethodFormProps { @@ -81,7 +87,7 @@ const PaymentMethodForm = ({ }} />

- {showError && error?.message} + {showError ? getErrorMessage(error) : null}

+ +
+ } + /> +) + +export default UpgradeFormModal diff --git a/src/services/account/useAccountDetails.ts b/src/services/account/useAccountDetails.ts index ec46cf8709..44e903a9a8 100644 --- a/src/services/account/useAccountDetails.ts +++ b/src/services/account/useAccountDetails.ts @@ -150,6 +150,14 @@ export const AccountDetailsSchema = z.object({ studentCount: z.number(), subscriptionDetail: SubscriptionDetailSchema, usesInvoice: z.boolean(), + unverifiedPaymentMethods: z + .array( + z.object({ + paymentMethodId: z.string(), + hostedVerificationLink: z.string(), + }) + ) + .nullable(), }) export interface UseAccountDetailsArgs { diff --git a/src/services/account/useUpdatePaymentMethod.ts b/src/services/account/useUpdatePaymentMethod.ts index 40c88afced..77e739c157 100644 --- a/src/services/account/useUpdatePaymentMethod.ts +++ b/src/services/account/useUpdatePaymentMethod.ts @@ -94,3 +94,8 @@ export function useUpdatePaymentMethod({ }, }) } + +// Errors from Stripe api confirmSetup() - unfortunately seems to just be by text, no error codes +export const MissingNameError = `You specified "never" for fields.billing_details.name when creating the payment Element, but did not pass confirmParams.payment_method_data.billing_details.name when calling stripe.confirmSetup(). If you opt out of collecting data via the payment Element using the fields option, the data must be passed in when calling stripe.confirmSetup().` +export const MissingEmailError = `You specified "never" for fields.billing_details.email when creating the payment Element, but did not pass confirmParams.payment_method_data.billing_details.email when calling stripe.confirmSetup(). If you opt out of collecting data via the payment Element using the fields option, the data must be passed in when calling stripe.confirmSetup().` +export const MissingAddressError = `You specified "never" for fields.billing_details.address when creating the payment Element, but did not pass confirmParams.payment_method_data.billing_details.address when calling stripe.confirmSetup(). If you opt out of collecting data via the payment Element using the fields option, the data must be passed in when calling stripe.confirmSetup().`