UNPKG

@navinc/base-react-components

Version:
107 lines (97 loc) 3.41 kB
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