mirror of
https://github.com/kingomarnajjar/flex-template-web.git
synced 2026-07-28 03:43:28 +10:00
Allow adding a message in the StripePaymentForm
This commit is contained in:
parent
59209c6edb
commit
27ea4a66f2
7 changed files with 93 additions and 17 deletions
|
|
@ -104,16 +104,21 @@ export const speculateTransactionError = e => ({
|
|||
|
||||
/* ================ Thunks ================ */
|
||||
|
||||
export const initiateOrder = params => (dispatch, getState, sdk) => {
|
||||
export const initiateOrder = (orderParams, initialMessage) => (dispatch, getState, sdk) => {
|
||||
dispatch(initiateOrderRequest());
|
||||
const bodyParams = {
|
||||
transition: 'transition/preauthorize',
|
||||
params,
|
||||
params: orderParams,
|
||||
};
|
||||
let orderResponse;
|
||||
return sdk.transactions
|
||||
.initiate(bodyParams)
|
||||
.then(response => {
|
||||
const orderId = response.data.data.id;
|
||||
orderResponse = response;
|
||||
console.log(`TODO: save initial message: "${initialMessage}"`);
|
||||
})
|
||||
.then(() => {
|
||||
const orderId = orderResponse.data.data.id;
|
||||
dispatch(initiateOrderSuccess(orderId));
|
||||
dispatch(fetchCurrentUserHasOrdersSuccess(true));
|
||||
return orderId;
|
||||
|
|
@ -121,9 +126,9 @@ export const initiateOrder = params => (dispatch, getState, sdk) => {
|
|||
.catch(e => {
|
||||
dispatch(initiateOrderError(storableError(e)));
|
||||
log.error(e, 'initiate-order-failed', {
|
||||
listingId: params.listingId.uuid,
|
||||
bookingStart: params.bookingStart,
|
||||
bookingEnd: params.bookingEnd,
|
||||
listingId: orderParams.listingId.uuid,
|
||||
bookingStart: orderParams.bookingStart,
|
||||
bookingEnd: orderParams.bookingEnd,
|
||||
});
|
||||
throw e;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -103,6 +103,7 @@ export class CheckoutPageComponent extends Component {
|
|||
this.setState({ submitting: true });
|
||||
|
||||
const cardToken = values.token;
|
||||
const initialMessage = values.message;
|
||||
const { history, sendOrderRequest, speculatedTransaction } = this.props;
|
||||
const requestParams = {
|
||||
listingId: this.state.pageData.listing.id,
|
||||
|
|
@ -111,7 +112,7 @@ export class CheckoutPageComponent extends Component {
|
|||
bookingEnd: speculatedTransaction.booking.attributes.end,
|
||||
};
|
||||
|
||||
sendOrderRequest(requestParams)
|
||||
sendOrderRequest(requestParams, initialMessage)
|
||||
.then(orderId => {
|
||||
this.setState({ submitting: false });
|
||||
const orderDetailsPath = pathByRouteName('OrderDetailsPage', routeConfiguration(), {
|
||||
|
|
@ -327,6 +328,7 @@ export class CheckoutPageComponent extends Component {
|
|||
inProgress={this.state.submitting}
|
||||
formId="CheckoutPagePaymentForm"
|
||||
paymentInfo={intl.formatMessage({ id: 'CheckoutPage.paymentInfo' })}
|
||||
authorDisplayName={currentAuthor.attributes.profile.displayName}
|
||||
/>
|
||||
) : null}
|
||||
</section>
|
||||
|
|
@ -431,7 +433,7 @@ const mapStateToProps = state => {
|
|||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
sendOrderRequest: params => dispatch(initiateOrder(params)),
|
||||
sendOrderRequest: (params, initialMessage) => dispatch(initiateOrder(params, initialMessage)),
|
||||
fetchSpeculatedTransaction: (listingId, bookingStart, bookingEnd) =>
|
||||
dispatch(speculateTransaction(listingId, bookingStart, bookingEnd)),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@ exports[`CheckoutPage matches snapshot 1`] = `
|
|||
</div>
|
||||
<section>
|
||||
<InjectIntl(StripePaymentForm)
|
||||
authorDisplayName="author display name"
|
||||
formId="CheckoutPagePaymentForm"
|
||||
inProgress={false}
|
||||
onSubmit={[Function]}
|
||||
|
|
|
|||
|
|
@ -64,6 +64,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
.message {
|
||||
border-bottom-color: var(--matterColorAnti);
|
||||
}
|
||||
|
||||
.submitContainer {
|
||||
margin-top: auto;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ export const Empty = {
|
|||
component: StripePaymentForm,
|
||||
props: {
|
||||
formId: 'StripePaymentFormExample',
|
||||
authorDisplayName: 'Janne K',
|
||||
onChange: values => {
|
||||
console.log('form onChange:', values);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import React, { Component } from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
import { FormattedMessage, injectIntl, intlShape } from 'react-intl';
|
||||
import classNames from 'classnames';
|
||||
import { Form, PrimaryButton } from '../../components';
|
||||
import { Form, PrimaryButton, ExpandingTextarea } from '../../components';
|
||||
import * as log from '../../util/log';
|
||||
import config from '../../config';
|
||||
|
||||
|
|
@ -70,6 +70,14 @@ const cardStyles = {
|
|||
},
|
||||
};
|
||||
|
||||
const initialState = {
|
||||
error: null,
|
||||
submitting: false,
|
||||
cardValueValid: false,
|
||||
token: null,
|
||||
message: '',
|
||||
};
|
||||
|
||||
/**
|
||||
* Payment form that asks for credit card info using Stripe Elements.
|
||||
*
|
||||
|
|
@ -82,7 +90,7 @@ const cardStyles = {
|
|||
class StripePaymentForm extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { error: null, submitting: false, cardValueValid: false };
|
||||
this.state = initialState;
|
||||
this.handleCardValueChange = this.handleCardValueChange.bind(this);
|
||||
this.handleSubmit = this.handleSubmit.bind(this);
|
||||
}
|
||||
|
|
@ -105,6 +113,9 @@ class StripePaymentForm extends Component {
|
|||
}
|
||||
});
|
||||
}
|
||||
componentWillReceiveProps() {
|
||||
this.setState(initialState);
|
||||
}
|
||||
componentWillUnmount() {
|
||||
if (this.card) {
|
||||
this.card.removeEventListener('change', this.handleCardValueChange);
|
||||
|
|
@ -114,11 +125,21 @@ class StripePaymentForm extends Component {
|
|||
handleCardValueChange(event) {
|
||||
const { intl, onChange } = this.props;
|
||||
const { error, complete } = event;
|
||||
this.setState({
|
||||
error: error ? stripeErrorTranslation(intl, error) : null,
|
||||
cardValueValid: complete,
|
||||
|
||||
// A change in the card should clear the token and trigger a call
|
||||
// to the onChange prop with the cleared token and the current
|
||||
// message.
|
||||
|
||||
this.setState(prevState => {
|
||||
const { message } = prevState;
|
||||
const token = null;
|
||||
onChange({ token, message });
|
||||
return {
|
||||
error: error ? stripeErrorTranslation(intl, error) : null,
|
||||
cardValueValid: complete,
|
||||
token,
|
||||
};
|
||||
});
|
||||
onChange({ token: null });
|
||||
}
|
||||
handleSubmit(event) {
|
||||
event.preventDefault();
|
||||
|
|
@ -129,6 +150,13 @@ class StripePaymentForm extends Component {
|
|||
}
|
||||
|
||||
const { intl, onSubmit } = this.props;
|
||||
|
||||
if (this.state.token) {
|
||||
// Token already fetched for the current card value
|
||||
onSubmit({ token: this.state.token, message: this.state.message.trim() });
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({ submitting: true });
|
||||
|
||||
this.stripe
|
||||
|
|
@ -139,10 +167,11 @@ class StripePaymentForm extends Component {
|
|||
this.setState({
|
||||
submitting: false,
|
||||
error: stripeErrorTranslation(intl, error),
|
||||
token: null,
|
||||
});
|
||||
} else {
|
||||
this.setState({ submitting: false });
|
||||
onSubmit({ token: token.id });
|
||||
this.setState({ submitting: false, token: token.id });
|
||||
onSubmit({ token: token.id, message: this.state.message.trim() });
|
||||
}
|
||||
})
|
||||
.catch(e => {
|
||||
|
|
@ -158,7 +187,16 @@ class StripePaymentForm extends Component {
|
|||
});
|
||||
}
|
||||
render() {
|
||||
const { className, rootClassName, inProgress, formId, paymentInfo } = this.props;
|
||||
const {
|
||||
className,
|
||||
rootClassName,
|
||||
inProgress,
|
||||
formId,
|
||||
paymentInfo,
|
||||
onChange,
|
||||
authorDisplayName,
|
||||
intl,
|
||||
} = this.props;
|
||||
const submitInProgress = this.state.submitting || inProgress;
|
||||
const submitDisabled = !this.state.cardValueValid || submitInProgress;
|
||||
const classes = classNames(rootClassName || css.root, className);
|
||||
|
|
@ -167,6 +205,23 @@ class StripePaymentForm extends Component {
|
|||
[css.cardError]: this.state.error,
|
||||
});
|
||||
|
||||
const messagePlaceholder = intl.formatMessage(
|
||||
{ id: 'StripePaymentForm.messagePlaceholder' },
|
||||
{ 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;
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Form className={classes} onSubmit={this.handleSubmit}>
|
||||
<h3 className={css.paymentHeading}>
|
||||
|
|
@ -186,6 +241,12 @@ class StripePaymentForm extends Component {
|
|||
<h3 className={css.messageHeading}>
|
||||
<FormattedMessage id="StripePaymentForm.messageHeading" />
|
||||
</h3>
|
||||
<ExpandingTextarea
|
||||
className={css.message}
|
||||
placeholder={messagePlaceholder}
|
||||
value={this.state.message}
|
||||
onChange={handleMessageChange}
|
||||
/>
|
||||
<div className={css.submitContainer}>
|
||||
{paymentInfo ? <p className={css.paymentInfo}>{paymentInfo}</p> : null}
|
||||
<PrimaryButton
|
||||
|
|
@ -221,6 +282,7 @@ StripePaymentForm.propTypes = {
|
|||
onSubmit: func.isRequired,
|
||||
onChange: func,
|
||||
paymentInfo: string,
|
||||
authorDisplayName: string.isRequired,
|
||||
};
|
||||
|
||||
export default injectIntl(StripePaymentForm);
|
||||
|
|
|
|||
|
|
@ -521,6 +521,7 @@
|
|||
"StripePaymentForm.creditCardDetails": "Credit card details",
|
||||
"StripePaymentForm.genericError": "Could not handle payment data. Please try again.",
|
||||
"StripePaymentForm.messageHeading": "Message",
|
||||
"StripePaymentForm.messagePlaceholder": "Hello {name}! I'm looking forward to…",
|
||||
"StripePaymentForm.paymentHeading": "Payment",
|
||||
"StripePaymentForm.stripe.api_connection_error": "Could not connect to Stripe API.",
|
||||
"StripePaymentForm.stripe.api_error": "Error in Stripe API.",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue