three-d-secure.tsx 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. import { useEffect, useRef } from 'react'
  2. import { useTranslation } from 'react-i18next'
  3. import { Alert } from 'react-bootstrap'
  4. import { RecurlyError, TokenPayload } from 'recurly__recurly-js'
  5. type ThreeDSecureProps = {
  6. actionTokenId: string
  7. onToken: (token: TokenPayload) => void
  8. onError: (error: RecurlyError) => void
  9. }
  10. function ThreeDSecure({ actionTokenId, onToken, onError }: ThreeDSecureProps) {
  11. const { t } = useTranslation()
  12. const container = useRef<HTMLDivElement>(null)
  13. const recurlyContainer = useRef<HTMLDivElement | null>(null)
  14. useEffect(() => {
  15. // scroll the UI into view (timeout needed to make sure the element is
  16. // visible)
  17. const timeout = setTimeout(() => {
  18. container.current?.scrollIntoView()
  19. }, 0)
  20. return () => {
  21. clearTimeout(timeout)
  22. }
  23. }, [])
  24. useEffect(() => {
  25. if (!recurly || !recurlyContainer.current) return
  26. // instanciate and configure Recurly 3DSecure flow
  27. const risk = recurly.Risk()
  28. const threeDSecure = risk.ThreeDSecure({ actionTokenId })
  29. threeDSecure.on('token', onToken)
  30. threeDSecure.on('error', onError)
  31. threeDSecure.attach(recurlyContainer.current)
  32. return () => {
  33. recurlyContainer.current = null
  34. }
  35. }, [actionTokenId, onToken, onError])
  36. return (
  37. <div className="three-d-secure-container--react" ref={container}>
  38. <Alert bsStyle="info" className="small" aria-live="assertive">
  39. <strong>{t('card_must_be_authenticated_by_3dsecure')}</strong>
  40. </Alert>
  41. <div
  42. className="three-d-secure-recurly-container"
  43. ref={recurlyContainer}
  44. />
  45. </div>
  46. )
  47. }
  48. export default ThreeDSecure