monei-widget2
Version:
An easy way to accept payments from your customers. Embed this widget on your website, blog or online store.
253 lines (229 loc) • 7.16 kB
JavaScript
import {Component} from 'preact';
import $ from 'cash-dom';
import classNames from './PaymentForm.scss';
import render from 'preact-render-to-string';
import {formatAmount, isValidEmail, updateQuery} from 'lib/utils';
import cx from 'classnames';
import checkout from 'lib/checkout';
import {Spinner} from 'spin.js';
class PaymentForm extends Component {
static defaultProps = {
brands: 'VISA MASTER',
redirectUrl: location.href,
showLabels: false,
showPlaceholders: true,
showCardHolder: false,
showEmail: true,
labels: {
email: 'Email'
},
errorMessages: {
email: 'Invalid email'
},
style: 'plain',
spinner: {
lines: 8,
width: 3,
radius: 8,
length: 5,
position: 'fixed'
}
};
constructor(props) {
super(props);
this.apiBaseUrl = `https://${props.test ? 'test.' : ''}oppwa.com`;
if (props.submitText) {
props.labels.submit = props.submitText.replace(
'{amount}',
formatAmount(props.amount, props.currency)
);
}
window.wpwlOptions = {
...props,
brandDetection: true,
onLoadThreeDIframe: this.onLoadThreeDIframe,
onReady: this.onReady,
onError: this.onError,
onBeforeSubmitCard: this.onBeforeSubmitCard
};
}
injectPaymentScript(checkoutId, cb) {
const script = document.createElement('script');
script.src = `${this.apiBaseUrl}/v1/paymentWidgets.js?checkoutId=${checkoutId}`;
script.async = true;
script.onload = () => {
cb && cb();
this.props.onLoad && this.props.onLoad();
};
document.body.appendChild(script);
this.$script = $(script);
}
removePaymentScript() {
if (this.$script) {
this.$script.remove();
this.$script = null;
// remove script added by paymentWidgets.js
window.wpwl && wpwl.unload();
$('script[src*="oppwa.com"]').remove();
}
}
onBeforeSubmitCard = e => {
e.preventDefault();
if (this.props.onBeforeSubmitCard) {
return this.props.onBeforeSubmitCard(e) && this.validateEmail(true);
}
return this.validateEmail(true);
};
onLoadThreeDIframe = () => {
this.props.onLoadThreeDIframe && this.props.onLoadThreeDIframe();
this.setState({is3DFrame: true});
};
onError = error => {
this.props.onError && this.props.onError(error);
this.setState({isError: true});
};
onReady = () => {
this.props.onReady && this.props.onReady();
this.setState({isReady: true});
this.adjustForm();
};
checkPaymentError = () => {
if (this.$formContainer.find('.wpwl-message.wpwl-has-error').length) {
this.onError();
}
};
appendEmail($form) {
const {showLabels, showPlaceholders, labels} = this.props;
this.$emailField = $(
render(
<div className="wpwl-group wpwl-group-email wpwl-clearfix">
{showLabels && <div className="wpwl-label wpwl-label-email">{labels.email}</div>}
<div className="wpwl-wrapper wpwl-wrapper-email">
<input
name="customer.email"
className="wpwl-control wpwl-control-email"
placeholder={showPlaceholders && labels.email}
type="text"
/>
</div>
</div>
)
);
const $emailInput = this.$emailField.find('input');
$emailInput.on('blur', () => this.validateEmail());
$form.prepend(this.$emailField);
}
validateEmail(errorOnEmpty = false) {
if (!this.$emailField) return true;
const $input = this.$emailField.find('input');
const value = $input.val();
if (!value && !errorOnEmpty) {
return true;
}
const isValid = isValidEmail(value);
const $hint = this.$emailField.find('.wpwl-hint-emailError');
$input.toggleClass('wpwl-has-error', !isValid);
if (isValid && $hint.length) {
$hint.remove();
} else if (!isValid && !$hint.length) {
$input.after(
render(
<div className="wpwl-hint wpwl-hint-emailError">{this.props.errorMessages.email}</div>
)
);
}
return isValid;
}
adjustForm() {
const {showCardHolder, showEmail, customer, customParameters, primaryColor} = this.props;
const $form = this.$formContainer.find('.wpwl-form-card');
// move brand icon to the card number field and hide by default
const $brand = $form
.find('.wpwl-brand-card')
.removeClass('wpwl-brand-VISA')
.addClass('wpwl-brand-GENERIC');
$brand.appendTo($form.find('.wpwl-wrapper-cardNumber'));
// show cardholder firs or hide it
const $cardHolder = $form.find('.wpwl-group-cardHolder');
if (showCardHolder) {
$cardHolder.prependTo($form);
} else {
$cardHolder.remove();
}
if (showEmail && !customer.email) {
this.appendEmail($form);
}
$form.find('.wpwl-button-pay').css({backgroundColor: primaryColor});
// add custom fields
Object.keys(customer).forEach(key => {
const value = customer[key];
if (value) $form.prepend(`<input type="hidden" name="customer.${key}" value="${value}">`);
});
Object.keys(customParameters).forEach(key => {
const value = customParameters[key];
if (value)
$form.prepend(
`<input type="hidden" name="customParameters[SHOPPER_${key}]" value="${value}">`
);
});
}
componentDidMount() {
if (this.props.checkoutId) {
this.injectPaymentScript(this.props.checkoutId);
} else {
const spinner = new Spinner(this.props.spinner).spin(document.body);
checkout(this.props).then(({id, error}) => {
if (error) {
return this.onError(error);
}
this.injectPaymentScript(id, () => {
spinner.stop();
});
});
}
setTimeout(() => {
this.checkPaymentError();
}, 1000);
}
componentWillUnmount() {
this.removePaymentScript();
}
render(
{brands, redirectUrl, token, className, test, popup},
{is3DFrame, isReady, isError},
context
) {
if (token) {
redirectUrl = updateQuery(redirectUrl, 'token', token);
}
return (
<div
className={cx(classNames.formContainer, className, {
[classNames.frame]: is3DFrame,
[classNames.ready]: isReady,
[classNames.error]: isError
})}
ref={el => (this.$formContainer = $(el))}>
{test && (
<div className={classNames.testModeWarning}>
<div>You will not be billed for this test charge.</div>
</div>
)}
<div>
<form action={redirectUrl} className="paymentWidgets" data-brands={brands} />
</div>
<div className={classNames.brand}>
<span>Powered by</span>{' '}
<a href="https://monei.net/" target="_blank" tabIndex={-1}>
<img
src="https://static.monei.net/monei-logo.svg"
alt="MONEI"
title="Best payment gateway rates. The perfect solution to manage your digital payments. Get in now!"
/>
</a>
</div>
</div>
);
}
}
export default PaymentForm;