@navinc/base-react-components
Version:
Nav's Pattern Library
107 lines (97 loc) • 3.41 kB
JavaScript
import { useEffect } from 'react'
import styled, { useTheme } from 'styled-components'
import { loadScript, global, noop } from '@navinc/utils'
import Copy from './copy.js'
import { Input, Label, FieldWrapper, Field, Errors, Err } from './form-elements/shared.js'
import isRebrand from './is-rebrand.js'
export const getStripeDefaults = (theme) => ({
stripe: {
fonts: [
{
family: 'Averta',
src: `local("Averta"),
local("averta"),
url('https://dxkdvuv3hanyu.cloudfront.net/webfonts/Averta-Regular.eot?#iefix') format('embedded-opentype'),
url('https://dxkdvuv3hanyu.cloudfront.net/webfonts/Averta-Regular.woff2') format('woff2'),
url('https://dxkdvuv3hanyu.cloudfront.net/webfonts/Averta-Regular.woff') format('woff'),
url('https://dxkdvuv3hanyu.cloudfront.net/webfonts/Averta-Regular.ttf') format('truetype')`,
weight: 400,
style: 'normal',
},
],
},
elements: {
classes: {
base: 'c-input__input-field c-input__input-field--stripe',
empty: 'is-empty',
focus: 'is-focused',
complete: 'is-focused',
invalid: 'is-focused',
},
hideIcon: false,
style: {
base: {
color: isRebrand(theme) ? theme.navNeutralDark : theme.neutral400,
fontFamily: 'Averta',
fontSize: '16px',
lineHeight: '1.8',
},
invalid: {
color: isRebrand(theme) ? theme.navStatusNegative : theme.error,
},
},
},
})
export const CCInputWrapper = styled(Input).attrs(() => ({ as: 'div' }))``
const CC_INPUT_CLASS_NAME = 'js-stripe_card'
export const CCInput = ({
className = '',
label,
hasSpaceForErrors,
isInvalid,
value,
required,
type,
errors = [],
lede = '',
onChange = noop,
onBlur = noop,
onFocus = noop,
createPaymentMethodRef = noop,
createTokenRef = noop,
...props
}) => {
const theme = useTheme()
useEffect(() => {
Promise.resolve(global.Stripe || loadScript('https://js.stripe.com/v3/').then(() => global.Stripe))
.then((stripe) => stripe(global?.process?.env?.CLIENT_BILLING_PUBLIC_KEY ?? ''))
.then((stripe) => {
const elements = stripe.elements(getStripeDefaults(theme).stripe)
const cc = elements.create('card', getStripeDefaults(theme).elements)
cc.mount(`.${CC_INPUT_CLASS_NAME}`)
cc.addEventListener('change', (changeEvent) => {
onChange(changeEvent)
})
createTokenRef((billingInfo) => stripe.createToken(cc, billingInfo))
createPaymentMethodRef((billingInfo) => stripe.createPaymentMethod('card', cc, billingInfo))
return stripe
})
.catch((err) => console.error('Stripe failed to initialize! ', err))
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
return (
<FieldWrapper className={className}>
{lede && <Copy bold>{lede}</Copy>}
<Field value={value} isVisited isInvalid={isInvalid} required={required} type={type}>
<CCInputWrapper data-heap-redact-text="true" className={`js-private ${CC_INPUT_CLASS_NAME}`} {...props} />
<Label required={required} value={value}>
{label}
</Label>
</Field>
<Errors hasSpaceForErrors={hasSpaceForErrors}>
{!!errors.length && errors.map((err, i) => <Err key={`err-${i}`}>{err}</Err>)}
</Errors>
</FieldWrapper>
)
}
export default CCInput