|
| 1 | +import * as stripeJs from '@stripe/stripe-js'; |
| 2 | +import React from 'react'; |
| 3 | +import {parseStripeProp} from '../utils/parseStripeProp'; |
| 4 | +import {registerWithStripeJs} from '../utils/registerWithStripeJs'; |
| 5 | +import {StripeError} from '@stripe/stripe-js'; |
| 6 | +import {usePrevious} from '../utils/usePrevious'; |
| 7 | + |
| 8 | +interface FinancialAccountDisclosureProps { |
| 9 | + /** |
| 10 | + * A [Stripe object](https://stripe.com/docs/js/initializing) or a `Promise` resolving to a `Stripe` object. |
| 11 | + * The easiest way to initialize a `Stripe` object is with the the [Stripe.js wrapper module](https://github.com/stripe/stripe-js/blob/master/README.md#readme). |
| 12 | + * Once this prop has been set, it can not be changed. |
| 13 | + * |
| 14 | + * You can also pass in `null` or a `Promise` resolving to `null` if you are performing an initial server-side render or when generating a static site. |
| 15 | + */ |
| 16 | + |
| 17 | + stripe: PromiseLike<stripeJs.Stripe | null> | stripeJs.Stripe | null; |
| 18 | + |
| 19 | + /** |
| 20 | + * Callback function called when the disclosure content is loading. |
| 21 | + */ |
| 22 | + onLoad?: () => void; |
| 23 | + |
| 24 | + /** |
| 25 | + * Callback function called when an error occurs during disclosure creation. |
| 26 | + */ |
| 27 | + onError?: (error: StripeError) => void; |
| 28 | + |
| 29 | + /** |
| 30 | + * Optional Financial Account Disclosure configuration options. |
| 31 | + * |
| 32 | + * businessName: The name of your business as you would like it to appear in the disclosure. If not provided, the business name will be inferred from the Stripe account. |
| 33 | + * learnMoreLink: A supplemental link to for your users to learn more about Financial Accounts for platforms or any other relevant information included in the disclosure. |
| 34 | + */ |
| 35 | + options?: { |
| 36 | + businessName?: string; |
| 37 | + learnMoreLink?: string; |
| 38 | + }; |
| 39 | +} |
| 40 | + |
| 41 | +const FinancialAccountDisclosure = ({ |
| 42 | + stripe: rawStripeProp, |
| 43 | + onLoad, |
| 44 | + onError, |
| 45 | + options, |
| 46 | +}: FinancialAccountDisclosureProps) => { |
| 47 | + const businessName = options?.businessName; |
| 48 | + const learnMoreLink = options?.learnMoreLink; |
| 49 | + const containerRef = React.useRef<HTMLDivElement>(null); |
| 50 | + const parsed = React.useMemo(() => parseStripeProp(rawStripeProp), [ |
| 51 | + rawStripeProp, |
| 52 | + ]); |
| 53 | + const [stripeState, setStripeState] = React.useState<stripeJs.Stripe | null>( |
| 54 | + parsed.tag === 'sync' ? parsed.stripe : null |
| 55 | + ); |
| 56 | + |
| 57 | + React.useEffect(() => { |
| 58 | + let isMounted = true; |
| 59 | + |
| 60 | + if (parsed.tag === 'async') { |
| 61 | + parsed.stripePromise.then((stripePromise: stripeJs.Stripe | null) => { |
| 62 | + if (stripePromise && isMounted) { |
| 63 | + setStripeState(stripePromise); |
| 64 | + } |
| 65 | + }); |
| 66 | + } else if (parsed.tag === 'sync') { |
| 67 | + setStripeState(parsed.stripe); |
| 68 | + } |
| 69 | + |
| 70 | + return () => { |
| 71 | + isMounted = false; |
| 72 | + }; |
| 73 | + }, [parsed]); |
| 74 | + |
| 75 | + // Warn on changes to stripe prop |
| 76 | + const prevStripe = usePrevious(rawStripeProp); |
| 77 | + React.useEffect(() => { |
| 78 | + if (prevStripe !== null && prevStripe !== rawStripeProp) { |
| 79 | + console.warn( |
| 80 | + 'Unsupported prop change on FinancialAccountDisclosure: You cannot change the `stripe` prop after setting it.' |
| 81 | + ); |
| 82 | + } |
| 83 | + }, [prevStripe, rawStripeProp]); |
| 84 | + |
| 85 | + // Attach react-stripe-js version to stripe.js instance |
| 86 | + React.useEffect(() => { |
| 87 | + registerWithStripeJs(stripeState); |
| 88 | + }, [stripeState]); |
| 89 | + |
| 90 | + React.useEffect(() => { |
| 91 | + const createDisclosure = async () => { |
| 92 | + if (!stripeState || !containerRef.current) { |
| 93 | + return; |
| 94 | + } |
| 95 | + |
| 96 | + const { |
| 97 | + htmlElement: disclosureContent, |
| 98 | + error, |
| 99 | + } = await (stripeState as any).createFinancialAccountDisclosure({ |
| 100 | + businessName, |
| 101 | + learnMoreLink, |
| 102 | + }); |
| 103 | + |
| 104 | + if (error && onError) { |
| 105 | + onError(error); |
| 106 | + } else if (disclosureContent) { |
| 107 | + const container = containerRef.current; |
| 108 | + container.innerHTML = ''; |
| 109 | + container.appendChild(disclosureContent); |
| 110 | + if (onLoad) { |
| 111 | + onLoad(); |
| 112 | + } |
| 113 | + } |
| 114 | + }; |
| 115 | + |
| 116 | + createDisclosure(); |
| 117 | + }, [stripeState, businessName, learnMoreLink, onLoad, onError]); |
| 118 | + |
| 119 | + return React.createElement('div', {ref: containerRef}); |
| 120 | +}; |
| 121 | + |
| 122 | +export default FinancialAccountDisclosure; |
0 commit comments