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

New Donation Flow - Stripe elements components for getting the users payment details #1269

4 changes: 4 additions & 0 deletions .env.local.example
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ NEXTAUTH_SECRET=super-dev-secret
GOOGLE_ID=
GOOGLE_SECRET=

## Stripe ##
##############
STRIPE_PUBLIC_KEY=

## Paypal ##
##############
# using 'sb' as sandbox. no need to put real sandbox key if you don't plan to test requests with backend webhooks
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ Watch releases of this repository to be notified about future updates:

![Peek 2022-12-23 11-19](https://user-images.githubusercontent.com/893608/209308853-ddb8dfe8-1c42-4c18-be9c-4d55f8599d73.gif)


## Contributors ✨

<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
"@paypal/react-paypal-js": "^7.8.1",
"@react-pdf/renderer": "^3.0.1",
"@sentry/nextjs": "7.21.1",
"@stripe/react-stripe-js": "^1.16.1",
"@stripe/stripe-js": "^1.46.0",
"@tanstack/react-query": "^4.16.1",
"@tryghost/content-api": "^1.11.4",
"axios": "0.21.4",
Expand Down
66 changes: 66 additions & 0 deletions src/components/donations/stripe/PaymentDetailsStripeForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import getConfig from 'next/config'
import { Appearance, loadStripe } from '@stripe/stripe-js'
import { Elements, PaymentElement } from '@stripe/react-stripe-js'

import theme from 'common/theme'
import { Box, BoxProps } from '@mui/material'
const {
publicRuntimeConfig: { STRIPE_PUBLIC_KEY },
} = getConfig()

const appearance: Appearance = {
theme: 'stripe',
variables: {
colorPrimary: theme.palette.primary.main,
colorBackground: theme.palette.background.paper,
colorText: theme.palette.text.primary,
colorDanger: theme.palette.error.main,
fontFamily: "Montserrat, 'Helvetica Neue', Helvetica, Arial, sans-serif",
fontSizeSm: theme.typography.pxToRem(12),
fontSizeBase: theme.typography.pxToRem(16),
fontSizeLg: theme.typography.pxToRem(18),
fontSizeXl: theme.typography.pxToRem(20),
spacingUnit: theme.spacing(0),
borderRadius: theme.borders.round,
focusBoxShadow: 'none',
focusOutline: `2px solid ${theme.palette.primary.main}`,
},
rules: {
'.Input': {
boxShadow: 'none',
border: `1px solid ${theme.palette.grey[300]}`,
},
'.Input:focus': {
border: 'none',
boxShadow: 'none',
},
},
}

const stripePromise = loadStripe(STRIPE_PUBLIC_KEY)

export type PaymentDetailsStripeFormProps = {
clientSecret: string
containerProps?: BoxProps
}
export default function PaymentDetailsStripeForm({
clientSecret,
containerProps,
}: PaymentDetailsStripeFormProps) {
// const mutation = useCreatePaymentIntent({ amount: 100, currency: Currencies.BGN })
// useEffect(() => {
// mutation.mutate()
// }, [])
return (
<Elements
stripe={stripePromise}
options={{
clientSecret: clientSecret,
appearance,
}}>
<Box {...containerProps}>
<PaymentElement />
</Box>
</Elements>
)
}
1 change: 0 additions & 1 deletion src/components/modal/DetailsModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ function DetailsModal() {
))}
</List>
</Grid>
{/* */}
</DialogContent>
<DialogActions>
<Button autoFocus onClick={handleClose} color="primary">
Expand Down
18 changes: 17 additions & 1 deletion src/components/one-time-donation/OneTimeDonationPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { useViewCampaign } from 'common/hooks/campaigns'
import CenteredSpinner from 'components/common/CenteredSpinner'

import DonationStepper from './Steps'
// import PaymentDetailsStripeForm from 'components/donations/stripe/PaymentDetailsStripeForm'

const PREFIX = 'OneTimeDonationPage'

Expand Down Expand Up @@ -74,11 +75,19 @@ const scrollWindow = () => {
export default function OneTimeDonation({ slug }: { slug: string }) {
const { data, isLoading } = useViewCampaign(slug)
const matches = useMediaQuery('sm')
// const paymentIntentMutation = useCreatePaymentIntent({
// amount: 100,
// currency: 'BGN',
// })
// useEffect(() => {
// paymentIntentMutation.mutate()
// }, [])
if (isLoading || !data) return <CenteredSpinner size="2rem" />
const { campaign } = data

const bannerSource = backgroundCampaignPictureUrl(campaign)
const beneficiaryAvatarSource = beneficiaryCampaignPictureUrl(campaign)

return (
<StyledLayout maxWidth={false}>
<Grid
Expand All @@ -98,7 +107,6 @@ export default function OneTimeDonation({ slug }: { slug: string }) {
className={classes.banner}
/>
</Box>

<Grid
item
xs={12}
Expand All @@ -123,6 +131,14 @@ export default function OneTimeDonation({ slug }: { slug: string }) {
{campaign.title}
</Typography>
</Link>
{/* {paymentIntentMutation.isLoading ? (
<CenteredSpinner size="2rem" />
) : (
<PaymentDetailsStripeForm
clientSecret={paymentIntentMutation.data?.data.client_secret as string}
containerProps={{ maxWidth: 400 }}
/>
)} */}
<DonationStepper onStepChange={scrollWindow} />
</Grid>
</Grid>
Expand Down
2 changes: 1 addition & 1 deletion src/pages/campaigns/donation/[slug].tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { QueryClient, dehydrate } from '@tanstack/react-query'
import { GetServerSideProps, GetServerSidePropsContext } from 'next'
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
import { QueryClient, dehydrate } from '@tanstack/react-query'

import OneTimeDonation from 'components/one-time-donation/OneTimeDonationPage'
import { endpoints } from 'service/apiEndpoints'
Expand Down
1 change: 1 addition & 0 deletions src/service/apiEndpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export const endpoints = {
singlePrices: <Endpoint>{ url: '/donation/prices/single', method: 'GET' },
recurringPrices: <Endpoint>{ url: '/donation/prices/recurring', method: 'GET' },
createCheckoutSession: <Endpoint>{ url: '/donation/create-checkout-session', method: 'POST' },
createPaymentIntent: <Endpoint>{ url: '/donation/create-payment-intent', method: 'POST' },
createDonation: <Endpoint>{ url: '/donation/create-payment', method: 'POST' },
createBankDonation: <Endpoint>{ url: '/donation/create-bank-payment', method: 'POST' },
getDonation: (id: string) => <Endpoint>{ url: `/donation/${id}`, method: 'GET' },
Expand Down
13 changes: 13 additions & 0 deletions src/service/donation.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Stripe from 'stripe'
import { AxiosResponse } from 'axios'
import { useSession } from 'next-auth/react'

Expand All @@ -14,6 +15,7 @@ import { apiClient } from 'service/apiClient'
import { endpoints } from 'service/apiEndpoints'
import { authConfig } from 'service/restRequests'
import { UploadBankTransactionsFiles } from 'components/bank-transactions-file/types'
import { useMutation } from '@tanstack/react-query'

export const createCheckoutSession = async (data: CheckoutSessionInput) => {
return await apiClient.post<CheckoutSessionInput, AxiosResponse<CheckoutSessionResponse>>(
Expand All @@ -22,6 +24,17 @@ export const createCheckoutSession = async (data: CheckoutSessionInput) => {
)
}

export function useCreatePaymentIntent(params: Stripe.PaymentIntentCreateParams) {
//Create payment intent useing the react-query mutation
const { data: session } = useSession()
return useMutation(async () => {
return await apiClient.post<
Stripe.PaymentIntentCreateParams,
AxiosResponse<Stripe.PaymentIntent>
>(endpoints.donation.createPaymentIntent.url, params, authConfig(session?.accessToken))
})
}

export function useCreateDonation() {
const { data: session } = useSession()
return async (data: DonationInput) => {
Expand Down
22 changes: 22 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2339,6 +2339,26 @@ __metadata:
languageName: node
linkType: hard

"@stripe/react-stripe-js@npm:^1.16.1":
version: 1.16.1
resolution: "@stripe/react-stripe-js@npm:1.16.1"
dependencies:
prop-types: ^15.7.2
peerDependencies:
"@stripe/stripe-js": ^1.44.1
react: ^16.8.0 || ^17.0.0 || ^18.0.0
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
checksum: edd829619c714eeafe3235b1de731d03165dfa7f88b2596c2533912121cfde418dc412c3778e0eef17af59929280ece08269516272fd49569d8545f4f267dd1d
languageName: node
linkType: hard

"@stripe/stripe-js@npm:^1.46.0":
version: 1.46.0
resolution: "@stripe/stripe-js@npm:1.46.0"
checksum: e9f1a6c1abc1e9eb5cfe7d604066230078958d3ada61089912829b57d090e768d6310149f054c8da0a8c49d7a313c44418705f91174909c2d2313c9ded781be1
languageName: node
linkType: hard

"@swc/helpers@npm:0.4.14, @swc/helpers@npm:^0.4.2":
version: 0.4.14
resolution: "@swc/helpers@npm:0.4.14"
Expand Down Expand Up @@ -8801,6 +8821,8 @@ __metadata:
"@playwright/test": ^1.24.2
"@react-pdf/renderer": ^3.0.1
"@sentry/nextjs": 7.21.1
"@stripe/react-stripe-js": ^1.16.1
"@stripe/stripe-js": ^1.46.0
"@tanstack/react-query": ^4.16.1
"@testing-library/jest-dom": ^5.16.5
"@testing-library/react": ^13.4.0
Expand Down