Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Cut over to Stripe PaymentElement #3665

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/assets/billing/bank.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 14 additions & 1 deletion src/pages/PlanPage/PlanPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,16 @@ import config from 'config'

import { SentryRoute } from 'sentry'

import { Theme, useThemeContext } from 'shared/ThemeContext'
import LoadingLogo from 'ui/LoadingLogo'

import { PlanProvider } from './context'
import PlanBreadcrumb from './PlanBreadcrumb'
import { PlanPageDataQueryOpts } from './queries/PlanPageDataQueryOpts'
import Tabs from './Tabs'

import { StripeAppearance } from '../../stripe'

const CancelPlanPage = lazy(() => import('./subRoutes/CancelPlanPage'))
const CurrentOrgPlan = lazy(() => import('./subRoutes/CurrentOrgPlan'))
const InvoicesPage = lazy(() => import('./subRoutes/InvoicesPage'))
Expand All @@ -37,6 +40,8 @@ function PlanPage() {
const { data: ownerData } = useSuspenseQueryV5(
PlanPageDataQueryOpts({ owner, provider })
)
const { theme } = useThemeContext()
const isDarkMode = theme !== Theme.LIGHT

if (config.IS_SELF_HOSTED || !ownerData?.isCurrentUserPartOfOrg) {
return <Redirect to={`/${provider}/${owner}`} />
Expand All @@ -45,7 +50,15 @@ function PlanPage() {
return (
<div className="flex flex-col gap-4">
<Tabs />
<Elements stripe={stripePromise}>
<Elements
stripe={stripePromise}
options={{
...StripeAppearance(isDarkMode),
// mode and currency are required for the PaymentElement
mode: 'setup',
currency: 'usd',
}}
>
<PlanProvider>
<PlanBreadcrumb />
<Suspense fallback={<Loader />}>
Expand Down
28 changes: 16 additions & 12 deletions src/pages/PlanPage/PlanPage.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import { MemoryRouter, Route } from 'react-router-dom'

import config from 'config'

import { ThemeContextProvider } from 'shared/ThemeContext'

import PlanPage from './PlanPage'

vi.mock('config')
Expand Down Expand Up @@ -44,18 +46,20 @@ const wrapper =
({ children }) => (
<QueryClientProviderV5 client={queryClientV5}>
<QueryClientProvider client={queryClient}>
<Suspense fallback={null}>
<MemoryRouter initialEntries={[initialEntries]}>
<Route path="/plan/:provider/:owner">{children}</Route>
<Route
path="*"
render={({ location }) => {
testLocation = location
return null
}}
/>
</MemoryRouter>
</Suspense>
<ThemeContextProvider>
<Suspense fallback={null}>
<MemoryRouter initialEntries={[initialEntries]}>
<Route path="/plan/:provider/:owner">{children}</Route>
<Route
path="*"
render={({ location }) => {
testLocation = location
return null
}}
/>
</MemoryRouter>
</Suspense>
</ThemeContextProvider>
</QueryClientProvider>
</QueryClientProviderV5>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ describe('AddressCard', () => {
{ wrapper }
)

expect(screen.getByText('Cardholder name')).toBeInTheDocument()
expect(screen.getByText('Full name')).toBeInTheDocument()
expect(screen.getByText('N/A')).toBeInTheDocument()
expect(screen.getByText('Billing address')).toBeInTheDocument()
expect(screen.queryByText(/null/)).not.toBeInTheDocument()
Expand All @@ -241,7 +241,7 @@ describe('AddressCard', () => {
{ wrapper }
)

expect(screen.getByText(/Cardholder name/)).toBeInTheDocument()
expect(screen.getByText(/Full name/)).toBeInTheDocument()
expect(screen.getByText(/Bob Smith/)).toBeInTheDocument()
})
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ function AddressCard({
{!isFormOpen && (
<>
<div className="flex justify-between">
<h4 className="font-semibold">Cardholder name</h4>
<h4 className="font-semibold">Full name</h4>
<A
variant="semibold"
onClick={() => setIsFormOpen(true)}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { z } from 'zod'

import bankLogo from 'assets/billing/bank.svg'
import { USBankAccountSchema } from 'services/account'

interface BankInformationProps {
usBankAccount: z.infer<typeof USBankAccountSchema>
}

function BankInformation({ usBankAccount }: BankInformationProps) {
return (
<div className="flex flex-col gap-2">
<div className="flex gap-1">
<img src={bankLogo} alt="bank logo" />
<div className="ml-1 flex flex-col self-center">
<b>
{usBankAccount?.bankName}
&nbsp;••••&nbsp;
{usBankAccount?.last4}
</b>
</div>
</div>
</div>
)
}

export default BankInformation
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import A from 'ui/A'
import Button from 'ui/Button'
import Icon from 'ui/Icon'

import BankInformation from './BankInformation'
import CardInformation from './CardInformation'
import CreditCardForm from './CreditCardForm'
import PaymentMethodForm from './PaymentMethodForm'
function PaymentCard({ subscriptionDetail, provider, owner }) {
const [isFormOpen, setIsFormOpen] = useState(false)
const card = subscriptionDetail?.defaultPaymentMethod?.card
const usBankAccount = subscriptionDetail?.defaultPaymentMethod?.usBankAccount

return (
<div className="flex flex-col gap-2 border-t p-4">
Expand All @@ -20,25 +22,28 @@ function PaymentCard({ subscriptionDetail, provider, owner }) {
<A
variant="semibold"
onClick={() => setIsFormOpen(true)}
hook="edit-card"
hook="edit-payment-method"
>
Edit <Icon name="chevronRight" size="sm" variant="solid" />
</A>
)}
</div>
{isFormOpen ? (
<CreditCardForm
<PaymentMethodForm
provider={provider}
owner={owner}
closeForm={() => setIsFormOpen(false)}
subscriptionDetail={subscriptionDetail}
/>
) : card ? (
<CardInformation card={card} subscriptionDetail={subscriptionDetail} />
) : usBankAccount ? (
<BankInformation usBankAccount={usBankAccount} />
) : (
<div className="flex flex-col gap-4 text-ds-gray-quinary">
<p className="mt-4">
No credit card set. Please contact support if you think it’s an
error or set it yourself.
No payment method set. Please contact support if you think it&apos;s
an error or set it yourself.
</p>
<div className="flex self-start">
<Button
Expand Down
Loading
Loading