From 600969694df4798b96ef9e96604166ff9ab742c0 Mon Sep 17 00:00:00 2001 From: Jenni Laakso Date: Fri, 5 Feb 2021 14:28:01 +0200 Subject: [PATCH 01/10] Add test data to stripe-config.js --- src/config.js | 3 ++- src/stripe-config.js | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/config.js b/src/config.js index 0c6f67a6..17a1fa17 100644 --- a/src/config.js +++ b/src/config.js @@ -1,6 +1,6 @@ import * as custom from './marketplace-custom-config.js'; import defaultLocationSearches from './default-location-searches'; -import { defaultMCC, stripePublishableKey, stripeCountryDetails } from './stripe-config'; +import { defaultMCC, stripePublishableKey, stripeCountryDetails, testData } from './stripe-config'; import { currencyConfiguration } from './currency-config'; const env = process.env.REACT_APP_ENV; @@ -229,6 +229,7 @@ const config = { defaultMCC: defaultMCC, publishableKey: stripePublishableKey, supportedCountries: stripeCountryDetails, + testData: testData, }, canonicalRootURL, address: { diff --git a/src/stripe-config.js b/src/stripe-config.js index 89585206..4bae7219 100644 --- a/src/stripe-config.js +++ b/src/stripe-config.js @@ -1,3 +1,6 @@ +import { types as sdkTypes } from './util/sdkLoader'; +const { UUID } = sdkTypes; + /* Stripe related configuration. NOTE: REACT_APP_STRIPE_PUBLISHABLE_KEY is mandatory environment variable. @@ -329,6 +332,41 @@ export const stripeCountryDetails = [ }, ]; +/** + * Stripe test data + * + * This data is for filling up the test values related to Stripe + * in the demo application to make testing easier. + */ + +export const testData = { + basicTestCardToken: 'tok_visa', + basicTestCardDetails: { + id: new UUID('test-card'), + type: 'stripePaymentMethod', + attributes: { + type: 'stripe-payment-method/card', + stripePaymentMethodId: 'test-card', + card: { + brand: 'visa', + last4Digits: '4242', + expirationMonth: 4, + expirationYear: 2424, + }, + }, + }, + address: { + addressLine1: 'Erottajankatu 19', + postal: '00130', + city: 'Helsinki', + country: 'FI', + }, + accountType: 'individual', + country: 'FI', + bankAccountNumber: 'FI89370400440532013000', + bankAccountType: 'iban', +}; + /* NOTE: This configuration will not be updated! We might remove this code in the later releases. From 78137058c7e21944566e39e327c3bc5fc7b9204d Mon Sep 17 00:00:00 2001 From: Jenni Laakso Date: Fri, 5 Feb 2021 14:30:25 +0200 Subject: [PATCH 02/10] Use test data for payout details --- .../EditListingWizard/EditListingWizard.js | 23 ++++++++++++++++++- .../EditListingWizard.module.css | 7 ++++++ .../StripeBankAccountTokenInputField.js | 11 ++++++++- .../StripeConnectAccountForm.js | 14 ++++++++++- 4 files changed, 52 insertions(+), 3 deletions(-) diff --git a/src/components/EditListingWizard/EditListingWizard.js b/src/components/EditListingWizard/EditListingWizard.js index 00a3c167..09e2f0c9 100644 --- a/src/components/EditListingWizard/EditListingWizard.js +++ b/src/components/EditListingWizard/EditListingWizard.js @@ -15,7 +15,13 @@ import { } from '../../util/urlHelpers'; import { ensureCurrentUser, ensureListing } from '../../util/data'; -import { Modal, NamedRedirect, Tabs, StripeConnectAccountStatusBox } from '../../components'; +import { + Button, + Modal, + NamedRedirect, + Tabs, + StripeConnectAccountStatusBox, +} from '../../components'; import { StripeConnectAccountForm } from '../../forms'; import EditListingWizardTab, { @@ -193,6 +199,7 @@ class EditListingWizard extends Component { this.state = { draftId: null, showPayoutDetails: false, + useDefaultTestData: false, }; this.handleCreateFlowTabScrolling = this.handleCreateFlowTabScrolling.bind(this); this.handlePublishListing = this.handlePublishListing.bind(this); @@ -366,6 +373,15 @@ class EditListingWizard extends Component { return ; } + const handleStripeTestData = () => { + this.setState({ useDefaultTestData: true }); + }; + + const stripeDefaultTestData = config.stripe.testData; + const stripeInitialValues = this.state.useDefaultTestData + ? { accountType: stripeDefaultTestData.accountType, country: stripeDefaultTestData.country } + : null; + return (

+ {stripeConnected && !returnedAbnormallyFromStripe && showVerificationNeeded ? ( { this.initialState[inputType] = { - value: '', + value: this.props.useDefaultTestData ? config.stripe.testData.bankAccountNumber : null, touched: false, error: formatFieldMessage(intl, inputType, 'required'), }; @@ -76,6 +76,15 @@ class TokenInputFieldComponent extends Component { } this.stripe = window.Stripe(config.stripe.publishableKey); this._isMounted = true; + + if (!!this.props.useDefaultTestData) { + this.handleInputChange( + { target: { value: config.stripe.testData.bankAccountNumber } }, + config.stripe.testData.bankAccountType, + config.stripe.testData.country, + this.props.intl + ); + } } componentDidUpdate(prevProps) { diff --git a/src/forms/StripeConnectAccountForm/StripeConnectAccountForm.js b/src/forms/StripeConnectAccountForm/StripeConnectAccountForm.js index f2a37ffa..63cbdb1a 100644 --- a/src/forms/StripeConnectAccountForm/StripeConnectAccountForm.js +++ b/src/forms/StripeConnectAccountForm/StripeConnectAccountForm.js @@ -40,7 +40,16 @@ const countryCurrency = countryCode => { }; const CreateStripeAccountFields = props => { - const { disabled, countryLabel, showAsRequired, form, values, intl, currentUserId } = props; + const { + disabled, + countryLabel, + showAsRequired, + form, + values, + intl, + currentUserId, + useDefaultTestData, + } = props; /* We pass some default values to Stripe when creating a new Stripe account in order to reduce couple of steps from Connect Onboarding form. @@ -138,6 +147,7 @@ const CreateStripeAccountFields = props => { country={country} currency={countryCurrency(country)} validate={validators.required(' ')} + useDefaultTestData={useDefaultTestData} /> ) : null}
@@ -242,6 +252,7 @@ const StripeConnectAccountFormComponent = props => { values, stripeConnected, currentUser, + useDefaultTestData, } = fieldRenderProps; const accountDataLoaded = stripeConnected && stripeAccountFetched && savedCountry; @@ -278,6 +289,7 @@ const StripeConnectAccountFormComponent = props => { form={form} values={values} intl={intl} + useDefaultTestData={useDefaultTestData} /> ) : ( Date: Fri, 5 Feb 2021 14:31:46 +0200 Subject: [PATCH 03/10] Use test data for billing details --- src/containers/CheckoutPage/CheckoutPage.js | 64 +++++++++++++------ .../CheckoutPage/CheckoutPage.module.css | 10 ++- .../StripePaymentForm/StripePaymentForm.js | 40 +++++++++--- 3 files changed, 83 insertions(+), 31 deletions(-) diff --git a/src/containers/CheckoutPage/CheckoutPage.js b/src/containers/CheckoutPage/CheckoutPage.js index 02324629..5d5af28f 100644 --- a/src/containers/CheckoutPage/CheckoutPage.js +++ b/src/containers/CheckoutPage/CheckoutPage.js @@ -39,6 +39,7 @@ import { NamedRedirect, Page, ResponsiveImage, + Button, } from '../../components'; import { StripePaymentForm } from '../../forms'; import { isScrollingDisabled } from '../../ducks/UI.duck'; @@ -101,6 +102,7 @@ export class CheckoutPageComponent extends Component { pageData: {}, dataLoaded: false, submitting: false, + useDefaultTestData: false, }; this.stripe = null; @@ -108,6 +110,7 @@ export class CheckoutPageComponent extends Component { this.loadInitialData = this.loadInitialData.bind(this); this.handlePaymentIntent = this.handlePaymentIntent.bind(this); this.handleSubmit = this.handleSubmit.bind(this); + this.handleInitialTestData = this.handleInitialTestData.bind(this); } componentDidMount() { @@ -462,6 +465,10 @@ export class CheckoutPageComponent extends Component { }); } + handleInitialTestData = () => { + this.setState({ useDefaultTestData: true }); + }; + onStripeInitialized(stripe) { this.stripe = stripe; @@ -746,7 +753,9 @@ export class CheckoutPageComponent extends Component { // If your marketplace works mostly in one country you can use initial values to select country automatically // e.g. {country: 'FI'} - const initalValuesForStripePayment = { name: userName }; + const initalValuesForStripePayment = !this.state.useDefaultTestData + ? { name: userName } + : { name: userName, ...config.stripe.testData.address }; return ( @@ -792,26 +801,39 @@ export class CheckoutPageComponent extends Component {

) : null} {showPaymentForm ? ( - + <> + {!hasDefaultPaymentMethod ? ( + + ) : null} + + ) : null} {isPaymentExpired ? (

diff --git a/src/containers/CheckoutPage/CheckoutPage.module.css b/src/containers/CheckoutPage/CheckoutPage.module.css index fa1f4312..b702eec2 100644 --- a/src/containers/CheckoutPage/CheckoutPage.module.css +++ b/src/containers/CheckoutPage/CheckoutPage.module.css @@ -141,12 +141,11 @@ @media (--viewportMedium) { margin-top: 27px; - margin-bottom: 30px; + margin-bottom: 22px; } @media (--viewportLarge) { margin-top: 0px; - margin-bottom: 54px; padding: 0; } } @@ -331,3 +330,10 @@ margin: 0 48px; } } + +.stripeTestDataButton { + @apply --marketplaceSmallFontStyles; + width: 100%; + min-height: 40px; + margin-bottom: 16px; +} diff --git a/src/forms/StripePaymentForm/StripePaymentForm.js b/src/forms/StripePaymentForm/StripePaymentForm.js index 399c407e..caf85998 100644 --- a/src/forms/StripePaymentForm/StripePaymentForm.js +++ b/src/forms/StripePaymentForm/StripePaymentForm.js @@ -86,7 +86,16 @@ const cardStyles = { }; const OneTimePaymentWithCardElement = props => { - const { cardClasses, formId, handleStripeElementRef, hasCardError, error, label, intl } = props; + const { + cardClasses, + formId, + handleStripeElementRef, + hasCardError, + error, + label, + intl, + useDefaultTestData, + } = props; const labelText = label || intl.formatMessage({ id: 'StripePaymentForm.saveAfterOnetimePayment' }); return ( @@ -94,8 +103,14 @@ const OneTimePaymentWithCardElement = props => { -

- {hasCardError ? {error} : null} + {useDefaultTestData ? ( + <>Use test card + ) : ( + <> +
+ {hasCardError ? {error} : null} + + )}
{ error, paymentMethod, intl, + useDefaultTestData, } = props; const last4Digits = defaultPaymentMethod.attributes.card.last4Digits; const labelText = intl.formatMessage( @@ -151,6 +167,7 @@ const PaymentMethodSelector = props => { error={error} label={labelText} intl={intl} + useDefaultTestData={useDefaultTestData} /> ) : null} @@ -289,7 +306,8 @@ class StripePaymentForm extends Component { const { initialMessage } = values; const { cardValueValid, paymentMethod } = this.state; const billingDetailsKnown = hasHandledCardPayment || defaultPaymentMethod; - const onetimePaymentNeedsAttention = !billingDetailsKnown && !cardValueValid; + const onetimePaymentNeedsAttention = + !billingDetailsKnown && !cardValueValid && !this.props.useDefaultTestData; if (inProgress || onetimePaymentNeedsAttention) { // Already submitting or card value incomplete/invalid @@ -298,7 +316,11 @@ class StripePaymentForm extends Component { const params = { message: initialMessage ? initialMessage.trim() : null, - card: this.card, + card: this.props.useDefaultTestData + ? { + token: config.stripe.testData.basicTestCardToken, + } + : card, formId, formValues: values, paymentMethod: getPaymentMethod( @@ -328,6 +350,7 @@ class StripePaymentForm extends Component { form, hasHandledCardPayment, defaultPaymentMethod, + useDefaultTestData, } = formRenderProps; this.finalFormAPI = form; @@ -392,9 +415,8 @@ class StripePaymentForm extends Component { this.state.paymentMethod, showPaymentMethodSelector ); - const showOnetimePaymentFields = ['onetimeCardPayment', 'replaceCard'].includes( - selectedPaymentMethod - ); + const showOnetimePaymentFields = + !!useDefaultTestData || ['onetimeCardPayment', 'replaceCard'].includes(selectedPaymentMethod); return hasStripeKey ? (
{billingDetailsNeeded && !loadingData ? ( @@ -410,6 +432,7 @@ class StripePaymentForm extends Component { error={this.state.error} paymentMethod={selectedPaymentMethod} intl={intl} + useDefaultTestData={useDefaultTestData} /> ) : ( @@ -423,6 +446,7 @@ class StripePaymentForm extends Component { hasCardError={hasCardError} error={this.state.error} intl={intl} + useDefaultTestData={useDefaultTestData} /> )} From aea0ef55a1e0b09f114efa050b36f1f424775de0 Mon Sep 17 00:00:00 2001 From: Jenni Laakso Date: Mon, 8 Feb 2021 16:59:08 +0200 Subject: [PATCH 04/10] Use test data on StripePayoutPage --- .../StripePayoutPage/StripePayoutPage.js | 99 +++++++++++-------- .../StripePayoutPage.module.css | 9 ++ 2 files changed, 68 insertions(+), 40 deletions(-) diff --git a/src/containers/StripePayoutPage/StripePayoutPage.js b/src/containers/StripePayoutPage/StripePayoutPage.js index d3df24a0..de23536a 100644 --- a/src/containers/StripePayoutPage/StripePayoutPage.js +++ b/src/containers/StripePayoutPage/StripePayoutPage.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useState } from 'react'; import { bool, func, oneOf, shape } from 'prop-types'; import { compose } from 'redux'; import { connect } from 'react-redux'; @@ -14,6 +14,7 @@ import { getStripeConnectAccountLink, } from '../../ducks/stripeConnectAccount.duck'; import { + Button, NamedRedirect, LayoutSideNavigation, LayoutWrapperMain, @@ -95,6 +96,17 @@ export const StripePayoutPageComponent = props => { intl, } = props; + const [useDefaultTestData, setUseDefaultTestData] = useState(false); + + const handleStripeTestData = () => { + setUseDefaultTestData(true); + }; + + const stripeDefaultTestData = config.stripe.testData; + const stripeInitialValues = useDefaultTestData + ? { accountType: stripeDefaultTestData.accountType, country: stripeDefaultTestData.country } + : null; + const { returnURLType } = params; const ensuredCurrentUser = ensureCurrentUser(currentUser); const currentUserLoaded = !!ensuredCurrentUser.id; @@ -164,45 +176,52 @@ export const StripePayoutPageComponent = props => { ) : returnedAbnormallyFromStripe && !getAccountLinkError ? ( ) : ( - - {stripeConnected && !returnedAbnormallyFromStripe && showVerificationNeeded ? ( - - ) : stripeConnected && savedCountry && !returnedAbnormallyFromStripe ? ( - - ) : null} - + <> + + + {stripeConnected && !returnedAbnormallyFromStripe && showVerificationNeeded ? ( + + ) : stripeConnected && savedCountry && !returnedAbnormallyFromStripe ? ( + + ) : null} + + )}
diff --git a/src/containers/StripePayoutPage/StripePayoutPage.module.css b/src/containers/StripePayoutPage/StripePayoutPage.module.css index 567ac1ef..3d1bc22f 100644 --- a/src/containers/StripePayoutPage/StripePayoutPage.module.css +++ b/src/containers/StripePayoutPage/StripePayoutPage.module.css @@ -1,3 +1,5 @@ +@import '../../styles/propertySets.css'; + .content { @media (--viewportMedium) { margin: 32px auto 0 auto; @@ -24,3 +26,10 @@ margin-bottom: 47px; } } + +.stripeTestDataButton { + @apply --marketplaceSmallFontStyles; + width: 100%; + min-height: 40px; + margin-top: 24px; +} From 62b01caadae9ea9d3c3fe809a1d6a46c7e28579a Mon Sep 17 00:00:00 2001 From: Jenni Laakso Date: Mon, 8 Feb 2021 17:00:21 +0200 Subject: [PATCH 05/10] Use test data on PaymentMethodPage --- .../PaymentMethodsPage/PaymentMethodsPage.js | 43 +++++++++++++------ .../PaymentMethodsForm/PaymentMethodsForm.js | 39 ++++++++++------- 2 files changed, 52 insertions(+), 30 deletions(-) diff --git a/src/containers/PaymentMethodsPage/PaymentMethodsPage.js b/src/containers/PaymentMethodsPage/PaymentMethodsPage.js index 62d10cbc..7d503eed 100644 --- a/src/containers/PaymentMethodsPage/PaymentMethodsPage.js +++ b/src/containers/PaymentMethodsPage/PaymentMethodsPage.js @@ -2,6 +2,7 @@ import React, { useState } from 'react'; import { bool, func, object } from 'prop-types'; import { compose } from 'redux'; import { connect } from 'react-redux'; +import config from '../../config'; import { FormattedMessage, injectIntl, intlShape } from '../../util/reactIntl'; import { ensureCurrentUser, ensureStripeCustomer, ensurePaymentMethodCard } from '../../util/data'; import { propTypes } from '../../util/types'; @@ -9,6 +10,7 @@ import { savePaymentMethod, deletePaymentMethod } from '../../ducks/paymentMetho import { handleCardSetup } from '../../ducks/stripe.duck'; import { manageDisableScrolling, isScrollingDisabled } from '../../ducks/UI.duck'; import { + Button, SavedCardDetails, LayoutSideNavigation, LayoutWrapperMain, @@ -28,6 +30,7 @@ import css from './PaymentMethodsPage.module.css'; const PaymentMethodsPageComponent = props => { const [isSubmitting, setIsSubmitting] = useState(false); const [cardState, setCardState] = useState(null); + const [useDefaultTestData, setUseDefaultTestData] = useState(false); const { currentUser, @@ -136,7 +139,13 @@ const PaymentMethodsPageComponent = props => { ? `${ensuredCurrentUser.attributes.profile.firstName} ${ensuredCurrentUser.attributes.profile.lastName}` : null; - const initalValuesForStripePayment = { name: userName }; + const initalValuesForStripePayment = !useDefaultTestData + ? { name: userName } + : { name: userName, ...config.stripe.testData.address }; + + const handleInitialTestData = () => { + setUseDefaultTestData(true); + }; const card = hasDefaultPaymentMethod ? ensurePaymentMethodCard(currentUser.stripeCustomer.defaultPaymentMethod).attributes.card @@ -173,19 +182,25 @@ const PaymentMethodsPageComponent = props => { /> ) : null} {showForm ? ( - + <> + + + ) : null} )} diff --git a/src/forms/PaymentMethodsForm/PaymentMethodsForm.js b/src/forms/PaymentMethodsForm/PaymentMethodsForm.js index e90927fe..eacd0650 100644 --- a/src/forms/PaymentMethodsForm/PaymentMethodsForm.js +++ b/src/forms/PaymentMethodsForm/PaymentMethodsForm.js @@ -146,7 +146,7 @@ class PaymentMethodsForm extends Component { } handleSubmit(values) { const { onSubmit, inProgress, formId } = this.props; - const cardInputNeedsAttention = !this.state.cardValueValid; + const cardInputNeedsAttention = !this.state.cardValueValid && !this.props.useDefaultTestData; if (inProgress || cardInputNeedsAttention) { // Already submitting or card value incomplete/invalid @@ -155,7 +155,7 @@ class PaymentMethodsForm extends Component { const params = { stripe: this.stripe, - card: this.card, + card: this.props.useDefaultTestData ? { payment_method: 'pm_card_visa' } : this.card, formId, formValues: values, }; @@ -177,10 +177,11 @@ class PaymentMethodsForm extends Component { createStripeCustomerError, handleCardSetupError, form, + useDefaultTestData, } = formRenderProps; this.finalFormAPI = form; - const cardInputNeedsAttention = !this.state.cardValueValid; + const cardInputNeedsAttention = !this.state.cardValueValid && !useDefaultTestData; const submitDisabled = invalid || cardInputNeedsAttention || submitInProgress; const hasCardError = this.state.error && !submitInProgress; const classes = classNames(rootClassName || css.root, className); @@ -219,19 +220,25 @@ class PaymentMethodsForm extends Component { return hasStripeKey ? ( - - -
{ - this.cardContainer = el; - }} - /> -
{infoText}
- {hasCardError ? {this.state.error} : null} + {useDefaultTestData ? ( + <>Test card + ) : ( + <> + + +
{ + this.cardContainer = el; + }} + /> +
{infoText}
+ {hasCardError ? {this.state.error} : null} + + )}

From 5b1d701897e00ce8d8df75a06d433d4a3ee2e385 Mon Sep 17 00:00:00 2001 From: Jenni Laakso Date: Mon, 8 Feb 2021 17:03:50 +0200 Subject: [PATCH 06/10] Update tests --- .../__snapshots__/CheckoutPage.test.js.snap | 13 ++++++ .../StripePayoutPage.test.js.snap | 42 +++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/src/containers/CheckoutPage/__snapshots__/CheckoutPage.test.js.snap b/src/containers/CheckoutPage/__snapshots__/CheckoutPage.test.js.snap index 1010dfa5..362c07e4 100644 --- a/src/containers/CheckoutPage/__snapshots__/CheckoutPage.test.js.snap +++ b/src/containers/CheckoutPage/__snapshots__/CheckoutPage.test.js.snap @@ -98,6 +98,18 @@ exports[`CheckoutPage matches snapshot 1`] = `
+

diff --git a/src/containers/StripePayoutPage/__snapshots__/StripePayoutPage.test.js.snap b/src/containers/StripePayoutPage/__snapshots__/StripePayoutPage.test.js.snap index 21869175..b23e04f8 100644 --- a/src/containers/StripePayoutPage/__snapshots__/StripePayoutPage.test.js.snap +++ b/src/containers/StripePayoutPage/__snapshots__/StripePayoutPage.test.js.snap @@ -43,6 +43,18 @@ exports[`StripePayoutPage matches snapshot with Stripe connected 1`] = ` values={Object {}} /> +
@@ -145,6 +159,18 @@ exports[`StripePayoutPage matches snapshot with Stripe not connected 1`] = ` values={Object {}} /> +
@@ -237,6 +265,18 @@ exports[`StripePayoutPage matches snapshot with details submitted 1`] = ` values={Object {}} /> +
From 7adbb16c96dcb09b6b107599ef78f3c8a027a8fa Mon Sep 17 00:00:00 2001 From: Jenni Laakso Date: Tue, 9 Feb 2021 14:56:55 +0200 Subject: [PATCH 07/10] Add translation keys --- .../EditListingWizard/EditListingWizard.js | 2 +- src/containers/CheckoutPage/CheckoutPage.js | 2 +- .../__snapshots__/CheckoutPage.test.js.snap | 5 ++++- .../PaymentMethodsPage/PaymentMethodsPage.js | 3 ++- .../StripePayoutPage/StripePayoutPage.js | 2 +- .../__snapshots__/StripePayoutPage.test.js.snap | 15 ++++++++++++--- .../PaymentMethodsForm/PaymentMethodsForm.js | 7 ++++++- src/forms/StripePaymentForm/StripePaymentForm.js | 7 ++++++- src/translations/en.json | 6 ++++++ 9 files changed, 39 insertions(+), 10 deletions(-) diff --git a/src/components/EditListingWizard/EditListingWizard.js b/src/components/EditListingWizard/EditListingWizard.js index 09e2f0c9..c2b5351e 100644 --- a/src/components/EditListingWizard/EditListingWizard.js +++ b/src/components/EditListingWizard/EditListingWizard.js @@ -437,7 +437,7 @@ class EditListingWizard extends Component {

- Fill in test details + ) : null} - Fill in test details + { const handleRemovePaymentMethod = () => { onDeletePaymentMethod().then(() => { + setUseDefaultTestData(false); fetchStripeCustomer(); }); }; @@ -184,7 +185,7 @@ const PaymentMethodsPageComponent = props => { {showForm ? ( <> { ) : ( <> - Fill in test details + - Fill in test details + - Fill in test details + {useDefaultTestData ? ( - <>Test card + ) : ( <> {useDefaultTestData ? ( - <>Use test card + ) : ( <>
diff --git a/src/translations/en.json b/src/translations/en.json index ae451266..b6f9cba3 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -94,6 +94,7 @@ "CheckoutPage.bookingTimeNotAvailableMessage": "Unfortunately, the requested time is already booked.", "CheckoutPage.chargeDisabledMessage": "This provider's payout information is incomplete so this listing cannot be booked. Please contact the marketplace administrators.", "CheckoutPage.errorlistingLinkText": "the sauna page", + "CheckoutPage.fillInTestDetails": "Fill in test details", "CheckoutPage.goToLandingPage": "Go to homepage", "CheckoutPage.hostedBy": "Hosted by {name}", "CheckoutPage.initiateOrderAmountTooLow": "We are unable to process this payment since the payment amount is too low. Please contact the marketplace administrator.", @@ -232,6 +233,7 @@ "EditListingPricingPanel.createListingTitle": "How much does it cost?", "EditListingPricingPanel.listingPriceCurrencyInvalid": "Listing currency is different from the marketplace currency. You cannot edit the price.", "EditListingPricingPanel.title": "Edit the pricing of {listingTitle}", + "EditListingWizard.fillInTestDetails": "Fill in test details", "EditListingWizard.payoutModalInfo": "Almost done! In order to send you money, we need to know a bit more about you. Next, we will guide you through verifying your account. The details can also be edited from Account Setting page on Payout details tab. ", "EditListingWizard.payoutModalTitleOneMoreThing": "One more thing:", "EditListingWizard.payoutModalTitlePayoutPreferences": "Payout preferences", @@ -509,10 +511,12 @@ "PaymentMethodsForm.confirmCardPaymentError": "We are unable to authenticate your payment method. Please check your authentication details and try again.", "PaymentMethodsForm.infoText": "I authorise Saunatime to send instructions to the financial institution that issued my card to take payments from my card account in accordance with the terms of my agreement with you.", "PaymentMethodsForm.paymentHeading": "Payment", + "PaymentMethodsPage.fillInTestDetails": "Fill in test details", "PaymentMethodsPage.heading": "Payment methods", "PaymentMethodsPage.loadingData": "Loading data…", "PaymentMethodsPage.savedPaymentMethodTitle": "Credit card details", "PaymentMethodsForm.submitPaymentInfo": "Save payment card", + "PaymentMethodsForm.useDefaultTestCard": "Using test card •••• •••• •••• {last4}", "PaymentMethodsPage.title": "Payment methods", "PayoutDetailsForm.accountOpenerInfoText": "Account opener needs to be an individual with authorization to sign on behalf of the organization.", "PayoutDetailsForm.accountOpenerTitle": "Account opener", @@ -906,6 +910,7 @@ "StripePaymentForm.stripe.validation_error.processing_error": "An error occurred while processing the card.", "StripePaymentForm.submitConfirmPaymentInfo": "Confirm request", "StripePaymentForm.submitPaymentInfo": "Send request", + "StripePaymentForm.useDefaultTestCard": "Using test card •••• •••• •••• {last4}", "StripeConnectAccountForm.accountTypeTitle": "Account type", "StripeConnectAccountForm.bankAccountLabel": "Bank account", "StripeConnectAccountForm.companyAccount": "I represent a company", @@ -956,6 +961,7 @@ "StripeConnectAccountForm.loadingStripeAccountData": "Fetching payout details…", "StripeConnectAccountForm.stripeToSText": "By saving details, you agree to the {stripeConnectedAccountTermsLink}", "StripeConnectAccountForm.stripeConnectedAccountTermsLink": "Stripe Connected Account Agreement", + "StripePayoutPage.fillInTestDetails": "Fill in test details", "StripePayoutPage.heading": "Payout details", "StripePayoutPage.loadingData": "Loading data…", "StripePayoutPage.redirectingToStripe": "You returned early from Stripe. Redirecting you back to Stripe…", From b369b4d0cbeaa152fada3bce5dfdefbe6f413110 Mon Sep 17 00:00:00 2001 From: Jenni Laakso Date: Wed, 10 Feb 2021 10:41:55 +0200 Subject: [PATCH 08/10] Add some code comments --- .../StripeBankAccountTokenInputField.js | 6 ++++++ src/forms/PaymentMethodsForm/PaymentMethodsForm.js | 7 ++++++- src/forms/StripePaymentForm/StripePaymentForm.js | 3 +++ src/stripe-config.js | 1 + 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.js b/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.js index d2938a1f..7f26581e 100644 --- a/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.js +++ b/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.js @@ -40,6 +40,8 @@ class TokenInputFieldComponent extends Component { }; // Fill initialState with input type specific data + // Demo specific: If the user wants to use default test values, + // we need to add the default bankAccountNumber as inital value BANK_ACCOUNT_INPUTS.forEach(inputType => { this.initialState[inputType] = { value: this.props.useDefaultTestData ? config.stripe.testData.bankAccountNumber : null, @@ -77,6 +79,10 @@ class TokenInputFieldComponent extends Component { this.stripe = window.Stripe(config.stripe.publishableKey); this._isMounted = true; + // Demo specific: If the user wants to use default test values, + // we need to trigger fetching the bank account token from Stripe + // separately (as the value is initial value and the field has not changed yet actually). + // This is a bit hacky, but it keeps the diff in minimum. if (!!this.props.useDefaultTestData) { this.handleInputChange( { target: { value: config.stripe.testData.bankAccountNumber } }, diff --git a/src/forms/PaymentMethodsForm/PaymentMethodsForm.js b/src/forms/PaymentMethodsForm/PaymentMethodsForm.js index da0e591f..c898401e 100644 --- a/src/forms/PaymentMethodsForm/PaymentMethodsForm.js +++ b/src/forms/PaymentMethodsForm/PaymentMethodsForm.js @@ -153,9 +153,14 @@ class PaymentMethodsForm extends Component { return; } + // Demo specific: If the user wants to use default test values, + // we should pass the default test token from Stripe instead of using + // card from Stripe Element (it's not possible to pass default value to that). const params = { stripe: this.stripe, - card: this.props.useDefaultTestData ? { payment_method: 'pm_card_visa' } : this.card, + card: this.props.useDefaultTestData + ? { payment_method: config.stripe.testData.basicTestPaymentMethodToken } + : this.card, formId, formValues: values, }; diff --git a/src/forms/StripePaymentForm/StripePaymentForm.js b/src/forms/StripePaymentForm/StripePaymentForm.js index ca7a2cd8..e57fad40 100644 --- a/src/forms/StripePaymentForm/StripePaymentForm.js +++ b/src/forms/StripePaymentForm/StripePaymentForm.js @@ -319,6 +319,9 @@ class StripePaymentForm extends Component { return; } + // Demo specific: If the user wants to use default test values, + // we should pass the default test token from Stripe instead of using + // card from Stripe Element (it's not possible to pass default value to that). const params = { message: initialMessage ? initialMessage.trim() : null, card: this.props.useDefaultTestData diff --git a/src/stripe-config.js b/src/stripe-config.js index 4bae7219..7b7a3f2d 100644 --- a/src/stripe-config.js +++ b/src/stripe-config.js @@ -340,6 +340,7 @@ export const stripeCountryDetails = [ */ export const testData = { + basicTestPaymentMethodToken: 'pm_card_visa', basicTestCardToken: 'tok_visa', basicTestCardDetails: { id: new UUID('test-card'), From 6700dfb9ab3cec6db9baf1b70c57ee9140e67dc6 Mon Sep 17 00:00:00 2001 From: Jenni Laakso Date: Wed, 10 Feb 2021 15:19:57 +0200 Subject: [PATCH 09/10] Update address in config --- src/stripe-config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stripe-config.js b/src/stripe-config.js index 7b7a3f2d..cc9c65d5 100644 --- a/src/stripe-config.js +++ b/src/stripe-config.js @@ -357,7 +357,7 @@ export const testData = { }, }, address: { - addressLine1: 'Erottajankatu 19', + addressLine1: 'Main Street 123', postal: '00130', city: 'Helsinki', country: 'FI', From 8d59fda3d7271ad7b41a4e5f0a2f6bb014b42d6a Mon Sep 17 00:00:00 2001 From: Jenni Laakso Date: Thu, 11 Feb 2021 10:24:47 +0200 Subject: [PATCH 10/10] Make upstream updates easier by organizing the code a bit differently --- .../EditListingWizard/EditListingWizard.js | 17 ++- .../EditListingWizard.module.css | 7 -- .../EditListingWizardDemoChanges.module.css | 8 ++ src/containers/CheckoutPage/CheckoutPage.js | 78 +++++++------ .../CheckoutPage/CheckoutPage.module.css | 9 +- .../CheckoutPageDemoChanges.module.css | 8 ++ .../__snapshots__/CheckoutPage.test.js.snap | 16 +-- .../PaymentMethodsPage/PaymentMethodsPage.js | 57 +++++---- .../PaymentMethodsPageDemoChanges.module.css | 8 ++ .../StripePayoutPage/StripePayoutPage.js | 109 ++++++++++-------- .../StripePayoutPage.module.css | 9 -- .../StripePayoutPageDemoChanges.module.css | 8 ++ .../StripePayoutPage.test.js.snap | 48 +------- .../StripePaymentForm/StripePaymentForm.js | 5 +- src/stripe-config.js | 2 +- 15 files changed, 187 insertions(+), 202 deletions(-) create mode 100644 src/components/EditListingWizard/EditListingWizardDemoChanges.module.css create mode 100644 src/containers/CheckoutPage/CheckoutPageDemoChanges.module.css create mode 100644 src/containers/PaymentMethodsPage/PaymentMethodsPageDemoChanges.module.css create mode 100644 src/containers/StripePayoutPage/StripePayoutPageDemoChanges.module.css diff --git a/src/components/EditListingWizard/EditListingWizard.js b/src/components/EditListingWizard/EditListingWizard.js index c2b5351e..239d7224 100644 --- a/src/components/EditListingWizard/EditListingWizard.js +++ b/src/components/EditListingWizard/EditListingWizard.js @@ -34,6 +34,7 @@ import EditListingWizardTab, { PHOTOS, } from './EditListingWizardTab'; import css from './EditListingWizard.module.css'; +import cssForDemo from './EditListingWizardDemoChanges.module.css'; // Show availability calendar only if environment variable availabilityEnabled is true const availabilityMaybe = config.enableAvailability ? [AVAILABILITY] : []; @@ -373,15 +374,23 @@ class EditListingWizard extends Component { return ; } + // Demo customization begins const handleStripeTestData = () => { this.setState({ useDefaultTestData: true }); }; const stripeDefaultTestData = config.stripe.testData; - const stripeInitialValues = this.state.useDefaultTestData + const stripeInitialValuesForDemo = this.state.useDefaultTestData ? { accountType: stripeDefaultTestData.accountType, country: stripeDefaultTestData.country } : null; + const FillDemoDataButton = () => ( + + ); + // Demo customization ends + return (

- + {stripeConnected && !returnedAbnormallyFromStripe && showVerificationNeeded ? ( diff --git a/src/components/EditListingWizard/EditListingWizard.module.css b/src/components/EditListingWizard/EditListingWizard.module.css index 84aa5dcb..96db275f 100644 --- a/src/components/EditListingWizard/EditListingWizard.module.css +++ b/src/components/EditListingWizard/EditListingWizard.module.css @@ -116,10 +116,3 @@ .modalMessage { @apply --marketplaceModalParagraphStyles; } - -.stripeTestDataButton { - @apply --marketplaceSmallFontStyles; - width: 100%; - min-height: 40px; - margin-top: 24px; -} diff --git a/src/components/EditListingWizard/EditListingWizardDemoChanges.module.css b/src/components/EditListingWizard/EditListingWizardDemoChanges.module.css new file mode 100644 index 00000000..8d0964ac --- /dev/null +++ b/src/components/EditListingWizard/EditListingWizardDemoChanges.module.css @@ -0,0 +1,8 @@ +@import '../../styles/propertySets.css'; + +.stripeTestDataButton { + @apply --marketplaceSmallFontStyles; + width: 100%; + min-height: 40px; + margin-top: 24px; +} diff --git a/src/containers/CheckoutPage/CheckoutPage.js b/src/containers/CheckoutPage/CheckoutPage.js index 87346123..512bfe22 100644 --- a/src/containers/CheckoutPage/CheckoutPage.js +++ b/src/containers/CheckoutPage/CheckoutPage.js @@ -56,6 +56,7 @@ import { } from './CheckoutPage.duck'; import { storeData, storedData, clearData } from './CheckoutPageSessionHelpers'; import css from './CheckoutPage.module.css'; +import cssForDemo from './CheckoutPageDemoChanges.module.css'; const STORAGE_KEY = 'CheckoutPage'; @@ -110,6 +111,8 @@ export class CheckoutPageComponent extends Component { this.loadInitialData = this.loadInitialData.bind(this); this.handlePaymentIntent = this.handlePaymentIntent.bind(this); this.handleSubmit = this.handleSubmit.bind(this); + + // For demo: this.handleInitialTestData = this.handleInitialTestData.bind(this); } @@ -465,10 +468,6 @@ export class CheckoutPageComponent extends Component { }); } - handleInitialTestData = () => { - this.setState({ useDefaultTestData: true }); - }; - onStripeInitialized(stripe) { this.stripe = stripe; @@ -497,6 +496,11 @@ export class CheckoutPageComponent extends Component { } } + // For demo: + handleInitialTestData = () => { + this.setState({ useDefaultTestData: true }); + }; + render() { const { scrollingDisabled, @@ -757,6 +761,17 @@ export class CheckoutPageComponent extends Component { ? { name: userName } : { name: userName, ...config.stripe.testData.address }; + // Demo customization begins + const showFillDemoDataButton = showPaymentForm && !hasDefaultPaymentMethod; + + const FillDemoDataButton = () => + showFillDemoDataButton ? ( + + ) : null; + // Demo customization ends + return ( {topbar} @@ -800,40 +815,29 @@ export class CheckoutPageComponent extends Component { />

) : null} + {showPaymentForm ? ( - <> - {!hasDefaultPaymentMethod ? ( - - ) : null} - - + ) : null} {isPaymentExpired ? (

diff --git a/src/containers/CheckoutPage/CheckoutPage.module.css b/src/containers/CheckoutPage/CheckoutPage.module.css index b702eec2..5fe4f248 100644 --- a/src/containers/CheckoutPage/CheckoutPage.module.css +++ b/src/containers/CheckoutPage/CheckoutPage.module.css @@ -141,7 +141,7 @@ @media (--viewportMedium) { margin-top: 27px; - margin-bottom: 22px; + margin-bottom: 22px; /* Demo customization */ } @media (--viewportLarge) { @@ -330,10 +330,3 @@ margin: 0 48px; } } - -.stripeTestDataButton { - @apply --marketplaceSmallFontStyles; - width: 100%; - min-height: 40px; - margin-bottom: 16px; -} diff --git a/src/containers/CheckoutPage/CheckoutPageDemoChanges.module.css b/src/containers/CheckoutPage/CheckoutPageDemoChanges.module.css new file mode 100644 index 00000000..cc525e69 --- /dev/null +++ b/src/containers/CheckoutPage/CheckoutPageDemoChanges.module.css @@ -0,0 +1,8 @@ +@import '../../styles/propertySets.css'; + +.stripeTestDataButton { + @apply --marketplaceSmallFontStyles; + width: 100%; + min-height: 40px; + margin-bottom: 16px; +} diff --git a/src/containers/CheckoutPage/__snapshots__/CheckoutPage.test.js.snap b/src/containers/CheckoutPage/__snapshots__/CheckoutPage.test.js.snap index 8b2d2d3d..dd3e6a1f 100644 --- a/src/containers/CheckoutPage/__snapshots__/CheckoutPage.test.js.snap +++ b/src/containers/CheckoutPage/__snapshots__/CheckoutPage.test.js.snap @@ -98,21 +98,7 @@ exports[`CheckoutPage matches snapshot 1`] = `

- + { const [isSubmitting, setIsSubmitting] = useState(false); const [cardState, setCardState] = useState(null); + + // For demo: const [useDefaultTestData, setUseDefaultTestData] = useState(false); const { @@ -144,16 +147,27 @@ const PaymentMethodsPageComponent = props => { ? { name: userName } : { name: userName, ...config.stripe.testData.address }; - const handleInitialTestData = () => { - setUseDefaultTestData(true); - }; - const card = hasDefaultPaymentMethod ? ensurePaymentMethodCard(currentUser.stripeCustomer.defaultPaymentMethod).attributes.card : null; const showForm = cardState === 'replaceCard' || !hasDefaultPaymentMethod; const showCardDetails = !!hasDefaultPaymentMethod; + + // Demo customization begins + const handleInitialTestData = () => { + setUseDefaultTestData(true); + }; + + const FillDemoDataButton = () => + showForm ? ( + + ) : null; + + // Demo customization ends + return ( @@ -182,26 +196,23 @@ const PaymentMethodsPageComponent = props => { deletePaymentMethodInProgress={deletePaymentMethodInProgress} /> ) : null} + + {showForm ? ( - <> - - - + ) : null} )} diff --git a/src/containers/PaymentMethodsPage/PaymentMethodsPageDemoChanges.module.css b/src/containers/PaymentMethodsPage/PaymentMethodsPageDemoChanges.module.css new file mode 100644 index 00000000..cc525e69 --- /dev/null +++ b/src/containers/PaymentMethodsPage/PaymentMethodsPageDemoChanges.module.css @@ -0,0 +1,8 @@ +@import '../../styles/propertySets.css'; + +.stripeTestDataButton { + @apply --marketplaceSmallFontStyles; + width: 100%; + min-height: 40px; + margin-bottom: 16px; +} diff --git a/src/containers/StripePayoutPage/StripePayoutPage.js b/src/containers/StripePayoutPage/StripePayoutPage.js index 5aea98c9..a1bba508 100644 --- a/src/containers/StripePayoutPage/StripePayoutPage.js +++ b/src/containers/StripePayoutPage/StripePayoutPage.js @@ -31,6 +31,7 @@ import { TopbarContainer } from '..'; import { savePayoutDetails, loadData } from './StripePayoutPage.duck'; import css from './StripePayoutPage.module.css'; +import cssForDemo from './StripePayoutPageDemoChanges.module.css'; const STRIPE_ONBOARDING_RETURN_URL_SUCCESS = 'success'; const STRIPE_ONBOARDING_RETURN_URL_FAILURE = 'failure'; @@ -96,12 +97,9 @@ export const StripePayoutPageComponent = props => { intl, } = props; + // For demo: const [useDefaultTestData, setUseDefaultTestData] = useState(false); - const handleStripeTestData = () => { - setUseDefaultTestData(true); - }; - const stripeDefaultTestData = config.stripe.testData; const stripeInitialValues = useDefaultTestData ? { accountType: stripeDefaultTestData.accountType, country: stripeDefaultTestData.country } @@ -154,6 +152,21 @@ export const StripePayoutPageComponent = props => { handleGetStripeConnectAccountLink('custom_account_verification')(); } + // Demo customization begins + + const handleStripeTestData = () => { + setUseDefaultTestData(true); + }; + + const FillDemoDataButton = () => + currentUserLoaded && !stripeConnected ? ( + + ) : null; + + // Demo customization ends + return ( @@ -171,57 +184,53 @@ export const StripePayoutPageComponent = props => {

+ {!currentUserLoaded ? ( ) : returnedAbnormallyFromStripe && !getAccountLinkError ? ( ) : ( - <> - - - {stripeConnected && !returnedAbnormallyFromStripe && showVerificationNeeded ? ( - - ) : stripeConnected && savedCountry && !returnedAbnormallyFromStripe ? ( - - ) : null} - - + + {stripeConnected && !returnedAbnormallyFromStripe && showVerificationNeeded ? ( + + ) : stripeConnected && savedCountry && !returnedAbnormallyFromStripe ? ( + + ) : null} + )}
diff --git a/src/containers/StripePayoutPage/StripePayoutPage.module.css b/src/containers/StripePayoutPage/StripePayoutPage.module.css index 3d1bc22f..567ac1ef 100644 --- a/src/containers/StripePayoutPage/StripePayoutPage.module.css +++ b/src/containers/StripePayoutPage/StripePayoutPage.module.css @@ -1,5 +1,3 @@ -@import '../../styles/propertySets.css'; - .content { @media (--viewportMedium) { margin: 32px auto 0 auto; @@ -26,10 +24,3 @@ margin-bottom: 47px; } } - -.stripeTestDataButton { - @apply --marketplaceSmallFontStyles; - width: 100%; - min-height: 40px; - margin-top: 24px; -} diff --git a/src/containers/StripePayoutPage/StripePayoutPageDemoChanges.module.css b/src/containers/StripePayoutPage/StripePayoutPageDemoChanges.module.css new file mode 100644 index 00000000..8d0964ac --- /dev/null +++ b/src/containers/StripePayoutPage/StripePayoutPageDemoChanges.module.css @@ -0,0 +1,8 @@ +@import '../../styles/propertySets.css'; + +.stripeTestDataButton { + @apply --marketplaceSmallFontStyles; + width: 100%; + min-height: 40px; + margin-top: 24px; +} diff --git a/src/containers/StripePayoutPage/__snapshots__/StripePayoutPage.test.js.snap b/src/containers/StripePayoutPage/__snapshots__/StripePayoutPage.test.js.snap index 8cb7f594..e55300c8 100644 --- a/src/containers/StripePayoutPage/__snapshots__/StripePayoutPage.test.js.snap +++ b/src/containers/StripePayoutPage/__snapshots__/StripePayoutPage.test.js.snap @@ -43,21 +43,7 @@ exports[`StripePayoutPage matches snapshot with Stripe connected 1`] = ` values={Object {}} /> - + - + - + {billingDetailsNeeded && !loadingData ? ( diff --git a/src/stripe-config.js b/src/stripe-config.js index cc9c65d5..40153693 100644 --- a/src/stripe-config.js +++ b/src/stripe-config.js @@ -358,7 +358,7 @@ export const testData = { }, address: { addressLine1: 'Main Street 123', - postal: '00130', + postal: '00100', city: 'Helsinki', country: 'FI', },