import React, { Component } from 'react'; import { inject, observer } from 'mobx-react'; import { Text, Flex, Box } from '@rebass/emotion'; import hexToRgba from 'hex-rgba'; import { navigate } from 'gatsby'; import { CardElement } from 'react-stripe-elements'; import { ProductOrderService } from 'lib'; import typography from 'utils/typography'; import { space, colors } from 'utils/theme'; import Button from 'components/button'; import PaymentLogos from 'components/payment-logos'; import { InputField, FormHeader } from 'components/checkout-layout/checkout-layout.styles'; import { PaymentFormProps, PaymentFormState } from './payment-form.types'; import { fields } from '../../payment.constants'; import * as Styles from './payment-form.styles'; class PaymentForm extends Component { state = { nameOnCard: '', card: null, validation: null, hasAttemptedSubmit: false, isSubmmitting: false, paymentSubmissionError: null }; onSubmit = async (event: React.MouseEvent): any => { event.preventDefault(); if (!this.state.hasAttemptedSubmit) { this.setState({ hasAttemptedSubmit: true }); } if (this.isValid()) { this.enableSubmittingState(); const makePayment = await ProductOrderService.handleCardPayment( this.props.stripe.handleCardPayment, this.props.checkoutStore!.paymentIntent.payment_intent_stripe_secret, this.state.card, this.props.checkoutStore!.buildStripePaymentData(this.state.nameOnCard) ); if (makePayment.status === 'succeeded') { const { data, errors } = await ProductOrderService.finaliseOrderPayment( this.props.checkoutStore!.paymentIntent.order.id, makePayment.id, makePayment.client_secret ); this.disableSubmittingState(); if (data.finalizeOrderPayment.response && data.finalizeOrderPayment.response === 'Updated.') { navigate('/payment-success'); } else if (errors) { // TODO Sentry Logging for order payment succeeded, but order not updated in floom } } else { this.disableSubmittingState(); this.setState({ paymentSubmissionError: 'There has been an error making payment' }); } } } disableSubmittingState = (): void => { this.setState({ isSubmmitting: false }); } enableSubmittingState = (): void => { this.setState({ isSubmmitting: true }); } isValid = (): boolean => { // @ts-ignore return this.state.validation && this.state.validation!.complete && this.state.nameOnCard.length; } storeCardInstance = (el: stripe.elements.Element): void => { if (el) { el.focus(); this.setState({ card: el }); } } subscribeToChanges = (el: stripe.elements.Element): void => { el.on('change', (event): void => { this.setState({ validation: event }); }); } onNameOnCardChange = (value: string): void => { this.setState({ nameOnCard: value }); } cardElementStyles = (): stripe.elements.ElementsOptions['style'] => { return { base: { 'fontSize': '14px', 'lineHeight': '20px', 'fontFamily': typography.options.bodyFontFamily!.join(), 'color': colors.black, '::placeholder': { color: hexToRgba(colors.black, 50), } }, invalid: { iconColor: colors.red, color: colors.red, } } } hasCardValidationError = (): boolean => !!this.state.validation && !!this.state.validation!.error shouldDisplayError = (): boolean => { if (!this.state.hasAttemptedSubmit) return false; return this.hasCardValidationError() || !this.state.nameOnCard.length; } render(): JSX.Element { return ( Accepted payment: { this.storeCardInstance(el) this.subscribeToChanges(el) }} style={this.cardElementStyles()} />
{ this.shouldDisplayError() && { this.hasCardValidationError() ? this.state.validation!.error.message : 'You need to enter the name on your card' } }
); } } export default inject('checkoutStore')(observer(PaymentForm));