diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0e776ca0..d59777d8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,6 +14,9 @@ way to update this template, but currently, we follow a pattern:
## Upcoming version 2019-XX-XX
+- [cghange] Use Final Form on `StripePaymentForm` for consistency. Note that card form Stripe
+ Elements in `StripePaymentForm` is not a Final Form field so it's not available trough Final Form
+ but handled separately. [#1088](https://github.com/sharetribe/flex-template-web/pull/1088)
- [change] Move Stripe SDK call from `StripePaymentForm` to `stripe.duck.js` for consistency.
[#1086](https://github.com/sharetribe/flex-template-web/pull/1086)
diff --git a/src/containers/CheckoutPage/CheckoutPage.js b/src/containers/CheckoutPage/CheckoutPage.js
index a2670126..2c7f580f 100644
--- a/src/containers/CheckoutPage/CheckoutPage.js
+++ b/src/containers/CheckoutPage/CheckoutPage.js
@@ -516,6 +516,8 @@ CheckoutPageComponent.defaultProps = {
enquiredTransaction: null,
currentUser: null,
stripePaymentToken: null,
+ stripePaymentTokenInProgress: false,
+ stripePaymentTokenError: null,
};
CheckoutPageComponent.propTypes = {
@@ -539,8 +541,8 @@ CheckoutPageComponent.propTypes = {
}).isRequired,
sendOrderRequest: func.isRequired,
onCreateStripePaymentToken: func.isRequired,
- stripePaymentTokenInProgress: bool.isRequired,
- stripePaymentTokenError: bool.isRequired,
+ stripePaymentTokenInProgress: bool,
+ stripePaymentTokenError: propTypes.error,
stripePaymentToken: object,
// from connect
diff --git a/src/containers/CheckoutPage/CheckoutPage.test.js b/src/containers/CheckoutPage/CheckoutPage.test.js
index 82588f8d..41712660 100644
--- a/src/containers/CheckoutPage/CheckoutPage.test.js
+++ b/src/containers/CheckoutPage/CheckoutPage.test.js
@@ -26,7 +26,7 @@ describe('CheckoutPage', () => {
scrollingDisabled: false,
onCreateStripePaymentToken: noop,
stripePaymentTokenInProgress: false,
- stripePaymentTokenError: false,
+ stripePaymentTokenError: null,
};
const tree = renderShallow();
expect(tree).toMatchSnapshot();
diff --git a/src/containers/CheckoutPage/__snapshots__/CheckoutPage.test.js.snap b/src/containers/CheckoutPage/__snapshots__/CheckoutPage.test.js.snap
index 19f87dd7..56452338 100644
--- a/src/containers/CheckoutPage/__snapshots__/CheckoutPage.test.js.snap
+++ b/src/containers/CheckoutPage/__snapshots__/CheckoutPage.test.js.snap
@@ -95,7 +95,7 @@ exports[`CheckoutPage matches snapshot 1`] = `
paymentInfo="CheckoutPage.paymentInfo"
showInitialMessageInput={true}
stripePaymentToken={null}
- stripePaymentTokenError={false}
+ stripePaymentTokenError={null}
stripePaymentTokenInProgress={false}
/>
diff --git a/src/ducks/stripe.duck.js b/src/ducks/stripe.duck.js
index fb57b6db..1a7716a0 100644
--- a/src/ducks/stripe.duck.js
+++ b/src/ducks/stripe.duck.js
@@ -18,9 +18,9 @@ export const PERSON_CREATE_REQUEST = 'app/stripe/PERSON_CREATE_REQUEST';
export const PERSON_CREATE_SUCCESS = 'app/stripe/PERSON_CREATE_SUCCESS';
export const PERSON_CREATE_ERROR = 'app/stripe/PERSON_CREATE_ERROR';
-export const STRIPE_PAYMENT_TOKEN_CREATE_REQUEST = 'app/stripe/STRIPE_PAYMENT_TOKEN_CREATE_REQUEST';
-export const STRIPE_PAYMENT_TOKEN_CREATE_SUCCESS = 'app/stripe/STRIPE_PAYMENT_TOKEN_CREATE_SUCCESS';
-export const STRIPE_PAYMENT_TOKEN_CREATE_ERROR = 'app/stripe/STRIPE_PAYMENT_TOKEN_CREATE_ERROR';
+export const CREATE_PAYMENT_TOKEN_REQUEST = 'app/stripe/CREATE_PAYMENT_TOKEN_REQUEST';
+export const CREATE_PAYMENT_TOKEN_SUCCESS = 'app/stripe/CREATE_PAYMENT_TOKEN_SUCCESS';
+export const CREATE_PAYMENT_TOKEN_ERROR = 'app/stripe/CREATE_PAYMENT_TOKEN_ERROR';
// ================ Reducer ================ //
@@ -34,7 +34,7 @@ const initialState = {
stripeAccount: null,
stripeAccountFetched: false,
stripePaymentTokenInProgress: false,
- stripePaymentTokenError: false,
+ stripePaymentTokenError: null,
stripePaymentToken: null,
};
@@ -101,15 +101,15 @@ export default function reducer(state = initialState, action = {}) {
}),
};
- case STRIPE_PAYMENT_TOKEN_CREATE_REQUEST:
+ case CREATE_PAYMENT_TOKEN_REQUEST:
return {
...state,
stripePaymentTokenError: null,
stripePaymentTokenInProgress: true,
};
- case STRIPE_PAYMENT_TOKEN_CREATE_SUCCESS:
+ case CREATE_PAYMENT_TOKEN_SUCCESS:
return { ...state, stripePaymentTokenInProgress: false, stripePaymentToken: payload };
- case STRIPE_PAYMENT_TOKEN_CREATE_ERROR:
+ case CREATE_PAYMENT_TOKEN_ERROR:
console.error(payload);
return { ...state, stripePaymentTokenError: payload, stripePaymentTokenInProgress: false };
@@ -169,17 +169,17 @@ export const personCreateError = payload => ({
error: true,
});
-export const stripePaymentTokenCreateRequest = () => ({
- type: STRIPE_PAYMENT_TOKEN_CREATE_REQUEST,
+export const createPaymentTokenRequest = () => ({
+ type: CREATE_PAYMENT_TOKEN_REQUEST,
});
-export const stripePaymentTokenCreateSuccess = payload => ({
- type: STRIPE_PAYMENT_TOKEN_CREATE_SUCCESS,
+export const createPaymentTokenSuccess = payload => ({
+ type: CREATE_PAYMENT_TOKEN_SUCCESS,
payload,
});
-export const stripePaymentTokenCreateError = payload => ({
- type: STRIPE_PAYMENT_TOKEN_CREATE_ERROR,
+export const createPaymentTokenError = payload => ({
+ type: CREATE_PAYMENT_TOKEN_ERROR,
payload,
error: true,
});
@@ -499,21 +499,18 @@ export const createStripePaymentToken = params => dispatch => {
// so that's why Stripe needs to be passed here and we can't create a new instance.
const { stripe, card } = params;
- dispatch(stripePaymentTokenCreateRequest());
+ dispatch(createPaymentTokenRequest());
return stripe
.createToken(card)
.then(response => {
- dispatch(stripePaymentTokenCreateSuccess(response.token));
+ dispatch(createPaymentTokenSuccess(response.token));
return response;
})
.catch(err => {
const e = storableError(err);
- dispatch(stripeAccountCreateError(e));
- const stripeMessage =
- e.apiErrors && e.apiErrors.length > 0 && e.apiErrors[0].meta
- ? e.apiErrors[0].meta.stripeMessage
- : null;
+ dispatch(createPaymentTokenError(e));
+ const stripeMessage = e.message;
log.error(err, 'create-stripe-payment-token-failed', { stripeMessage });
throw e;
});
diff --git a/src/forms/StripePaymentForm/StripePaymentForm.example.js b/src/forms/StripePaymentForm/StripePaymentForm.example.js
index 845308a5..739a31e6 100644
--- a/src/forms/StripePaymentForm/StripePaymentForm.example.js
+++ b/src/forms/StripePaymentForm/StripePaymentForm.example.js
@@ -18,7 +18,7 @@ export const Empty = {
intl: fakeIntl,
onCreateStripePaymentToken: noop,
stripePaymentTokenInProgress: false,
- stripePaymentTokenError: false,
+ stripePaymentTokenError: null,
},
group: 'forms',
};
diff --git a/src/forms/StripePaymentForm/StripePaymentForm.js b/src/forms/StripePaymentForm/StripePaymentForm.js
index f1a58a49..46b9bfa4 100644
--- a/src/forms/StripePaymentForm/StripePaymentForm.js
+++ b/src/forms/StripePaymentForm/StripePaymentForm.js
@@ -1,9 +1,16 @@
+/**
+ * Note: This form is using card from Stripe Elements https://stripe.com/docs/stripe-js#elements
+ * Card is not a Final Form field so it's not available trough Final Form.
+ * It's also handled separately in handleSubmit function.
+ */
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage, injectIntl, intlShape } from 'react-intl';
+import { Form as FinalForm } from 'react-final-form';
import classNames from 'classnames';
-import { Form, PrimaryButton, ExpandingTextarea } from '../../components';
import config from '../../config';
+import { propTypes } from '../../util/types';
+import { Form, PrimaryButton, FieldTextInput } from '../../components';
import css from './StripePaymentForm.css';
@@ -74,7 +81,6 @@ const initialState = {
submitting: false,
cardValueValid: false,
token: null,
- message: '',
};
/**
@@ -92,6 +98,7 @@ class StripePaymentForm extends Component {
this.state = initialState;
this.handleCardValueChange = this.handleCardValueChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
+ this.paymentForm = this.paymentForm.bind(this);
}
componentDidMount() {
if (!window.Stripe) {
@@ -139,9 +146,9 @@ class StripePaymentForm extends Component {
};
});
}
- handleSubmit(event) {
- event.preventDefault();
+ handleSubmit(values) {
const { onSubmit, stripePaymentTokenInProgress, stripePaymentToken } = this.props;
+ const initialMessage = values.initialMessage ? values.initialMessage.trim() : null;
if (stripePaymentTokenInProgress || !this.state.cardValueValid) {
// Already submitting or card value incomplete/invalid
@@ -150,7 +157,7 @@ class StripePaymentForm extends Component {
if (stripePaymentToken) {
// Token already fetched for the current card value
- onSubmit({ token: stripePaymentToken, message: this.state.message.trim() });
+ onSubmit({ token: stripePaymentToken.id, message: initialMessage });
return;
}
@@ -160,25 +167,28 @@ class StripePaymentForm extends Component {
};
this.props.onCreateStripePaymentToken(params).then(() => {
- onSubmit({ token: this.props.stripePaymentToken.id, message: this.state.message.trim() });
+ onSubmit({ token: this.props.stripePaymentToken.id, message: initialMessage });
});
}
- render() {
+
+ paymentForm(formRenderProps) {
const {
className,
rootClassName,
inProgress,
formId,
paymentInfo,
- onChange,
authorDisplayName,
showInitialMessageInput,
intl,
stripePaymentTokenInProgress,
stripePaymentTokenError,
- } = this.props;
+ invalid,
+ handleSubmit,
+ } = formRenderProps;
+
const submitInProgress = stripePaymentTokenInProgress || inProgress;
- const submitDisabled = !this.state.cardValueValid || submitInProgress;
+ const submitDisabled = invalid || !this.state.cardValueValid || submitInProgress;
const classes = classNames(rootClassName || css.root, className);
const cardClasses = classNames(css.card, {
[css.cardSuccess]: this.state.cardValueValid,
@@ -190,22 +200,13 @@ class StripePaymentForm extends Component {
{ name: authorDisplayName }
);
- const handleMessageChange = e => {
- // A change in the message should call the onChange prop with
- // the current token and the new message.
- const message = e.target.value;
- this.setState(prevState => {
- const { token } = prevState;
- const newState = { token, message };
- onChange(newState);
- return newState;
- });
- };
+ const messageOptionalText = intl.formatMessage({
+ id: 'StripePaymentForm.messageOptionalText',
+ });
- const messageOptionalText = (
-
-
-
+ const initialMessageLabel = intl.formatMessage(
+ { id: 'StripePaymentForm.messageLabel' },
+ { messageOptionalText: messageOptionalText }
);
const initialMessage = showInitialMessageInput ? (
@@ -213,21 +214,20 @@ class StripePaymentForm extends Component {
-
-
) : null;
return config.stripe.publishableKey ? (
-