Commit 45691907 authored by Stephanie Kirtiadi's avatar Stephanie Kirtiadi
Browse files

Make the credit card error not confusing.

Credit card errors now appear at the same time as
the other errors, which is during form submission.

Issue #47847
parent 1ee7488e
Loading
Loading
Loading
Loading
+16 −2
Original line number Diff line number Diff line
@@ -27,6 +27,11 @@ export function _GivingForm(props) {
  const [mailingListOptIn, setMailingListOptIn] = useState(false);
  const [loading, setLoading] = useState(false);
  const [errors, setErrors] = useState([]);
  const [stripeErrors, setStripeErrors] = useState({
    'cardNumber': new NamedError('cardNumber', "Your card number is incomplete."),
    'cardExpiry': new NamedError('cardExpiry', "Your card's expiration date is incomplete."),
    'cardCvc': new NamedError('cardCvc', "Your card's security code is incomplete."),
  });
  const [fitsAndSizes, setFitsAndSizes] = useState({
    'shirt1Fit': null,
    'shirt2Fit': null,
@@ -227,6 +232,9 @@ export function _GivingForm(props) {
        newErrors.push(new NamedError(fieldName, fieldName + ' must be filled out'));
      }
    }
    for (const stripeField in stripeErrors) {
      newErrors.push(stripeErrors[stripeField]);
    }
    return newErrors;
  }

@@ -380,9 +388,15 @@ export function _GivingForm(props) {
  }

  const onStripeFieldChange = (event) => {
    const field = event.elementType;
    const newState = {...stripeErrors};
    if (event.error != undefined) {
      const newError = new NamedError('stripeError', event.error.message);
      setErrors([...errors, newError]);
      const newError = new NamedError(field, event.error.message);
      newState[field] = newError;
      setStripeErrors(newState);
    } else {
      delete newState[field];
      setStripeErrors(newState);
    }
  }

+4 −2
Original line number Diff line number Diff line
@@ -55,7 +55,7 @@ export function GivingInfoForm(props) {
  let creditCardFields = null;
  if (paymentMethod == 'credit-card') {
    creditCardFields = (
      <StripeCreditCardForm onStripeFieldChange={onStripeFieldChange} />
      <StripeCreditCardForm onStripeFieldChange={onStripeFieldChange} errors={errors} />
    );
  };

@@ -81,7 +81,9 @@ export function GivingInfoForm(props) {
        <RegionDropdown regions={regions}
          selectedCountry={formData['country']}
          onChange={regionChanged}
          required={requiredFields.includes('region')}/>
          required={requiredFields.includes('region')}
          errors={errors}
        />
        {getInputTextField('postalCode')}
      </div>
      <div className="field-row">
+5 −2
Original line number Diff line number Diff line
import React from 'react';
import {findErrorByName} from './named_error';

export function RegionDropdown(props) {
  const {regions, selectedCountry, required, onChange} = props;
  const {regions, selectedCountry, required, onChange, errors} = props;

  let classes=['field'];
  if (required) {
  if (findErrorByName(errors, 'region') != undefined) {
    classes.push('error');
  } else {
    classes.push('required');
  }

+20 −9
Original line number Diff line number Diff line
import React, {useState} from 'react';
import {NamedError} from './named_error';
import {NamedError, findErrorByName} from './named_error';
import {CardNumberElement, CardExpiryElement, CardCVCElement} from 'react-stripe-elements';

const createOptions = (placeholder, fieldName) => {
const createOptions = (placeholder, fieldName, errors) => {
  let classes = ['field', fieldName];

  const fieldMapping = {
    'card-number': 'cardNumber',
    'exp-date': 'cardExpiry',
    'cvc': 'cardCvc'
  };

  if (findErrorByName(errors, fieldMapping[fieldName]) != undefined) {
    classes.push('error');
  }

  return {
    placeholder: placeholder,
    classes: {
      base: `field ${fieldName}`,
      invalid: 'field error',
      base: classes.join(" "),
    },
    style: {
      base: {
@@ -20,32 +31,32 @@ const createOptions = (placeholder, fieldName) => {
        fontFamily: '"Source Sans Pro", sans-serif'
      },
      invalid: {
        color: 'red',
        color: '#484848',
      },
    },
  };
};

export function StripeCreditCardForm(props) {
  const {onStripeFieldChange} = props;
  const {onStripeFieldChange, errors} = props;

  return (
    <React.Fragment>
      <div className="split-form stripe-elements">
        <div className="field-row">
          <CardNumberElement
            {...createOptions('Card Number', 'card-number')}
            {...createOptions('Card Number', 'card-number', errors)}
            onChange={onStripeFieldChange}
          />
        <img className='credit-cards' src='/static/images/donate/credit-cards.png'/>
        </div>
        <div className="field-row">
          <CardExpiryElement
            {...createOptions('MM/YY', 'exp-date')}
            {...createOptions('MM/YY', 'exp-date', errors)}
            onChange={onStripeFieldChange}
          />
          <CardCVCElement
            {...createOptions('CVC', 'cvc')}
            {...createOptions('CVC', 'cvc', errors)}
            onChange={onStripeFieldChange}
          />
        </div>