Skip to content

Commit

Permalink
add stripe payment element
Browse files Browse the repository at this point in the history
  • Loading branch information
suejung-sentry committed Jan 2, 2025
1 parent f428955 commit 0f6d1c3
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 117 deletions.
2 changes: 0 additions & 2 deletions .env.development
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,3 @@ REACT_APP_MARKETING_BASE_URL=https://about.codecov.io
# REACT_APP_STRIPE_KEY=
# REACT_APP_LAUNCHDARKLY=
# REACT_APP_BAREMETRICS_TOKEN=
REACT_APP_STRIPE_KEY=pk_test_514SJTOGlVGuVgOrkRgh7zxp3tQ7bX4CY6pnxxw6zRZZSoDVtUUjArPKC7oXeeIbJNICTqS7H88FRfwZnWMskPKxo00bAnu2i9I
REACT_APP_STRIPE_PUBLIC_KEY=pk_test_514SJTOGlVGuVgOrkRgh7zxp3tQ7bX4CY6pnxxw6zRZZSoDVtUUjArPKC7oXeeIbJNICTqS7H88FRfwZnWMskPKxo00bAnu2i9I
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
import React, { useState } from 'react'
import AddressForm from '../Address/AddressForm'
import {
Elements,
CardElement,
IbanElement,
useStripe,
PaymentElement,
useElements,
useStripe,
} from '@stripe/react-stripe-js'
import { loadStripe } from '@stripe/stripe-js'
import CreditCardForm from '../PaymentCard/CreditCardForm'
import { RadioTileGroup } from 'ui/RadioTileGroup'
import Icon from 'ui/Icon'
import React, { useState } from 'react'

import Button from 'ui/Button'

import AddressForm from '../Address/AddressForm'

// Load your Stripe public key
const stripePromise = loadStripe('your-publishable-key-here')
// 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<PaymentFormProps> = ({ clientSecret }) => {
const PaymentForm: React.FC<PaymentFormProps> = () => {
const stripe = useStripe()
const elements = useElements()
const [paymentMethod, setPaymentMethod] = useState<'card' | 'bank'>('card')
const [isSubmitting, setIsSubmitting] = useState(false)
const [errorMessage, setErrorMessage] = useState<string | null>(null)

Expand All @@ -37,21 +38,11 @@ const PaymentForm: React.FC<PaymentFormProps> = ({ clientSecret }) => {
return
}

const paymentElement = elements.getElement(
paymentMethod === 'card' ? CardElement : IbanElement
)

if (!paymentElement) {
setErrorMessage('Payment element is missing.')
setIsSubmitting(false)
return
}

// Confirm payment based on selected method
const { error } = await stripe.confirmPayment({
elements,
confirmParams: {
return_url: 'https://your-website.com/order-complete', // Redirect URL
// eslint-disable-next-line camelcase
return_url: 'https://codecov.io',
},
})

Expand All @@ -64,73 +55,50 @@ const PaymentForm: React.FC<PaymentFormProps> = ({ clientSecret }) => {
}

return (
<form onSubmit={handleSubmit} className="space-y-4">
<h2 className="text-lg font-bold">Choose Payment Method</h2>

<RadioTileGroup
value={paymentMethod}
onValueChange={(value: 'card' | 'bank') => setPaymentMethod(value)}
className="flex-row"
>
<RadioTileGroup.Item value="card" data-testid="card-radio">
<RadioTileGroup.Label>
<div className="flex items-center gap-2">
<Icon name="checkCircle"></Icon>
Card
</div>
</RadioTileGroup.Label>
</RadioTileGroup.Item>
<RadioTileGroup.Item value="bank" data-testid="bank-radio">
<RadioTileGroup.Label>
<div className="flex items-center gap-2">
<Icon name="checkCircle"></Icon>
Bank Account
</div>
</RadioTileGroup.Label>
</RadioTileGroup.Item>
</RadioTileGroup>

{/* Payment Element */}
{paymentMethod === 'card' && (
<div>
<h3 className="font-semibold">Card Details</h3>
<CreditCardForm
closeForm={function (): void {
throw new Error('Function not implemented.')
}}
provider={''}
owner={''}
/>
</div>
)}

{paymentMethod === 'bank' && (
<div>
<h3 className="font-semibold">Bank Account Details</h3>
<IbanElement
className="border p-2 rounded"
options={{
supportedCountries: ['SEPA'], // Specify the supported countries
}}
/>
</div>
)}
<div>
<PaymentElement
options={{
layout: 'tabs',
defaultValues: {
billingDetails: {
name: 'John Doe',
},
},
}}
/>
<div className="mb-8 mt-4 flex gap-1">
<Button
hook="submit-address-update"
type="submit"
variant="primary"
disabled={isSubmitting} // TODO - handle
onClick={handleSubmit}
to={undefined}
>
Save
</Button>
<Button
type="button"
hook="cancel-address-update"
variant="plain"
// disabled={isLoading}
onClick={() => console.log('TODO - implement me')} // TODO - implement me
to={undefined}
>
Cancel
</Button>
</div>

{errorMessage && <div className="text-red-500">{errorMessage}</div>}
</form>
</div>
)
}

// Wrapper Component to provide Stripe Elements
const PaymentPage: React.FC<{ clientSecret: string }> = ({ clientSecret }) => {
// if (!clientSecret) {
// return <div>Loading...</div>
// }

const options = {
clientSecret,
appearance: {
theme: 'stripe',
theme: 'stripe' as const,
},
}

Expand All @@ -145,20 +113,48 @@ interface EditablePaymentMethodProps {
clientSecret: string
}

const EditPaymentMethod: React.FC<EditablePaymentMethodProps> = ({
clientSecret,
}) => {
const EditPaymentMethod: React.FC<EditablePaymentMethodProps> = () => {
const clientSecret = MANUALLY_FETCHED_CLIENT_SECRET // TODO - fetch from API

const [activeTab, setActiveTab] = useState<'primary' | 'secondary'>('primary')

return (
<div className="flex flex-col gap-4 p-4">
<h3 className="font-semibold">Edit payment method</h3>
<PaymentPage clientSecret={clientSecret} />
<AddressForm
closeForm={function (): void {
throw new Error('TODO')
}}
provider={''}
owner={''}
/>
<div>
{/* Tabs for Primary and Secondary Payment Methods */}
<div className="ml-2 flex border-b border-ds-gray-tertiary">
{['primary', 'secondary'].map((tab) => (
<button
key={tab}
className={`py-2 ${tab === 'primary' ? 'mr-4' : ''} ${
activeTab === tab
? 'border-b-2 border-ds-gray-octonary font-semibold text-ds-gray-octonary'
: 'text-ds-gray-quinary hover:border-b-2 hover:border-ds-gray-quinary'
}`}
onClick={() => setActiveTab(tab as 'primary' | 'secondary')}
>
{tab === 'primary' ? 'Primary' : 'Secondary'} Payment Method
</button>
))}
</div>

{/* Payment Details for the selected tab */}
<div className="m-4">
{activeTab === 'primary' && (
<div>
<PaymentPage clientSecret={clientSecret} />
<AddressForm closeForm={() => {}} provider={''} owner={''} />
</div>
)}
{activeTab === 'secondary' && (
<div>
<PaymentPage clientSecret={clientSecret} />
<AddressForm closeForm={() => {}} provider={''} owner={''} />
</div>
)}
</div>
</div>
</div>
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { z } from 'zod'

import { SubscriptionDetailSchema } from 'services/account'
import Button from 'ui/Button'
import { ExpandableSection } from 'ui/ExpandableSection'

import AddressCard from '../Address/AddressCard'
import PaymentCard from '../PaymentCard'
import Button from 'ui/Button'

function PaymentMethod({
heading,
Expand All @@ -25,12 +25,8 @@ function PaymentMethod({
owner: string
}) {
const isAdmin = true // TODO

const isCreditCard = subscriptionDetail?.defaultPaymentMethod?.card // TODO

console.log(subscriptionDetail)

console.log(isEditMode)
return (
<div>
<ExpandableSection className="m-0 border-0" defaultOpen={isPrimary}>
Expand All @@ -47,14 +43,14 @@ function PaymentMethod({
) : null}
<div className="flex">
{/* Payment method summary */}
<PaymentCard
className="w-2/5 flex-1"
isEditMode={isEditMode}
setEditMode={setEditMode}
subscriptionDetail={subscriptionDetail}
provider={provider}
owner={owner}
/>
<PaymentCard
className="w-2/5 flex-1"
isEditMode={isEditMode}
setEditMode={setEditMode}
subscriptionDetail={subscriptionDetail}
provider={provider}
owner={owner}
/>
{/* Cardholder name */}
<div className="mx-4 w-1/5 border-x border-ds-gray-tertiary px-4">
<h4 className="mb-2 font-semibold">
Expand All @@ -63,20 +59,20 @@ function PaymentMethod({
<p>N/A</p>
</div>
{/* Address */}
<AddressCard
className="flex-1"
isEditMode={isEditMode}
setEditMode={setEditMode}
subscriptionDetail={subscriptionDetail}
provider={provider}
owner={owner}
/>
<AddressCard
className="flex-1"
isEditMode={isEditMode}
setEditMode={setEditMode}
subscriptionDetail={subscriptionDetail}
provider={provider}
owner={owner}
/>
</div>
{!isPrimary ? (
<Button
hook="button"
disabled={!isAdmin}
onClick={() => console.log('TODO - implement me')}
onClick={() => setEditMode(true)}
className="mt-4"
>
Set as primary
Expand Down

0 comments on commit 0f6d1c3

Please sign in to comment.