From f8c1578a9be375e83bd12785b127e59a4b46ad49 Mon Sep 17 00:00:00 2001 From: Suejung Shin Date: Mon, 6 Jan 2025 16:48:31 -0800 Subject: [PATCH] wip --- src/assets/billing/bank.svg | 10 ++ .../BillingDetails/BillingDetails.tsx | 48 +++--- .../EditPaymentMethod/EditPaymentMethod.tsx | 162 ------------------ .../BillingDetails/EditPaymentMethod/index.ts | 1 - .../Address/AddressForm.tsx | 0 .../EditPaymentMethods/EditPaymentMethods.tsx | 93 ++++++++++ .../PaymentMethod/PaymentMethodForm.tsx | 152 ++++++++++++++++ .../EditPaymentMethods/index.ts | 1 + .../PaymentCard/CreditCardForm.tsx | 100 ----------- .../BillingDetails/PaymentCard/index.ts | 1 - .../BillingDetails/PaymentMethod/index.ts | 1 - .../Address/AddressCard.test.tsx | 0 .../Address/AddressCard.tsx | 7 +- .../PaymentMethod/BankInformation.tsx | 26 +++ .../PaymentMethod}/CardInformation.tsx | 9 +- .../PaymentMethod/PaymentMethod.test.tsx} | 32 ++-- .../PaymentMethod/PaymentMethod.tsx} | 49 +++--- .../PaymentMethodContainer.tsx} | 32 ++-- .../PaymentMethodContainer/index.ts | 2 + src/services/account/useAccountDetails.ts | 10 ++ src/services/account/useStripeSetupIntent.ts | 55 ++++++ .../account/useUpdatePaymentMethod.ts | 62 +++++++ 22 files changed, 500 insertions(+), 353 deletions(-) create mode 100644 src/assets/billing/bank.svg delete mode 100644 src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/EditPaymentMethod/EditPaymentMethod.tsx delete mode 100644 src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/EditPaymentMethod/index.ts rename src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/{ => EditPaymentMethods}/Address/AddressForm.tsx (100%) create mode 100644 src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/EditPaymentMethods/EditPaymentMethods.tsx create mode 100644 src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/EditPaymentMethods/PaymentMethod/PaymentMethodForm.tsx create mode 100644 src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/EditPaymentMethods/index.ts delete mode 100644 src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/CreditCardForm.tsx delete mode 100644 src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/index.ts delete mode 100644 src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentMethod/index.ts rename src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/{ => PaymentMethodContainer}/Address/AddressCard.test.tsx (100%) rename src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/{ => PaymentMethodContainer}/Address/AddressCard.tsx (96%) create mode 100644 src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentMethodContainer/PaymentMethod/BankInformation.tsx rename src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/{PaymentCard => PaymentMethodContainer/PaymentMethod}/CardInformation.tsx (91%) rename src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/{PaymentCard/PaymentCard.test.tsx => PaymentMethodContainer/PaymentMethod/PaymentMethod.test.tsx} (94%) rename src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/{PaymentCard/PaymentCard.tsx => PaymentMethodContainer/PaymentMethod/PaymentMethod.tsx} (52%) rename src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/{PaymentMethod/PaymentMethod.tsx => PaymentMethodContainer/PaymentMethodContainer.tsx} (78%) create mode 100644 src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentMethodContainer/index.ts create mode 100644 src/services/account/useStripeSetupIntent.ts create mode 100644 src/services/account/useUpdatePaymentMethod.ts diff --git a/src/assets/billing/bank.svg b/src/assets/billing/bank.svg new file mode 100644 index 0000000000..42a10ad51e --- /dev/null +++ b/src/assets/billing/bank.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/BillingDetails.tsx b/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/BillingDetails.tsx index 6cb32dc984..42ab338246 100644 --- a/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/BillingDetails.tsx +++ b/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/BillingDetails.tsx @@ -1,13 +1,13 @@ +import { useState } from 'react' import { useParams } from 'react-router-dom' import { useAccountDetails } from 'services/account' +import A from 'ui/A' +import Button from 'ui/Button' +import EditPaymentMethods from './EditPaymentMethods' import EmailAddress from './EmailAddress' -import PaymentMethod from './PaymentMethod' -import Button from 'ui/Button' -import { useState } from 'react' -import A from 'ui/A' -import EditablePaymentMethod from './EditPaymentMethod' +import { PaymentMethodContainer } from './PaymentMethodContainer' interface URLParams { provider: string @@ -22,15 +22,12 @@ function BillingDetails() { }) const subscriptionDetail = accountDetails?.subscriptionDetail const [isEditMode, setEditMode] = useState(false) - - const isAdmin = true // TODO + const secondaryPaymentFeatureEnabled = false if (!subscriptionDetail) { return null } - console.log('iseditmode', isEditMode) - return (
{/* Billing Details Section */} @@ -50,7 +47,6 @@ function BillingDetails() { hook="button" onClick={() => setEditMode(true)} variant="default" - disabled={!isAdmin} className="flex-none" > Edit payment @@ -60,7 +56,6 @@ function BillingDetails() { hook="button" onClick={() => setEditMode(false)} variant="default" - disabled={!isAdmin} className="flex-none" > Back @@ -68,28 +63,35 @@ function BillingDetails() { )}
{isEditMode ? ( - + ) : ( <> - - + {secondaryPaymentFeatureEnabled && ( + + )} {subscriptionDetail?.taxIds?.length ? (

Tax ID

diff --git a/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/EditPaymentMethod/EditPaymentMethod.tsx b/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/EditPaymentMethod/EditPaymentMethod.tsx deleted file mode 100644 index c7142559c7..0000000000 --- a/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/EditPaymentMethod/EditPaymentMethod.tsx +++ /dev/null @@ -1,162 +0,0 @@ -import { - Elements, - PaymentElement, - useElements, - useStripe, -} from '@stripe/react-stripe-js' -import { loadStripe } from '@stripe/stripe-js' -import React, { useState } from 'react' - -import Button from 'ui/Button' - -import AddressForm from '../Address/AddressForm' - -// TODO - fetch from API -const STRIPE_PUBLISHABLE_KEY = process.env.STRIPE_PUBLISHABLE_KEY || '' -const MANUALLY_FETCHED_CLIENT_SECRET = process.env.STRIPE_CLIENT_SECRET || '' - -const stripePromise = loadStripe(STRIPE_PUBLISHABLE_KEY) - -interface PaymentFormProps { - clientSecret: string -} - -const PaymentForm: React.FC = () => { - const stripe = useStripe() - const elements = useElements() - const [isSubmitting, setIsSubmitting] = useState(false) - const [errorMessage, setErrorMessage] = useState(null) - - const handleSubmit = async (event: React.FormEvent) => { - event.preventDefault() - setIsSubmitting(true) - setErrorMessage(null) - - if (!stripe || !elements) { - setErrorMessage('Stripe has not loaded yet. Please try again.') - setIsSubmitting(false) - return - } - - const { error } = await stripe.confirmPayment({ - elements, - confirmParams: { - // eslint-disable-next-line camelcase - return_url: 'https://codecov.io', - }, - }) - - if (error) { - setErrorMessage(error.message || 'An unexpected error occurred.') - setIsSubmitting(false) - } else { - setIsSubmitting(false) - } - } - - return ( -
- -
- - -
- - {errorMessage &&
{errorMessage}
} -
- ) -} - -const PaymentPage: React.FC<{ clientSecret: string }> = ({ clientSecret }) => { - const options = { - clientSecret, - appearance: { - theme: 'stripe' as const, - }, - } - - return ( - - - - ) -} - -interface EditablePaymentMethodProps { - clientSecret: string -} - -const EditPaymentMethod: React.FC = () => { - const clientSecret = MANUALLY_FETCHED_CLIENT_SECRET // TODO - fetch from API - - const [activeTab, setActiveTab] = useState<'primary' | 'secondary'>('primary') - - return ( -
-

Edit payment method

-
- {/* Tabs for Primary and Secondary Payment Methods */} -
- {['primary', 'secondary'].map((tab) => ( - - ))} -
- - {/* Payment Details for the selected tab */} -
- {activeTab === 'primary' && ( -
- - {}} provider={''} owner={''} /> -
- )} - {activeTab === 'secondary' && ( -
- - {}} provider={''} owner={''} /> -
- )} -
-
-
- ) -} - -export default EditPaymentMethod diff --git a/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/EditPaymentMethod/index.ts b/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/EditPaymentMethod/index.ts deleted file mode 100644 index 4f454d7d4f..0000000000 --- a/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/EditPaymentMethod/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './EditPaymentMethod' diff --git a/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/Address/AddressForm.tsx b/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/EditPaymentMethods/Address/AddressForm.tsx similarity index 100% rename from src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/Address/AddressForm.tsx rename to src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/EditPaymentMethods/Address/AddressForm.tsx diff --git a/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/EditPaymentMethods/EditPaymentMethods.tsx b/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/EditPaymentMethods/EditPaymentMethods.tsx new file mode 100644 index 0000000000..7f82edad1d --- /dev/null +++ b/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/EditPaymentMethods/EditPaymentMethods.tsx @@ -0,0 +1,93 @@ +import React, { useState } from 'react' +import { z } from 'zod' + +import { SubscriptionDetailSchema } from 'services/account/useAccountDetails' + +import AddressForm from './Address/AddressForm' +import EditPaymentMethodForm from './PaymentMethod/PaymentMethodForm' + +interface EditPaymentMethodProps { + setEditMode: (isEditMode: boolean) => void + provider: string + owner: string + subscriptionDetail: z.infer +} + +const EditPaymentMethod = ({ + setEditMode, + provider, + owner, + subscriptionDetail, +}: EditPaymentMethodProps) => { + const [activeTab, setActiveTab] = useState<'primary' | 'secondary'>('primary') + const isSecondaryPaymentMethodFeatureEnabled = false + + return ( +
+

Edit payment method

+
+ {/* Tabs for Primary and Secondary Payment Methods */} +
+ {[ + 'primary', + ...(isSecondaryPaymentMethodFeatureEnabled ? ['secondary'] : []), + ].map((tab) => ( + + ))} +
+ + {/* Payment Details for the selected tab */} +
+ {activeTab === 'primary' && ( +
+ setEditMode(false)} + provider={provider} + owner={owner} + /> + setEditMode(false)} + provider={provider} + owner={owner} + /> +
+ )} + {activeTab === 'secondary' && + isSecondaryPaymentMethodFeatureEnabled && ( +
+ setEditMode(false)} + provider={provider} + owner={owner} + /> + setEditMode(false)} + provider={provider} + owner={owner} + /> +
+ )} +
+
+
+ ) +} + +export default EditPaymentMethod diff --git a/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/EditPaymentMethods/PaymentMethod/PaymentMethodForm.tsx b/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/EditPaymentMethods/PaymentMethod/PaymentMethodForm.tsx new file mode 100644 index 0000000000..5aef56df41 --- /dev/null +++ b/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/EditPaymentMethods/PaymentMethod/PaymentMethodForm.tsx @@ -0,0 +1,152 @@ +import { PaymentElement, useElements } from '@stripe/react-stripe-js' +import cs from 'classnames' +import { useState } from 'react' + +import { useStripeSetupIntent } from 'services/account/useStripeSetupIntent' +import { useUpdatePaymentMethod } from 'services/account/useUpdatePaymentMethod' +import { Theme, useThemeContext } from 'shared/ThemeContext' +import Button from 'ui/Button' + +interface PaymentMethodFormProps { + closeForm: () => void + provider: string + owner: string +} + +const EditPaymentMethodForm = ({ + closeForm, + provider, + owner, +}: PaymentMethodFormProps) => { + const [errorState, _] = useState('') + const { theme } = useThemeContext() + const isDarkMode = theme === Theme.DARK + + const { data: setupIntent } = useStripeSetupIntent({ owner, provider }) + const elements = useElements() + + elements?.update({ clientSecret: setupIntent?.clientSecret }) + + const { + mutate: updatePaymentMethod, + isLoading, + error, + reset, + } = useUpdatePaymentMethod({ + provider, + owner, + }) + + async function submit(e: React.FormEvent) { + e.preventDefault() + + if (!elements) { + return null + } + + const paymentElement = elements.getElement(PaymentElement) + + updatePaymentMethod(paymentElement, { + onSuccess: closeForm, + }) + } + + const showError = (error && !reset) || errorState + + // Note: unfortunately seems Stripe doesn't let us reference like `var(--)` so rgbs are hardcoded in below + elements?.update({ + appearance: { + variables: { + fontFamily: 'Poppins, ui-sans-serif, system-ui, sans-serif', + }, + rules: { + '.Label': { + fontWeight: '600', + color: isDarkMode ? 'rgb(210,212,215)' : 'rgb(14,27,41)', // Same values as --color-app-text-primary. + }, + '.Input': { + backgroundColor: isDarkMode ? 'rgb(22,24,29)' : 'rgb(255,255,255)', // Same values as --color-app-container. + borderColor: isDarkMode ? 'rgb(47,51,60)' : 'rgb(216,220,226)', // Same values as --color-ds-gray-tertiary. + color: isDarkMode ? 'rgb(210,212,215)' : 'rgb(14,27,41)', // Same values as --color-app-text-primary. + }, + '.Input:focus': { + borderColor: isDarkMode ? 'rgb(210,212,215)' : 'rgb(14,27,41)', // Same values as --color-app-text-primary. + }, + '.Tab': { + backgroundColor: isDarkMode ? 'rgb(22,24,29)' : 'rgb(255,255,255)', // Same values as --color-app-container. + borderColor: isDarkMode ? 'rgb(47,51,60)' : 'rgb(216,220,226)', // Same values as --color-ds-gray-tertiary. + color: isDarkMode ? 'rgb(210,212,215)' : 'rgb(14,27,41)', // Same values as --color-app-text-primary. + }, + '.Tab:hover': { + backgroundColor: isDarkMode ? 'rgb(22,24,29)' : 'rgb(255,255,255)', // Same values as --color-app-container. + borderColor: isDarkMode ? 'rgb(47,51,60)' : 'rgb(216,220,226)', // Same values as --color-ds-gray-tertiary. + color: isDarkMode ? 'rgb(210,212,215)' : 'rgb(14,27,41)', // Same values as --color-app-text-primary. + }, + '.Tab--selected': { + backgroundColor: isDarkMode ? 'rgb(22,24,29)' : 'rgb(255,255,255)', // Same values as --color-app-container. + borderColor: isDarkMode ? 'rgb(47,51,60)' : 'rgb(216,220,226)', // Same values as --color-ds-gray-tertiary. + color: isDarkMode ? 'rgb(210,212,215)' : 'rgb(14,27,41)', // Same values as --color-app-text-primary. + }, + '.PickerItem': { + backgroundColor: isDarkMode ? 'rgb(22,24,29)' : 'rgb(255,255,255)', // Same values as --color-app-container. + borderColor: isDarkMode ? 'rgb(47,51,60)' : 'rgb(216,220,226)', // Same values as --color-ds-gray-tertiary. + color: isDarkMode ? 'rgb(210,212,215)' : 'rgb(14,27,41)', // Same values as --color-app-text-primary. + }, + '.PickerItem:hover': { + backgroundColor: isDarkMode ? 'rgb(22,24,29)' : 'rgb(255,255,255)', // Same values as --color-app-container. + borderColor: isDarkMode ? 'rgb(210,212,215)' : 'rgb(14,27,41)', // Same values as --color-app-text-primary. color: isDarkMode ? 'rgb(210,212,215)' : 'rgb(14,27,41)', // Same values as --color-app-text-primary. + }, + '.PickerItem--selected': { + backgroundColor: isDarkMode ? 'rgb(22,24,29)' : 'rgb(255,255,255)', // Same values as --color-app-container. + borderColor: isDarkMode ? 'rgb(47,51,60)' : 'rgb(216,220,226)', // Same values as --color-ds-gray-tertiary. + color: isDarkMode ? 'rgb(210,212,215)' : 'rgb(14,27,41)', // Same values as --color-app-text-primary. + }, + }, + }, + }) + + return ( +
+
+
+ +

+ {showError && (error?.message || errorState)} +

+
+ + +
+
+
+
+ ) +} + +export default EditPaymentMethodForm diff --git a/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/EditPaymentMethods/index.ts b/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/EditPaymentMethods/index.ts new file mode 100644 index 0000000000..a53f3b83bd --- /dev/null +++ b/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/EditPaymentMethods/index.ts @@ -0,0 +1 @@ +export { default } from './EditPaymentMethods' diff --git a/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/CreditCardForm.tsx b/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/CreditCardForm.tsx deleted file mode 100644 index bfe18a3c7c..0000000000 --- a/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/CreditCardForm.tsx +++ /dev/null @@ -1,100 +0,0 @@ -import { CardElement, useElements } from '@stripe/react-stripe-js' -import cs from 'classnames' -import { useState } from 'react' - -import { useUpdateCard } from 'services/account' -import { Theme, useThemeContext } from 'shared/ThemeContext' -import Button from 'ui/Button' - -interface CreditCardFormProps { - closeForm: () => void - provider: string - owner: string -} - -function CreditCardForm({ closeForm, provider, owner }: CreditCardFormProps) { - const [errorState, setErrorState] = useState('') - const { theme } = useThemeContext() - const isDarkMode = theme === Theme.DARK - - const elements = useElements() - const { - mutate: updateCard, - isLoading, - error, - reset, - } = useUpdateCard({ - provider, - owner, - }) - - function submit(e: React.FormEvent) { - e.preventDefault() - - if (!elements) { - return null - } - - updateCard(elements.getElement(CardElement), { - onSuccess: closeForm, - }) - } - - const showError = (error && !reset) || errorState - - return ( -
-
-
- setErrorState(e.error?.message || '')} - options={{ - disableLink: true, - hidePostalCode: true, - classes: { - empty: - 'rounded border-ds-gray-tertiary border-2 bg-ds-container', - focus: - 'rounded !border-ds-blue-darker border-4 bg-ds-container', - base: 'px-4 py-3 bg-ds-container', - invalid: - 'rounded !border-ds-primary-red border-4 bg-ds-container', - }, - style: { - base: { - color: isDarkMode ? 'rgb(210,212,215)' : 'rgb(14,27,41)', // Same values as --color-app-text-primary. - }, - }, - }} - /> -

- {showError && (error?.message || errorState)} -

-
-
- - -
-
-
- ) -} - -export default CreditCardForm diff --git a/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/index.ts b/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/index.ts deleted file mode 100644 index 9102b8ff5f..0000000000 --- a/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './PaymentCard' diff --git a/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentMethod/index.ts b/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentMethod/index.ts deleted file mode 100644 index 34940e48e5..0000000000 --- a/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentMethod/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './PaymentMethod' diff --git a/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/Address/AddressCard.test.tsx b/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentMethodContainer/Address/AddressCard.test.tsx similarity index 100% rename from src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/Address/AddressCard.test.tsx rename to src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentMethodContainer/Address/AddressCard.test.tsx diff --git a/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/Address/AddressCard.tsx b/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentMethodContainer/Address/AddressCard.tsx similarity index 96% rename from src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/Address/AddressCard.tsx rename to src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentMethodContainer/Address/AddressCard.tsx index 0fe781ee79..cca09ab9f7 100644 --- a/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/Address/AddressCard.tsx +++ b/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentMethodContainer/Address/AddressCard.tsx @@ -1,16 +1,13 @@ -import { useState } from 'react' import { z } from 'zod' import { BillingDetailsSchema, SubscriptionDetailSchema, } from 'services/account' -import A from 'ui/A' +import { cn } from 'shared/utils/cn' import Button from 'ui/Button' -import Icon from 'ui/Icon' -import AddressForm from './AddressForm' -import { cn } from 'shared/utils/cn' +import AddressForm from '../../EditPaymentMethods/Address/AddressForm' interface AddressCardProps { isEditMode: boolean diff --git a/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentMethodContainer/PaymentMethod/BankInformation.tsx b/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentMethodContainer/PaymentMethod/BankInformation.tsx new file mode 100644 index 0000000000..f73afae9f8 --- /dev/null +++ b/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentMethodContainer/PaymentMethod/BankInformation.tsx @@ -0,0 +1,26 @@ +import { z } from 'zod' + +import bankLogo from 'assets/billing/bank.svg' +import { SubscriptionDetailSchema } from 'services/account' + +interface BankInformationProps { + subscriptionDetail: z.infer +} +function BankInformation({ subscriptionDetail }: BankInformationProps) { + return ( +
+
+ bank logo +
+ + {subscriptionDetail?.defaultPaymentMethod?.usBankAccount?.bankName} +  ••••  + {subscriptionDetail?.defaultPaymentMethod?.usBankAccount?.last4} + +
+
+
+ ) +} + +export default BankInformation diff --git a/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/CardInformation.tsx b/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentMethodContainer/PaymentMethod/CardInformation.tsx similarity index 91% rename from src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/CardInformation.tsx rename to src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentMethodContainer/PaymentMethod/CardInformation.tsx index b20ff6de5b..9193fdc345 100644 --- a/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/CardInformation.tsx +++ b/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentMethodContainer/PaymentMethod/CardInformation.tsx @@ -37,14 +37,9 @@ type CardBrand = keyof typeof cardBrands interface CardInformationProps { subscriptionDetail: z.infer - card: { - brand: string - last4: string - expMonth: number - expYear: number - } } -function CardInformation({ subscriptionDetail, card }: CardInformationProps) { +function CardInformation({ subscriptionDetail }: CardInformationProps) { + const card = subscriptionDetail?.defaultPaymentMethod?.card const typeCard = cardBrands[card?.brand as CardBrand] ?? cardBrands.fallback let nextBilling = null diff --git a/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/PaymentCard.test.tsx b/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentMethodContainer/PaymentMethod/PaymentMethod.test.tsx similarity index 94% rename from src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/PaymentCard.test.tsx rename to src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentMethodContainer/PaymentMethod/PaymentMethod.test.tsx index b8021a7cb6..b3f7fdd2d6 100644 --- a/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentCard/PaymentCard.test.tsx +++ b/src/pages/PlanPage/subRoutes/CurrentOrgPlan/BillingDetails/PaymentMethodContainer/PaymentMethod/PaymentMethod.test.tsx @@ -4,7 +4,7 @@ import userEvent from '@testing-library/user-event' import { ThemeContextProvider } from 'shared/ThemeContext' import { Plans } from 'shared/utils/billing' -import PaymentCard from './PaymentCard' +import PaymentMethod from './PaymentMethod' const mocks = vi.hoisted(() => ({ useUpdateCard: vi.fn(), @@ -66,7 +66,11 @@ describe('PaymentCard', () => { // BillingDetails.tsx if there is no subscriptionDetail it('renders the set card message', () => { render( - + ) expect( @@ -80,7 +84,7 @@ describe('PaymentCard', () => { describe(`when the user doesn't have any card`, () => { it('renders an error message', () => { render( - { it(`doesn't render the card anymore`, async () => { const { user } = setup() render( - { it('renders the form', async () => { const { user } = setup() render( - { describe('when the user have a card', () => { it('renders the card', () => { render( - { it('renders the next billing', () => { render( - { describe('when the subscription is set to expire', () => { it(`doesn't render the next billing`, () => { render( - { }) render( - { isLoading: false, }) render( - { isLoading: false, }) render( - { isLoading: false, }) render( - { error: { message: randomError }, }) render( - { isLoading: true, }) render( - +

Payment method

{isEditMode ? ( - setEditMode(false)} + setEditMode={setEditMode} + subscriptionDetail={subscriptionDetail} /> - ) : card ? ( - + ) : isPaymentMethodSet ? ( + isCard ? ( + + ) : isBank ? ( + + ) : null ) : (

- No credit card set. Please contact support if you think it’s an + No payment method set. Please contact support if you think it’s an error or set it yourself.