diff --git a/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/BillingDetails.tsx b/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/BillingDetails.tsx
index 75c66312a5..459a17e6d8 100644
--- a/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/BillingDetails.tsx
+++ b/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/BillingDetails.tsx
@@ -30,7 +30,7 @@ function BillingDetails() {
diff --git a/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/PaymentCard.jsx b/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/PaymentCard.jsx
index 4def60fbd4..c5b2e9f14d 100644
--- a/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/PaymentCard.jsx
+++ b/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/PaymentCard.jsx
@@ -1,7 +1,7 @@
import PropTypes from 'prop-types'
import { useState } from 'react'
-import { subscriptionDetailType } from 'services/account'
+import { accountDetailsPropType } from 'services/account'
import { formatTimestampToCalendarDate } from 'shared/utils/billing'
import A from 'ui/A'
import Button from 'ui/Button'
@@ -10,8 +10,9 @@ import Icon from 'ui/Icon'
import BankInformation from './BankInformation'
import CardInformation from './CardInformation'
import PaymentMethodForm from './PaymentMethodForm'
-function PaymentCard({ subscriptionDetail, provider, owner }) {
+function PaymentCard({ accountDetails, provider, owner }) {
const [isFormOpen, setIsFormOpen] = useState(false)
+ const subscriptionDetail = accountDetails?.subscriptionDetail
const card = subscriptionDetail?.defaultPaymentMethod?.card
const usBankAccount = subscriptionDetail?.defaultPaymentMethod?.usBankAccount
@@ -41,7 +42,7 @@ function PaymentCard({ subscriptionDetail, provider, owner }) {
provider={provider}
owner={owner}
closeForm={() => setIsFormOpen(false)}
- subscriptionDetail={subscriptionDetail}
+ accountDetails={accountDetails}
/>
) : card ? (
@@ -72,7 +73,7 @@ function PaymentCard({ subscriptionDetail, provider, owner }) {
}
PaymentCard.propTypes = {
- subscriptionDetail: subscriptionDetailType,
+ accountDetails: accountDetailsPropType,
provider: PropTypes.string.isRequired,
owner: PropTypes.string.isRequired,
}
diff --git a/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/PaymentCard.test.jsx b/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/PaymentCard.test.jsx
index 6173a5af87..fd48e5e014 100644
--- a/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/PaymentCard.test.jsx
+++ b/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/PaymentCard.test.jsx
@@ -55,6 +55,10 @@ const subscriptionDetail = {
cancelAtPeriodEnd: false,
}
+const accountDetails = {
+ subscriptionDetail,
+}
+
const usBankSubscriptionDetail = {
defaultPaymentMethod: {
usBankAccount: {
@@ -100,12 +104,10 @@ describe('PaymentCard', () => {
return { user }
}
- describe(`when the user doesn't have any subscriptionDetail`, () => {
- // NOTE: This test is misleading because we hide this component from a higher level in
- // BillingDetails.tsx if there is no subscriptionDetail
+ describe(`when the user doesn't have any accountDetails`, () => {
it('renders the set payment method message', () => {
render(
-
+
)
expect(
@@ -120,9 +122,12 @@ describe('PaymentCard', () => {
it('renders an error message', () => {
render(
{
const { user } = setup()
render(
{
const { user } = setup()
render(
{
it('renders the card', () => {
render(
,
@@ -204,7 +215,7 @@ describe('PaymentCard', () => {
it('renders the next billing', () => {
render(
,
@@ -217,9 +228,15 @@ describe('PaymentCard', () => {
describe('when the user has a US bank account', () => {
it('renders the bank account details', () => {
+ const testAccountDetails = {
+ ...accountDetails,
+ subscriptionDetail: {
+ ...usBankSubscriptionDetail,
+ },
+ }
render(
,
@@ -235,9 +252,12 @@ describe('PaymentCard', () => {
it(`doesn't render the next billing`, () => {
render(
{
render(
,
@@ -280,7 +300,7 @@ describe('PaymentCard', () => {
})
render(
,
@@ -305,7 +325,7 @@ describe('PaymentCard', () => {
render(
,
@@ -327,7 +347,7 @@ describe('PaymentCard', () => {
})
render(
,
@@ -354,7 +374,7 @@ describe('PaymentCard', () => {
})
render(
,
@@ -376,7 +396,7 @@ describe('PaymentCard', () => {
})
render(
,
diff --git a/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/PaymentMethodForm.test.tsx b/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/PaymentMethodForm.test.tsx
index 20331e0f06..8d824d2282 100644
--- a/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/PaymentMethodForm.test.tsx
+++ b/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/PaymentMethodForm.test.tsx
@@ -6,9 +6,12 @@ import { MemoryRouter, Route } from 'react-router-dom'
import { vi } from 'vitest'
import { z } from 'zod'
-import { SubscriptionDetailSchema } from 'services/account/useAccountDetails'
+import {
+ AccountDetailsSchema,
+ SubscriptionDetailSchema,
+} from 'services/account/useAccountDetails'
-import PaymentMethodForm from './PaymentMethodForm'
+import PaymentMethodForm, { getEmail, getName } from './PaymentMethodForm'
const queryClient = new QueryClient()
@@ -66,6 +69,26 @@ const subscriptionDetail: z.infer = {
trialEnd: null,
}
+const accountDetails: z.infer = {
+ name: 'John Doe',
+ email: 'test@example.com',
+ subscriptionDetail: subscriptionDetail,
+ activatedStudentCount: 0,
+ activatedUserCount: 0,
+ checkoutSessionId: null,
+ delinquent: null,
+ inactiveUserCount: 0,
+ integrationId: null,
+ nbActivePrivateRepos: null,
+ planAutoActivate: null,
+ planProvider: null,
+ repoTotalCredits: 0,
+ rootOrganization: null,
+ scheduleDetail: null,
+ studentCount: 0,
+ usesInvoice: false,
+}
+
const mocks = {
useUpdatePaymentMethod: vi.fn(),
}
@@ -90,7 +113,7 @@ describe('PaymentMethodForm', () => {
render(
{}}
@@ -111,7 +134,7 @@ describe('PaymentMethodForm', () => {
})
render(
{}}
@@ -133,7 +156,7 @@ describe('PaymentMethodForm', () => {
})
render(
{}}
@@ -155,7 +178,7 @@ describe('PaymentMethodForm', () => {
})
render(
{
})
render(
{}}
@@ -203,7 +226,7 @@ describe('PaymentMethodForm', () => {
})
render(
{}}
@@ -215,4 +238,62 @@ describe('PaymentMethodForm', () => {
expect(screen.queryByRole('button', { name: /Cancel/i })).toBeDisabled()
})
})
+
+ describe('when the email is missing from billing details', () => {
+ it('infers one from the rest of the data', () => {
+ const accountDetailsWithoutBillingEmail = {
+ email: 'customer@email.com',
+ subscriptionDetail: {
+ defaultPaymentMethod: {
+ billingDetails: {
+ email: null,
+ },
+ },
+ },
+ } as z.infer
+
+ const email = getEmail(accountDetailsWithoutBillingEmail)
+ expect(email).toBe('customer@email.com')
+ })
+ })
+
+ describe('when the name is missing from billing details', () => {
+ it('uses latestInvoice customerName when billing name is missing', () => {
+ const accountDetailsWithoutBillingName = {
+ subscriptionDetail: {
+ defaultPaymentMethod: {
+ billingDetails: {
+ name: undefined,
+ },
+ },
+ latestInvoice: {
+ customerName: 'Customer Name',
+ },
+ },
+ } as unknown as z.infer
+
+ const name = getName(accountDetailsWithoutBillingName)
+ expect(name).toBe('Customer Name')
+ })
+
+ it('uses account name when billing name and invoice name are missing', () => {
+ const accountDetailsWithoutBillingName = {
+ name: 'Account Name',
+ subscriptionDetail: {
+ defaultPaymentMethod: {
+ billingDetails: {
+ name: undefined,
+ },
+ },
+ latestInvoice: {
+ customerName: undefined,
+ },
+ },
+ } as unknown as z.infer
+
+ const name = getName(accountDetailsWithoutBillingName)
+
+ expect(name).toBe('Account Name')
+ })
+ })
})
diff --git a/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/PaymentMethodForm.tsx b/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/PaymentMethodForm.tsx
index 85c3141d09..5804b9ad77 100644
--- a/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/PaymentMethodForm.tsx
+++ b/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/PaymentMethodForm.tsx
@@ -3,10 +3,7 @@ import { StripePaymentElement } from '@stripe/stripe-js'
import cs from 'classnames'
import { z } from 'zod'
-import {
- BillingDetailsSchema,
- SubscriptionDetailSchema,
-} from 'services/account'
+import { AccountDetailsSchema, BillingDetailsSchema } from 'services/account'
import { useUpdatePaymentMethod } from 'services/account/useUpdatePaymentMethod'
import { Provider } from 'shared/api/helpers'
import Button from 'ui/Button'
@@ -15,20 +12,24 @@ interface PaymentMethodFormProps {
closeForm: () => void
provider: Provider
owner: string
- subscriptionDetail: z.infer
+ accountDetails: z.infer
}
const PaymentMethodForm = ({
closeForm,
provider,
owner,
- subscriptionDetail,
+ accountDetails,
}: PaymentMethodFormProps) => {
const elements = useElements()
+ const subscriptionDetail = accountDetails?.subscriptionDetail
const billingDetails =
subscriptionDetail?.defaultPaymentMethod?.billingDetails
+ const email = getEmail(accountDetails)
+ const name = getName(accountDetails)
+
const {
mutate: updatePaymentMethod,
isLoading,
@@ -37,8 +38,8 @@ const PaymentMethodForm = ({
} = useUpdatePaymentMethod({
provider,
owner,
- name: billingDetails?.name || undefined,
- email: billingDetails?.email || undefined,
+ name,
+ email,
address: stripeAddress(billingDetails) || undefined,
})
@@ -124,4 +125,29 @@ export const stripeAddress = (
}
}
+export const getEmail = (
+ accountDetails: z.infer
+) => {
+ return (
+ accountDetails?.subscriptionDetail?.defaultPaymentMethod?.billingDetails
+ ?.email ||
+ accountDetails?.subscriptionDetail?.latestInvoice?.customerEmail ||
+ accountDetails?.subscriptionDetail?.customer?.email ||
+ accountDetails?.email ||
+ undefined
+ )
+}
+
+export const getName = (
+ accountDetails: z.infer
+) => {
+ return (
+ accountDetails?.subscriptionDetail?.defaultPaymentMethod?.billingDetails
+ ?.name ||
+ accountDetails?.subscriptionDetail?.latestInvoice?.customerName ||
+ accountDetails?.name ||
+ undefined
+ )
+}
+
export default PaymentMethodForm