@navinc/base-react-components
Version:
Nav's Pattern Library
176 lines (159 loc) • 7.14 kB
JavaScript
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
/// <reference types="@types/stripe-v3" />
import { useEffect } from 'react';
import { styled, useTheme } from 'styled-components';
import { loadScript, global, noop, classNames } from '@navinc/utils';
import { Copy } from './copy.js';
import { Input, Label, FieldWrapper, Field, Errors, Err } from './form-elements/shared.js';
import { redactProps } from './redact/redact.js';
const anyGlobal = global;
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: theme.navNeutralDark,
fontFamily: 'Averta',
fontSize: '16px',
lineHeight: '1.8',
},
invalid: {
color: theme.navStatusNegative,
},
},
},
});
export const CCInputWrapper = styled(Input).attrs(() => ({ as: 'div' })).withConfig({ displayName: "brc-sc-CCInputWrapper", componentId: "brc-sc-1bt72c6" }) ``;
const CC_INPUT_CLASS_NAME = 'js-stripe_card';
/**
Use the `<CCInput />` component when credit card information is needed. Nav uses
Stripe as our merchant processor. Nav does not store credit card information in
our system. For this reason, the CCInput component works differently than most
other form components. CCInput is a fully uncontrolled component. No credit card
information is stored with Nav so a value is not given to the CCInput component.
#### Usage:
```
<CCInput
onChange={this.handelStripeChangeAction}
createTokenRef={(token) => this.token = token}
label='Credit Card Info'
/>
```
#### Props
#### onChange
Stripe passes certain information back to the consumer via a callback that is
accessible via the `onChange` prop. At certain points, when the value in the
component changes, a change event is fired. This is useful for setting
error classes. The change event object looks like this.
```
{
brand: String
complete: Boolean
elementType: String
empty: Boolean
error: null | {
code: String
message: String
type: String
}
value : { [fieldName]: String }
}
```
Not all fields will trigger changes as values are updated (credit card numbers
only fire change events on blur) and not all fields will be represented in the
value property (PII fields never return values).
#### createTokenRef
Similar to React's `createRef`, this prop is a callback to the component.
Unlike `createRef`, this callback passes a reference to a function that the
consumer is expected to call with the customer billing address information.
This function returns a promise that resolves with the Stripe token needed to
complete the billing process.
```
<CCInput createTokenRef={(token) => this.token = token} />
```
```
class BillingForm extends Component {
submitHandler = () => {
this.createToken(this.state.billing)
.then((token) => {
this.props.submitBillingForm({
...this.state.billing,
stripeToken: token
})
})
}
render () {
...
<CCInput
createTokenRef={(createToken) => { this.createStripeToken = createToken }
/>
...
}
}
```
#### label
The displayed field label.
#### errors
An array of error messages that will be displayed below the field.
*
* @deprecated This component is deprecated and will be removed in a future release. Avoid using it in new code.
*/
export const CCInput = (_a) => {
var { className = '', label, hasSpaceForErrors, required, errors = [], lede = '', onChange = noop, createPaymentMethodRef = noop, createTokenRef = noop } = _a, props = __rest(_a, ["className", "label", "hasSpaceForErrors", "required", "errors", "lede", "onChange", "createPaymentMethodRef", "createTokenRef"]);
const theme = useTheme();
useEffect(() => {
Promise.resolve(anyGlobal.Stripe || loadScript('https://js.stripe.com/v3/').then(() => anyGlobal.Stripe))
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- not sure if it is safe to remove the optional chaining
.then((stripe) => { var _a, _b, _c; return stripe((_c = (_b = (_a = anyGlobal === null || anyGlobal === void 0 ? void 0 : anyGlobal.process) === null || _a === void 0 ? void 0 : _a.env) === null || _b === void 0 ? void 0 : _b.CLIENT_BILLING_PUBLIC_KEY) !== null && _c !== void 0 ? _c : ''); })
.then((stripe) => {
const stripeDefaults = getStripeDefaults(theme);
// TODO: fix so `as any` isn't needed
const elements = stripe.elements(stripeDefaults.stripe);
const cc = elements.create('card', stripeDefaults.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 (_jsxs(FieldWrapper, { className: className, children: [lede && _jsx(Copy, { bold: true, children: lede }), _jsxs(Field, { isVisited: true, children: [_jsx(CCInputWrapper, Object.assign({}, redactProps, { className: classNames(redactProps.className, CC_INPUT_CLASS_NAME) }, props)), _jsx(Label, { required: required, children: label })] }), _jsx(Errors, { hasSpaceForErrors: hasSpaceForErrors, children: !!errors.length && errors.map((err, i) => _jsx(Err, { children: err }, `err-${i}`)) })] }));
};
//# sourceMappingURL=cc-input.js.map