From a84e8ae33e69f93644f05a4c81bd8b3b91e83e9a Mon Sep 17 00:00:00 2001 From: Jenni Nurmi Date: Wed, 5 Dec 2018 09:53:19 +0200 Subject: [PATCH 01/13] Refactor mapInputsToStripeAccountKeys function to make it easier to add different bank account formats --- .../StripeBankAccountTokenInputField.js | 11 +---- .../StripeBankAccountTokenInputField.util.js | 45 ++++++++++++++----- 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.js b/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.js index 3046759c..972b15b2 100644 --- a/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.js +++ b/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.js @@ -134,15 +134,8 @@ class TokenInputFieldComponent extends Component { }; // Include input values with correct stripe keys - inputsNeeded.forEach(inputType => { - // Stripe fails if there are spaces within the number, this is - // why we have to clean value up first. - const inputValueObj = mapInputsToStripeAccountKeys( - inputType, - cleanedString(values[inputType]) - ); - accountData = { ...accountData, ...inputValueObj }; - }); + const inputValueObj = mapInputsToStripeAccountKeys(country, inputsNeeded, values); + accountData = { ...accountData, ...inputValueObj }; // https://stripe.com/docs/stripe-js/reference#collecting-bank-account-details this.stripe diff --git a/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.util.js b/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.util.js index 1a20b72a..83277d0d 100644 --- a/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.util.js +++ b/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.util.js @@ -117,7 +117,7 @@ export const translateStripeError = (country, intl, stripeError) => { * * @return {Object} key - value in Object literal. */ -export const mapInputsToStripeAccountKeys = (inputType, value) => { +export const mapInputsToStripeAccountKeys = (country, inputsNeeded, values) => { // Stripe documentation speaks about actual bank account terms of different countries // (like BSB, sort code, routing number), but all of those get mapped to one of // the two different request keys: routing_number or account_number @@ -126,17 +126,42 @@ export const mapInputsToStripeAccountKeys = (inputType, value) => { // We use those country specific terms since we want to show correct labels and errors for users, // so this mapping is needed before sending data to Stripe. - switch (inputType) { - case IBAN: - case ACCOUNT_NUMBER: - return { account_number: value }; - case BSB: - case SORT_CODE: - case ROUTING_NUMBER: - return { routing_number: value }; + // Stripe fails if there are spaces within the number, this is + // why we have to clean value up first. + + switch (country) { + case 'AT': + case 'BE': + case 'DK': + case 'FI': + case 'FR': + case 'DE': + case 'IE': + case 'IT': + case 'LU': + case 'NL': + case 'PT': + case 'ES': + case 'SE': + return { account_number: cleanedString(values[IBAN]) }; + case 'AU': + return { + routing_number: cleanedString(values[BSB]), + account_number: cleanedString(values[ACCOUNT_NUMBER]), + }; + case 'GB': + return { + routing_number: cleanedString(values[SORT_CODE]), + account_number: cleanedString(values[ACCOUNT_NUMBER]), + }; + case 'US': + return { + routing_number: cleanedString(values[ROUTING_NUMBER]), + account_number: cleanedString(values[ACCOUNT_NUMBER]), + }; default: - throw new Error(`Unknown inputType (${inputType}) given to validator`); + throw new Error(`Not supported country (${country}) given to validator`); } }; From 89c62999be8fe69c0d3ea4408a18c291764cc343 Mon Sep 17 00:00:00 2001 From: Jenni Nurmi Date: Wed, 5 Dec 2018 10:55:15 +0200 Subject: [PATCH 02/13] Create PayoutDetailsAddress subcomponent and edit address config --- .../StripeBankAccountTokenInputField.js | 2 +- src/config.js | 98 +++++++++++-- src/ducks/user.duck.js | 1 + .../PayoutDetailsForm/PayoutDetailsAddress.js | 137 ++++++++++++++++++ .../PayoutDetailsForm/PayoutDetailsForm.js | 82 +---------- src/translations/en.json | 3 + 6 files changed, 227 insertions(+), 96 deletions(-) create mode 100644 src/forms/PayoutDetailsForm/PayoutDetailsAddress.js diff --git a/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.js b/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.js index 972b15b2..93eff0ff 100644 --- a/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.js +++ b/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.js @@ -134,7 +134,7 @@ class TokenInputFieldComponent extends Component { }; // Include input values with correct stripe keys - const inputValueObj = mapInputsToStripeAccountKeys(country, inputsNeeded, values); + const inputValueObj = mapInputsToStripeAccountKeys(country, values); accountData = { ...accountData, ...inputValueObj }; // https://stripe.com/docs/stripe-js/reference#collecting-bank-account-details diff --git a/src/config.js b/src/config.js index 725b72da..e224fdc4 100644 --- a/src/config.js +++ b/src/config.js @@ -90,7 +90,12 @@ const stripeSupportedCountries = [ // Australia code: 'AU', currency: 'AUD', - payoutAddressRequired: false, + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + state: true, + }, accountConfig: { bsb: true, accountNumber: true, @@ -100,7 +105,11 @@ const stripeSupportedCountries = [ // Austria code: 'AT', currency: 'EUR', - payoutAddressRequired: true, + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + }, accountConfig: { iban: true, }, @@ -109,7 +118,11 @@ const stripeSupportedCountries = [ // Belgium code: 'BE', currency: 'EUR', - payoutAddressRequired: true, + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + }, accountConfig: { iban: true, }, @@ -118,7 +131,11 @@ const stripeSupportedCountries = [ // Denmark code: 'DK', currency: 'DKK', - payoutAddressRequired: true, + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + }, accountConfig: { iban: true, }, @@ -127,7 +144,11 @@ const stripeSupportedCountries = [ // Finland code: 'FI', currency: 'EUR', - payoutAddressRequired: true, + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + }, accountConfig: { iban: true, }, @@ -136,7 +157,11 @@ const stripeSupportedCountries = [ // France code: 'FR', currency: 'EUR', - payoutAddressRequired: true, + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + }, accountConfig: { iban: true, }, @@ -145,7 +170,11 @@ const stripeSupportedCountries = [ // Germany code: 'DE', currency: 'EUR', - payoutAddressRequired: true, + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + }, accountConfig: { iban: true, }, @@ -154,7 +183,11 @@ const stripeSupportedCountries = [ // Ireland code: 'IE', currency: 'EUR', - payoutAddressRequired: true, + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + }, accountConfig: { iban: true, }, @@ -163,7 +196,11 @@ const stripeSupportedCountries = [ // Italy code: 'IT', currency: 'EUR', - payoutAddressRequired: true, + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + }, accountConfig: { iban: true, }, @@ -172,7 +209,11 @@ const stripeSupportedCountries = [ // Luxembourg code: 'LU', currency: 'EUR', - payoutAddressRequired: true, + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + }, accountConfig: { iban: true, }, @@ -181,7 +222,11 @@ const stripeSupportedCountries = [ // Netherlands code: 'NL', currency: 'EUR', - payoutAddressRequired: true, + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + }, accountConfig: { iban: true, }, @@ -190,7 +235,11 @@ const stripeSupportedCountries = [ // Portugal code: 'PT', currency: 'EUR', - payoutAddressRequired: true, + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + }, accountConfig: { iban: true, }, @@ -199,7 +248,11 @@ const stripeSupportedCountries = [ // Spain code: 'ES', currency: 'EUR', - payoutAddressRequired: true, + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + }, accountConfig: { iban: true, }, @@ -208,7 +261,11 @@ const stripeSupportedCountries = [ // Sweden code: 'SE', currency: 'SEK', - payoutAddressRequired: true, + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + }, accountConfig: { iban: true, }, @@ -217,7 +274,11 @@ const stripeSupportedCountries = [ // United Kingdom code: 'GB', currency: 'GBP', - payoutAddressRequired: true, + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + }, accountConfig: { sortCode: true, accountNumber: true, @@ -227,7 +288,12 @@ const stripeSupportedCountries = [ // United States code: 'US', currency: 'USD', - payoutAddressRequired: false, + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + state: true, + }, accountConfig: { routingNumber: true, accountNumber: true, diff --git a/src/ducks/user.duck.js b/src/ducks/user.duck.js index 7dbe3691..ec765155 100644 --- a/src/ducks/user.duck.js +++ b/src/ducks/user.duck.js @@ -397,6 +397,7 @@ export const createStripeAccount = payoutDetails => (dispatch, getState, sdk) => streetAddress, postalCode, city, + state, bankAccountToken, } = payoutDetails; diff --git a/src/forms/PayoutDetailsForm/PayoutDetailsAddress.js b/src/forms/PayoutDetailsForm/PayoutDetailsAddress.js new file mode 100644 index 00000000..b0990d08 --- /dev/null +++ b/src/forms/PayoutDetailsForm/PayoutDetailsAddress.js @@ -0,0 +1,137 @@ +import React from 'react'; +import { bool, object, string } from 'prop-types'; +import { FieldTextInput } from '../../components'; +import * as validators from '../../util/validators'; + +import { stripeCountryConfigs } from './PayoutDetailsForm'; +import css from './PayoutDetailsForm.css'; + +const PayoutDetailsAddress = props => { + const { country, intl, disabled, form } = props; + const countryConfig = country ? stripeCountryConfigs(country).addressConfig : null; + + const isRequired = (countryConfig, field) => { + return countryConfig[field]; + }; + + const showAddressLine = country && isRequired(countryConfig, 'addressLine'); + + const streetAddressLabel = intl.formatMessage({ + id: 'PayoutDetailsForm.streetAddressLabel', + }); + const streetAddressPlaceholder = intl.formatMessage({ + id: 'PayoutDetailsForm.streetAddressPlaceholder', + }); + const streetAddressRequired = validators.required( + intl.formatMessage({ + id: 'PayoutDetailsForm.streetAddressRequired', + }) + ); + + const showPostalCode = country && isRequired(countryConfig, 'postalCode'); + + const postalCodeLabel = intl.formatMessage({ id: 'PayoutDetailsForm.postalCodeLabel' }); + const postalCodePlaceholder = intl.formatMessage({ + id: 'PayoutDetailsForm.postalCodePlaceholder', + }); + const postalCodeRequired = validators.required( + intl.formatMessage({ + id: 'PayoutDetailsForm.postalCodeRequired', + }) + ); + + const showCity = country && isRequired(countryConfig, 'city'); + + const cityLabel = intl.formatMessage({ id: 'PayoutDetailsForm.cityLabel' }); + const cityPlaceholder = intl.formatMessage({ id: 'PayoutDetailsForm.cityPlaceholder' }); + const cityRequired = validators.required( + intl.formatMessage({ + id: 'PayoutDetailsForm.cityRequired', + }) + ); + + const showState = country && isRequired(countryConfig, 'state'); + + const stateLabel = intl.formatMessage({ id: 'PayoutDetailsForm.stateLabel' }); + const statePlaceholder = intl.formatMessage({ id: 'PayoutDetailsForm.statePlaceholder' }); + const stateRequired = validators.required( + intl.formatMessage({ + id: 'PayoutDetailsForm.stateRequired', + }) + ); + + return ( +
+ {showAddressLine ? ( + form.change('streetAddress', undefined)} + /> + ) : null} +
+ {showPostalCode ? ( + form.change('postalCode', undefined)} + /> + ) : null} + {showCity ? ( + form.change('city', undefined)} + /> + ) : null} +
+ {showState ? ( + form.change('state', undefined)} + /> + ) : null} +
+ ); +}; +PayoutDetailsAddress.defaultProps = { + country: null, + disabled: false, +}; + +PayoutDetailsAddress.propTypes = { + country: string, + disabled: bool, + form: object.isRequired, +}; + +export default PayoutDetailsAddress; diff --git a/src/forms/PayoutDetailsForm/PayoutDetailsForm.js b/src/forms/PayoutDetailsForm/PayoutDetailsForm.js index d379172e..ade74134 100644 --- a/src/forms/PayoutDetailsForm/PayoutDetailsForm.js +++ b/src/forms/PayoutDetailsForm/PayoutDetailsForm.js @@ -17,6 +17,7 @@ import { import * as validators from '../../util/validators'; import { isStripeInvalidPostalCode } from '../../util/errors'; +import PayoutDetailsAddress from './PayoutDetailsAddress'; import css from './PayoutDetailsForm.css'; const MIN_STRIPE_ACCOUNT_AGE = 18; @@ -32,11 +33,6 @@ export const stripeCountryConfigs = countryCode => { return country; }; -const requiresAddress = countryCode => { - const country = stripeCountryConfigs(countryCode); - return country.payoutAddressRequired; -}; - const countryCurrency = countryCode => { const country = stripeCountryConfigs(countryCode); return country.currency; @@ -114,38 +110,6 @@ const PayoutDetailsFormComponent = props => ( }) ); - const streetAddressLabel = intl.formatMessage({ - id: 'PayoutDetailsForm.streetAddressLabel', - }); - const streetAddressPlaceholder = intl.formatMessage({ - id: 'PayoutDetailsForm.streetAddressPlaceholder', - }); - const streetAddressRequired = validators.required( - intl.formatMessage({ - id: 'PayoutDetailsForm.streetAddressRequired', - }) - ); - - const postalCodeLabel = intl.formatMessage({ id: 'PayoutDetailsForm.postalCodeLabel' }); - const postalCodePlaceholder = intl.formatMessage({ - id: 'PayoutDetailsForm.postalCodePlaceholder', - }); - const postalCodeRequired = validators.required( - intl.formatMessage({ - id: 'PayoutDetailsForm.postalCodeRequired', - }) - ); - - const cityLabel = intl.formatMessage({ id: 'PayoutDetailsForm.cityLabel' }); - const cityPlaceholder = intl.formatMessage({ id: 'PayoutDetailsForm.cityPlaceholder' }); - const cityRequired = validators.required( - intl.formatMessage({ - id: 'PayoutDetailsForm.cityRequired', - }) - ); - - const showAddressFields = country && requiresAddress(country); - // StripeBankAccountTokenInputField handles the error messages // internally, we just have to make sure we require a valid token // out of the field. Therefore the empty validation message. @@ -245,48 +209,8 @@ const PayoutDetailsFormComponent = props => ( ))} - {showAddressFields ? ( -
- form.change('streetAddress', undefined)} - /> -
- form.change('postalCode', undefined)} - /> - form.change('city', undefined)} - /> -
-
- ) : null} + + {country ? (
diff --git a/src/translations/en.json b/src/translations/en.json index 8c0c1bce..9c5d2780 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -480,6 +480,9 @@ "PayoutDetailsForm.postalCodeLabel": "Postal code", "PayoutDetailsForm.postalCodePlaceholder": "00100", "PayoutDetailsForm.postalCodeRequired": "This field is required", + "PayoutDetailsForm.stateLabel": "State", + "PayoutDetailsForm.statePlaceholder": "Enter your state", + "PayoutDetailsForm.stateRequired": "This field is required", "PayoutDetailsForm.streetAddressLabel": "Street address", "PayoutDetailsForm.streetAddressPlaceholder": "Enter your street address…", "PayoutDetailsForm.streetAddressRequired": "This field is required", From fe1082e5e5dcc796563bea9bd4ca39519a1bbe5a Mon Sep 17 00:00:00 2001 From: Jenni Nurmi Date: Wed, 5 Dec 2018 16:43:00 +0200 Subject: [PATCH 03/13] Add field for personal id number to PayoutDetailsForm --- src/ducks/user.duck.js | 2 + .../PayoutDetailsForm/PayoutDetailsForm.js | 42 ++++++++++++++++++- src/translations/en.json | 2 + 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/ducks/user.duck.js b/src/ducks/user.duck.js index ec765155..48ecc506 100644 --- a/src/ducks/user.duck.js +++ b/src/ducks/user.duck.js @@ -399,6 +399,7 @@ export const createStripeAccount = payoutDetails => (dispatch, getState, sdk) => city, state, bankAccountToken, + personalIdNumber, } = payoutDetails; const address = { @@ -415,6 +416,7 @@ export const createStripeAccount = payoutDetails => (dispatch, getState, sdk) => address: omitBy(address, isUndefined), dob: birthDate, type: 'individual', + personal_id_number: personalIdNumber, }, tos_shown_and_accepted: true, }; diff --git a/src/forms/PayoutDetailsForm/PayoutDetailsForm.js b/src/forms/PayoutDetailsForm/PayoutDetailsForm.js index ade74134..eb163bcc 100644 --- a/src/forms/PayoutDetailsForm/PayoutDetailsForm.js +++ b/src/forms/PayoutDetailsForm/PayoutDetailsForm.js @@ -115,6 +115,27 @@ const PayoutDetailsFormComponent = props => ( // out of the field. Therefore the empty validation message. const bankAccountRequired = validators.required(' '); + const showPersonalIdNumber = + country && stripeCountryConfigs(country).personalIdNumberRequired; + + const personalIdNumberLabel = showPersonalIdNumber + ? intl.formatMessage({ + id: `PayoutDetailsForm.personalIdNumberLabel.${country}`, + }) + : null; + const personalIdNumberPlaceholder = showPersonalIdNumber + ? intl.formatMessage({ + id: `PayoutDetailsForm.personalIdNumberPlaceholder.${country}`, + }) + : null; + const personalIdNumberRequired = showPersonalIdNumber + ? validators.required( + intl.formatMessage({ + id: `PayoutDetailsForm.personalIdNumberRequired`, + }) + ) + : null; + const classes = classNames(css.root, className, { [css.disabled]: disabled, }); @@ -142,7 +163,6 @@ const PayoutDetailsFormComponent = props => ( ); - return (
@@ -227,7 +247,27 @@ const PayoutDetailsFormComponent = props => ( />
) : null} + + {showPersonalIdNumber ? ( +
+

+ +

+ +
+ ) : null} + {error} +

Date: Wed, 5 Dec 2018 13:59:17 +0200 Subject: [PATCH 04/13] Add Stripe support for Canada --- ...tripeBankAccountTokenInputField.example.js | 17 +++++++ .../StripeBankAccountTokenInputField.util.js | 23 ++++++++- src/config.js | 16 ++++++ src/ducks/user.duck.js | 4 ++ .../PayoutDetailsForm/PayoutDetailsAddress.js | 51 ++++++++++++++++++- src/translations/en.json | 28 ++++++++++ 6 files changed, 136 insertions(+), 3 deletions(-) diff --git a/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.example.js b/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.example.js index f0b95162..c791f073 100644 --- a/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.example.js +++ b/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.example.js @@ -104,3 +104,20 @@ export const AU_AUD = { }, group: 'custom inputs', }; + +// CA +export const CA_CAD = { + component: formComponent('CA'), + props: { + formName: 'CA_CAD', + onChange: formState => { + if (formState.dirty) { + console.log('form values changed to:', formState.values); + } + }, + onSubmit: values => { + console.log('values submitted:', values); + }, + }, + group: 'custom inputs', +}; diff --git a/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.util.js b/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.util.js index 83277d0d..60b6d645 100644 --- a/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.util.js +++ b/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.util.js @@ -6,6 +6,10 @@ import config from '../../config'; export const ACCOUNT_NUMBER = 'accountNumber'; // Australian equivalent for routing number export const BSB = 'bsb'; +// Needed for creating full routing number in Canada +export const INSTITUTION_NUMBER = 'institutionNumber'; +// Needed for creating full routing number in Canada +export const TRANSIT_NUMBER = 'transitNumber'; // International bank account number (e.g. EU countries use this) export const IBAN = 'iban'; // Routing number to separate bank account in different areas @@ -15,7 +19,15 @@ export const SORT_CODE = 'sortCode'; // Currently supported bank account inputs // the order here matters: account number input is asked after routing number and its equivalents -export const BANK_ACCOUNT_INPUTS = [BSB, SORT_CODE, ROUTING_NUMBER, ACCOUNT_NUMBER, IBAN]; +export const BANK_ACCOUNT_INPUTS = [ + BSB, + TRANSIT_NUMBER, + INSTITUTION_NUMBER, + SORT_CODE, + ROUTING_NUMBER, + ACCOUNT_NUMBER, + IBAN, +]; export const supportedCountries = config.stripe.supportedCountries.map(c => c.code); @@ -117,7 +129,7 @@ export const translateStripeError = (country, intl, stripeError) => { * * @return {Object} key - value in Object literal. */ -export const mapInputsToStripeAccountKeys = (country, inputsNeeded, values) => { +export const mapInputsToStripeAccountKeys = (country, values) => { // Stripe documentation speaks about actual bank account terms of different countries // (like BSB, sort code, routing number), but all of those get mapped to one of // the two different request keys: routing_number or account_number @@ -149,6 +161,13 @@ export const mapInputsToStripeAccountKeys = (country, inputsNeeded, values) => { routing_number: cleanedString(values[BSB]), account_number: cleanedString(values[ACCOUNT_NUMBER]), }; + case 'CA': + return { + routing_number: cleanedString(values[TRANSIT_NUMBER]).concat( + cleanedString(values[INSTITUTION_NUMBER]) + ), + account_number: cleanedString(values[ACCOUNT_NUMBER]), + }; case 'GB': return { routing_number: cleanedString(values[SORT_CODE]), diff --git a/src/config.js b/src/config.js index e224fdc4..133971d5 100644 --- a/src/config.js +++ b/src/config.js @@ -127,6 +127,22 @@ const stripeSupportedCountries = [ iban: true, }, }, + { + // Canada + code: 'CA', + currency: 'CAD', + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + province: true, + }, + accountConfig: { + transitNumber: true, + institutionNumber: true, + accountNumber: true, + }, + }, { // Denmark code: 'DK', diff --git a/src/ducks/user.duck.js b/src/ducks/user.duck.js index 48ecc506..b33b9eeb 100644 --- a/src/ducks/user.duck.js +++ b/src/ducks/user.duck.js @@ -398,14 +398,18 @@ export const createStripeAccount = payoutDetails => (dispatch, getState, sdk) => postalCode, city, state, + province, bankAccountToken, personalIdNumber, } = payoutDetails; + const hasProvince = province && !state; + const address = { city, line1: streetAddress, postal_code: postalCode, + state: hasProvince ? province : state, }; // Params for Stripe SDK diff --git a/src/forms/PayoutDetailsForm/PayoutDetailsAddress.js b/src/forms/PayoutDetailsForm/PayoutDetailsAddress.js index b0990d08..0e9ed0e1 100644 --- a/src/forms/PayoutDetailsForm/PayoutDetailsAddress.js +++ b/src/forms/PayoutDetailsForm/PayoutDetailsAddress.js @@ -1,11 +1,27 @@ import React from 'react'; import { bool, object, string } from 'prop-types'; -import { FieldTextInput } from '../../components'; +import { FieldSelect, FieldTextInput } from '../../components'; import * as validators from '../../util/validators'; import { stripeCountryConfigs } from './PayoutDetailsForm'; import css from './PayoutDetailsForm.css'; +const CANADIAN_PROVINCES = [ + 'AB', + 'BC', + 'MB', + 'NB', + 'NL', + 'NS', + 'NT', + 'NU', + 'ON', + 'PE', + 'QC', + 'SK', + 'YT', +]; + const PayoutDetailsAddress = props => { const { country, intl, disabled, form } = props; const countryConfig = country ? stripeCountryConfigs(country).addressConfig : null; @@ -60,6 +76,18 @@ const PayoutDetailsAddress = props => { }) ); + const showProvince = country && isRequired(countryConfig, 'province'); + + const provinceLabel = intl.formatMessage({ id: 'PayoutDetailsForm.canadianProvinceLabel' }); + const provincePlaceholder = intl.formatMessage({ + id: 'PayoutDetailsForm.canadianProvincePlaceholder', + }); + const provinceRequired = validators.required( + intl.formatMessage({ + id: 'PayoutDetailsForm.canadianProvinceRequired', + }) + ); + return (

{showAddressLine ? ( @@ -120,6 +148,27 @@ const PayoutDetailsAddress = props => { onUnmount={() => form.change('state', undefined)} /> ) : null} + + {showProvince ? ( + + + {CANADIAN_PROVINCES.map(p => ( + + ))} + + ) : null}
); }; diff --git a/src/translations/en.json b/src/translations/en.json index 7de039a6..9de33dc9 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -445,6 +445,22 @@ "PayoutDetailsForm.birthdayMonthPlaceholder": "mm", "PayoutDetailsForm.birthdayRequired": "Birthday is required and must be a valid date.", "PayoutDetailsForm.birthdayYearPlaceholder": "yyyy", + "PayoutDetailsForm.canadianProvinceLabel": "Province", + "PayoutDetailsForm.canadianProvinceNames.AB": "Alberta", + "PayoutDetailsForm.canadianProvinceNames.BC": "British Columbia", + "PayoutDetailsForm.canadianProvinceNames.MB": "Manitoba", + "PayoutDetailsForm.canadianProvinceNames.NB": "New Brunswick", + "PayoutDetailsForm.canadianProvinceNames.NL": "Newfoundland and Labrador", + "PayoutDetailsForm.canadianProvinceNames.NS": "Nova Scotia", + "PayoutDetailsForm.canadianProvinceNames.NT": "Northwest Territories", + "PayoutDetailsForm.canadianProvinceNames.NU": "Nunavut", + "PayoutDetailsForm.canadianProvinceNames.ON": "Ontario", + "PayoutDetailsForm.canadianProvinceNames.PE": "Prince Edward Island", + "PayoutDetailsForm.canadianProvinceNames.QC": "Quebec", + "PayoutDetailsForm.canadianProvinceNames.SK": "Saskatchewan", + "PayoutDetailsForm.canadianProvinceNames.YT": "Yukon", + "PayoutDetailsForm.canadianProvincePlaceholder": "Province", + "PayoutDetailsForm.canadianProvinceRequired": "This field is required", "PayoutDetailsForm.cityLabel": "City", "PayoutDetailsForm.cityPlaceholder": "Helsinki", "PayoutDetailsForm.cityRequired": "This field is required", @@ -452,6 +468,7 @@ "PayoutDetailsForm.countryNames.AT": "Austria", "PayoutDetailsForm.countryNames.AU": "Australia", "PayoutDetailsForm.countryNames.BE": "Belgium", + "PayoutDetailsForm.countryNames.CA": "Canada", "PayoutDetailsForm.countryNames.DE": "Germany", "PayoutDetailsForm.countryNames.DK": "Denmark", "PayoutDetailsForm.countryNames.ES": "Spain", @@ -478,6 +495,9 @@ "PayoutDetailsForm.lastNameRequired": "This field is required", "PayoutDetailsForm.personalDetailsTitle": "Personal details", "PayoutDetailsForm.personalIdNumberTitle": "Personal id number", + "PayoutDetailsForm.personalIdNumberLabel.HK": "Hong Kong Identity Card Number (HKID)", + "PayoutDetailsForm.personalIdNumberLabel.US": "Last 4 digits of social security number (SSN)", + "PayoutDetailsForm.personalIdNumberPlaceholder.HK": "XY123456", "PayoutDetailsForm.personalIdNumberRequired": "This field is required", "PayoutDetailsForm.postalCodeLabel": "Postal code", "PayoutDetailsForm.postalCodePlaceholder": "00100", @@ -644,6 +664,10 @@ "StripeBankAccountTokenInputField.iban.label": "Bank account number (IBAN)", "StripeBankAccountTokenInputField.iban.placeholder": "DE89 3704 0044 0532 0130 00", "StripeBankAccountTokenInputField.iban.required": "Bank account number (IBAN) is required", + "StripeBankAccountTokenInputField.institutionNumber.inline": "institution number", + "StripeBankAccountTokenInputField.institutionNumber.label": "Institution number", + "StripeBankAccountTokenInputField.institutionNumber.placeholder": "Type in institution number", + "StripeBankAccountTokenInputField.institutionNumber.required": "Institution number is required", "StripeBankAccountTokenInputField.routingNumber.inline": "routing number", "StripeBankAccountTokenInputField.routingNumber.label": "Routing number", "StripeBankAccountTokenInputField.routingNumber.placeholder": "Type in routing number…", @@ -653,6 +677,10 @@ "StripeBankAccountTokenInputField.sortCode.placeholder": "Type in sort code…", "StripeBankAccountTokenInputField.sortCode.required": "Sort code is required", "StripeBankAccountTokenInputField.unsupportedCountry": "Country not supported: {country}", + "StripeBankAccountTokenInputField.transitNumber.inline": "transit number", + "StripeBankAccountTokenInputField.transitNumber.label": "Transit number", + "StripeBankAccountTokenInputField.transitNumber.placeholder": "Type in transit number", + "StripeBankAccountTokenInputField.transitNumber.required": "Transit number is required", "StripePaymentForm.creditCardDetails": "Credit card details", "StripePaymentForm.genericError": "Could not handle payment data. Please try again.", "StripePaymentForm.messageHeading": "Message", From c79fb7e14104fb76a503a7779bbb3755fa53581c Mon Sep 17 00:00:00 2001 From: Jenni Nurmi Date: Wed, 5 Dec 2018 14:45:35 +0200 Subject: [PATCH 05/13] Add Stripe support for New Zealand --- .../StripeBankAccountTokenInputField.util.js | 4 ++++ src/config.js | 13 +++++++++++++ src/translations/en.json | 1 + 3 files changed, 18 insertions(+) diff --git a/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.util.js b/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.util.js index 60b6d645..53cebfc7 100644 --- a/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.util.js +++ b/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.util.js @@ -156,6 +156,10 @@ export const mapInputsToStripeAccountKeys = (country, values) => { case 'ES': case 'SE': return { account_number: cleanedString(values[IBAN]) }; + case 'NZ': + // NZ account number is typically presented in the format xx-xxxx-xxxxxxx-xxx + // '-' separators must be removed before sending value to Stripe API + return { account_number: cleanedString(values[ACCOUNT_NUMBER]).replace(/-/g, '') }; case 'AU': return { routing_number: cleanedString(values[BSB]), diff --git a/src/config.js b/src/config.js index 133971d5..59af03ff 100644 --- a/src/config.js +++ b/src/config.js @@ -247,6 +247,19 @@ const stripeSupportedCountries = [ iban: true, }, }, + { + // New Zealand + code: 'NZ', + currency: 'NZD', + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + }, + accountConfig: { + accountNumber: true, + }, + }, { // Portugal code: 'PT', diff --git a/src/translations/en.json b/src/translations/en.json index 9de33dc9..09695bc0 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -479,6 +479,7 @@ "PayoutDetailsForm.countryNames.IT": "Italy", "PayoutDetailsForm.countryNames.LU": "Luxembourg", "PayoutDetailsForm.countryNames.NL": "Netherlands", + "PayoutDetailsForm.countryNames.NZ": "New Zealand", "PayoutDetailsForm.countryNames.PT": "Portugal", "PayoutDetailsForm.countryNames.SE": "Sweden", "PayoutDetailsForm.countryNames.US": "United States", From d98d5d8f6237f755b29fc38db9d5e97b450e07e4 Mon Sep 17 00:00:00 2001 From: Jenni Nurmi Date: Wed, 5 Dec 2018 14:58:37 +0200 Subject: [PATCH 06/13] Add Stripe support for Switzerland --- .../StripeBankAccountTokenInputField.util.js | 1 + src/config.js | 13 +++++++++++++ src/translations/en.json | 1 + 3 files changed, 15 insertions(+) diff --git a/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.util.js b/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.util.js index 53cebfc7..f21be45d 100644 --- a/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.util.js +++ b/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.util.js @@ -155,6 +155,7 @@ export const mapInputsToStripeAccountKeys = (country, values) => { case 'PT': case 'ES': case 'SE': + case 'CH': return { account_number: cleanedString(values[IBAN]) }; case 'NZ': // NZ account number is typically presented in the format xx-xxxx-xxxxxxx-xxx diff --git a/src/config.js b/src/config.js index 59af03ff..5614b3fb 100644 --- a/src/config.js +++ b/src/config.js @@ -299,6 +299,19 @@ const stripeSupportedCountries = [ iban: true, }, }, + { + // Switzerland + code: 'CH', + currency: 'CHF', + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + }, + accountConfig: { + iban: true, + }, + }, { // United Kingdom code: 'GB', diff --git a/src/translations/en.json b/src/translations/en.json index 09695bc0..ab9ffb0d 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -469,6 +469,7 @@ "PayoutDetailsForm.countryNames.AU": "Australia", "PayoutDetailsForm.countryNames.BE": "Belgium", "PayoutDetailsForm.countryNames.CA": "Canada", + "PayoutDetailsForm.countryNames.CH": "Switzerland", "PayoutDetailsForm.countryNames.DE": "Germany", "PayoutDetailsForm.countryNames.DK": "Denmark", "PayoutDetailsForm.countryNames.ES": "Spain", From fe0102034a406d05af4925c7d1ae903899d78c36 Mon Sep 17 00:00:00 2001 From: Jenni Nurmi Date: Wed, 5 Dec 2018 15:08:19 +0200 Subject: [PATCH 07/13] Add Stripe support for Norway --- .../StripeBankAccountTokenInputField.util.js | 1 + src/config.js | 13 +++++++++++++ src/translations/en.json | 1 + 3 files changed, 15 insertions(+) diff --git a/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.util.js b/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.util.js index f21be45d..7618432f 100644 --- a/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.util.js +++ b/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.util.js @@ -156,6 +156,7 @@ export const mapInputsToStripeAccountKeys = (country, values) => { case 'ES': case 'SE': case 'CH': + case 'NO': return { account_number: cleanedString(values[IBAN]) }; case 'NZ': // NZ account number is typically presented in the format xx-xxxx-xxxxxxx-xxx diff --git a/src/config.js b/src/config.js index 5614b3fb..e835d63f 100644 --- a/src/config.js +++ b/src/config.js @@ -260,6 +260,19 @@ const stripeSupportedCountries = [ accountNumber: true, }, }, + { + // Norway + code: 'NO', + currency: 'EUR', + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + }, + accountConfig: { + iban: true, + }, + }, { // Portugal code: 'PT', diff --git a/src/translations/en.json b/src/translations/en.json index ab9ffb0d..ef6f21ac 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -481,6 +481,7 @@ "PayoutDetailsForm.countryNames.LU": "Luxembourg", "PayoutDetailsForm.countryNames.NL": "Netherlands", "PayoutDetailsForm.countryNames.NZ": "New Zealand", + "PayoutDetailsForm.countryNames.NO": "Norway", "PayoutDetailsForm.countryNames.PT": "Portugal", "PayoutDetailsForm.countryNames.SE": "Sweden", "PayoutDetailsForm.countryNames.US": "United States", From a137773b8202ade6a7cf0b38e51118f2033cc5f0 Mon Sep 17 00:00:00 2001 From: Jenni Nurmi Date: Fri, 7 Dec 2018 09:07:26 +0200 Subject: [PATCH 08/13] Add Stripe support for Hong Kong --- .../StripeBankAccountTokenInputField.util.js | 14 ++++++++++++++ src/config.js | 15 +++++++++++++++ src/translations/en.json | 9 +++++++++ 3 files changed, 38 insertions(+) diff --git a/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.util.js b/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.util.js index 7618432f..c095265f 100644 --- a/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.util.js +++ b/src/components/StripeBankAccountTokenInputField/StripeBankAccountTokenInputField.util.js @@ -10,6 +10,10 @@ export const BSB = 'bsb'; export const INSTITUTION_NUMBER = 'institutionNumber'; // Needed for creating full routing number in Canada export const TRANSIT_NUMBER = 'transitNumber'; +// Needed for creating full routing number in Hong Kong +export const CLEARING_CODE = 'clearingCode'; +// Needed for creating full routing number in Hong Kong +export const BRANCH_CODE = 'branchCode'; // International bank account number (e.g. EU countries use this) export const IBAN = 'iban'; // Routing number to separate bank account in different areas @@ -23,6 +27,8 @@ export const BANK_ACCOUNT_INPUTS = [ BSB, TRANSIT_NUMBER, INSTITUTION_NUMBER, + CLEARING_CODE, + BRANCH_CODE, SORT_CODE, ROUTING_NUMBER, ACCOUNT_NUMBER, @@ -184,6 +190,14 @@ export const mapInputsToStripeAccountKeys = (country, values) => { routing_number: cleanedString(values[ROUTING_NUMBER]), account_number: cleanedString(values[ACCOUNT_NUMBER]), }; + case 'HK': + return { + routing_number: cleanedString(values[CLEARING_CODE]).concat( + '-', + cleanedString(values[BRANCH_CODE]) + ), + account_number: cleanedString(values[ACCOUNT_NUMBER]), + }; default: throw new Error(`Not supported country (${country}) given to validator`); diff --git a/src/config.js b/src/config.js index e835d63f..32b8401e 100644 --- a/src/config.js +++ b/src/config.js @@ -195,6 +195,21 @@ const stripeSupportedCountries = [ iban: true, }, }, + { + // Hong Kong + code: 'HK', + currency: 'HKD', + addressConfig: { + addressLine: true, + city: true, + }, + accountConfig: { + clearingCode: true, + branchCode: true, + accountNumber: true, + }, + personalIdNumberRequired: true, + }, { // Ireland code: 'IE', diff --git a/src/translations/en.json b/src/translations/en.json index ef6f21ac..519e548f 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -476,6 +476,7 @@ "PayoutDetailsForm.countryNames.FI": "Finland", "PayoutDetailsForm.countryNames.FR": "France", "PayoutDetailsForm.countryNames.GB": "United Kingdom", + "PayoutDetailsForm.countryNames.HK": "Hong Kong", "PayoutDetailsForm.countryNames.IE": "Ireland", "PayoutDetailsForm.countryNames.IT": "Italy", "PayoutDetailsForm.countryNames.LU": "Luxembourg", @@ -657,10 +658,18 @@ "StripeBankAccountTokenInputField.accountNumber.placeholder": "Type in bank account number…", "StripeBankAccountTokenInputField.accountNumber.required": "Bank account number is required", "StripeBankAccountTokenInputField.andBeforeLastItemInAList": " and", + "StripeBankAccountTokenInputField.branchCode.inline": "Branch code", + "StripeBankAccountTokenInputField.branchCode.label": "Branch code", + "StripeBankAccountTokenInputField.branchCode.placeholder": "Type in branch code…", + "StripeBankAccountTokenInputField.branchCode.required": "Branch code is required", "StripeBankAccountTokenInputField.bsb.inline": "BSB", "StripeBankAccountTokenInputField.bsb.label": "BSB", "StripeBankAccountTokenInputField.bsb.placeholder": "Type in BSB…", "StripeBankAccountTokenInputField.bsb.required": "BSB is required", + "StripeBankAccountTokenInputField.clearingCode.inline": "Clearing code", + "StripeBankAccountTokenInputField.clearingCode.label": "Clearing code", + "StripeBankAccountTokenInputField.clearingCode.placeholder": "Type in clearing code…", + "StripeBankAccountTokenInputField.clearingCode.required": "Clearing code is required", "StripeBankAccountTokenInputField.genericStripeError": "Could not connect account number. Please double-check that your {inputs} are valid in {country}", "StripeBankAccountTokenInputField.genericStripeErrorIban": "Could not connect account number. Please double-check that your account number is valid in {country}", "StripeBankAccountTokenInputField.iban.inline": "IBAN", From 0cc6cf9663a7095bb2caad50ffff45e81f148c90 Mon Sep 17 00:00:00 2001 From: Jenni Nurmi Date: Mon, 10 Dec 2018 11:27:43 +0200 Subject: [PATCH 09/13] Add ID number field with validators to US and HK --- src/ducks/user.duck.js | 5 +- .../PayoutDetailsForm/PayoutDetailsForm.js | 56 +++++++++++----- src/translations/en.json | 1 + src/util/validators.js | 64 +++++++++++++++++++ 4 files changed, 108 insertions(+), 18 deletions(-) diff --git a/src/ducks/user.duck.js b/src/ducks/user.duck.js index b33b9eeb..2f110e82 100644 --- a/src/ducks/user.duck.js +++ b/src/ducks/user.duck.js @@ -412,6 +412,9 @@ export const createStripeAccount = payoutDetails => (dispatch, getState, sdk) => state: hasProvince ? province : state, }; + const idNumber = + country === 'US' ? { ssn_last_4: personalIdNumber } : { personal_id_number: personalIdNumber }; + // Params for Stripe SDK const params = { legal_entity: { @@ -420,7 +423,7 @@ export const createStripeAccount = payoutDetails => (dispatch, getState, sdk) => address: omitBy(address, isUndefined), dob: birthDate, type: 'individual', - personal_id_number: personalIdNumber, + ...idNumber, }, tos_shown_and_accepted: true, }; diff --git a/src/forms/PayoutDetailsForm/PayoutDetailsForm.js b/src/forms/PayoutDetailsForm/PayoutDetailsForm.js index eb163bcc..2be17464 100644 --- a/src/forms/PayoutDetailsForm/PayoutDetailsForm.js +++ b/src/forms/PayoutDetailsForm/PayoutDetailsForm.js @@ -116,25 +116,47 @@ const PayoutDetailsFormComponent = props => ( const bankAccountRequired = validators.required(' '); const showPersonalIdNumber = - country && stripeCountryConfigs(country).personalIdNumberRequired; + (country && stripeCountryConfigs(country).personalIdNumberRequired) || + (country && stripeCountryConfigs(country).ssnLast4Required); - const personalIdNumberLabel = showPersonalIdNumber - ? intl.formatMessage({ - id: `PayoutDetailsForm.personalIdNumberLabel.${country}`, + const personalIdNumberRequired = validators.required( + intl.formatMessage({ + id: `PayoutDetailsForm.personalIdNumberRequired`, + }) + ); + + let personalIdNumberLabel = null; + let personalIdNumberPlaceholder = null; + let personalIdNumberValid = personalIdNumberRequired; + + if (country === 'US') { + personalIdNumberLabel = intl.formatMessage({ + id: `PayoutDetailsForm.personalIdNumberLabel.US`, + }); + personalIdNumberPlaceholder = intl.formatMessage({ + id: `PayoutDetailsForm.personalIdNumberPlaceholder.US`, + }); + + const validSSN = validators.validSsnLast4( + intl.formatMessage({ + id: `PayoutDetailsForm.personalIdNumberValid`, }) - : null; - const personalIdNumberPlaceholder = showPersonalIdNumber - ? intl.formatMessage({ - id: `PayoutDetailsForm.personalIdNumberPlaceholder.${country}`, + ); + personalIdNumberValid = validators.composeValidators(personalIdNumberRequired, validSSN); + } else if (country === 'HK') { + personalIdNumberLabel = intl.formatMessage({ + id: `PayoutDetailsForm.personalIdNumberLabel.HK`, + }); + personalIdNumberPlaceholder = intl.formatMessage({ + id: `PayoutDetailsForm.personalIdNumberPlaceholder.HK`, + }); + const validHKID = validators.validHKID( + intl.formatMessage({ + id: `PayoutDetailsForm.personalIdNumberValid`, }) - : null; - const personalIdNumberRequired = showPersonalIdNumber - ? validators.required( - intl.formatMessage({ - id: `PayoutDetailsForm.personalIdNumberRequired`, - }) - ) - : null; + ); + personalIdNumberValid = validators.composeValidators(personalIdNumberRequired, validHKID); + } const classes = classNames(css.root, className, { [css.disabled]: disabled, @@ -261,7 +283,7 @@ const PayoutDetailsFormComponent = props => ( type="text" label={personalIdNumberLabel} placeholder={personalIdNumberPlaceholder} - validate={personalIdNumberRequired} + validate={personalIdNumberValid} />
) : null} diff --git a/src/translations/en.json b/src/translations/en.json index 519e548f..4f239168 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -503,6 +503,7 @@ "PayoutDetailsForm.personalIdNumberLabel.US": "Last 4 digits of social security number (SSN)", "PayoutDetailsForm.personalIdNumberPlaceholder.HK": "XY123456", "PayoutDetailsForm.personalIdNumberRequired": "This field is required", + "PayoutDetailsForm.personalIdNumberValid": "Invalid value", "PayoutDetailsForm.postalCodeLabel": "Postal code", "PayoutDetailsForm.postalCodePlaceholder": "00100", "PayoutDetailsForm.postalCodeRequired": "This field is required", diff --git a/src/util/validators.js b/src/util/validators.js index 07fe9660..2c6ecffa 100644 --- a/src/util/validators.js +++ b/src/util/validators.js @@ -136,5 +136,69 @@ export const ageAtLeast = (message, minYears) => value => { return message; }; +export const validSsnLast4 = message => value => { + return value.length === 4 ? VALID : message; +}; + +export const validHKID = message => value => { + // Accept value 000000000 for testing Stripe + if (value.length === 9 && value.match(/([0]{9})/)) { + return VALID; + } + + // HKID format example: AB364912(5) + // ID can start with one or two letters and the check digit in the end can be in brackets or not + if (value.length < 8) { + return message; + } + + // Handle possible brackets in value + if (value.charAt(value.length - 3) === '(' && value.charAt(value.length - 1) === ')') { + value = value.substring(0, value.length - 3) + value.charAt(value.length - 2); + } + value = value.toUpperCase(); + + // Check that pattern is correct and split value to array + const hkidPattern = /^([A-Z]{1,2})([0-9]{6})([A0-9])$/; + const matchArray = value.match(hkidPattern); + + if (!matchArray) { + return message; + } + + const charPart = matchArray[1]; + const numPart = matchArray[2]; + const checkDigit = matchArray[3]; + + // Calculate the checksum for character part. + // Transfer letters to numbers so that A=10, B=11, C=12 etc. + // If there is only one letter in the ID use 36 as the first value + // Total calculation is weighted so that 1st digit is x9, 2nd digit x8, 3rd digit x7 etc. + + const strValidChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + let checkSum = 0; + + if (charPart.length === 2) { + checkSum += 9 * (10 + strValidChars.indexOf(charPart.charAt(0))); + checkSum += 8 * (10 + strValidChars.indexOf(charPart.charAt(1))); + } else { + checkSum += 9 * 36; + checkSum += 8 * (10 + strValidChars.indexOf(charPart)); + } + + // Calculate the checksum for numeric part + + for (let i = 0, j = 7; i < numPart.length; i++, j--) { + checkSum += j * numPart.charAt(i); + } + + // Verify the check digit + const remaining = checkSum % 11; + const verify = remaining === 0 ? 0 : 11 - remaining; + const isValid = verify === checkDigit || (verify === 10 && checkDigit === 'A'); + + return isValid ? VALID : message; +}; + export const composeValidators = (...validators) => value => validators.reduce((error, validator) => error || validator(value), VALID); From 0035dae54b76c18c387e8f7ae2eb36da6e59fdbe Mon Sep 17 00:00:00 2001 From: Jenni Nurmi Date: Mon, 10 Dec 2018 11:27:43 +0200 Subject: [PATCH 10/13] Add ID number field with validators to US and HK --- src/util/validators.js | 3 ++- src/util/validators.test.js | 30 ++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/util/validators.js b/src/util/validators.js index 2c6ecffa..d8240dcc 100644 --- a/src/util/validators.js +++ b/src/util/validators.js @@ -194,7 +194,8 @@ export const validHKID = message => value => { // Verify the check digit const remaining = checkSum % 11; - const verify = remaining === 0 ? 0 : 11 - remaining; + let verify = remaining === 0 ? 0 : 11 - remaining; + verify = verify.toString(); const isValid = verify === checkDigit || (verify === 10 && checkDigit === 'A'); return isValid ? VALID : message; diff --git a/src/util/validators.test.js b/src/util/validators.test.js index 56c286bd..08e8d23a 100644 --- a/src/util/validators.test.js +++ b/src/util/validators.test.js @@ -6,6 +6,7 @@ import { maxLength, moneySubUnitAmountAtLeast, composeValidators, + validHKID, } from './validators'; const { Money } = sdkTypes; @@ -184,4 +185,33 @@ describe('validators', () => { expect(validateLength('')).toEqual('minLength'); }); }); + describe('validHKID()', () => { + it('should fail on too short HKID', () => { + expect(validHKID('fail')('AB987')).toEqual('fail'); + }); + it('should fail if value is in wrong format: no letters', () => { + expect(validHKID('fail')('13278240')).toEqual('fail'); + }); + it('should fail if value is in wrong format: too many letters', () => { + expect(validHKID('fail')('ABE9876543')).toEqual('fail'); + }); + it('should fail if value is in wrong format: too many numbers', () => { + expect(validHKID('fail')('E13278240')).toEqual('fail'); + }); + it('should fail if check digit is wrong', () => { + expect(validHKID('fail')('E327824(3)')).toEqual('fail'); + }); + it('should allow string of nine digits with all zeros', () => { + expect(validHKID('pass')('000000000')).toBeUndefined(); + }); + it('should allow string with valid HKID using two letters', () => { + expect(validHKID('pass')('AB9876543')).toBeUndefined(); + }); + it('should allow string with valid HKID using one letter', () => { + expect(validHKID('pass')('E3278240')).toBeUndefined(); + }); + it('should allow string with valid HKID using brackets in check digit', () => { + expect(validHKID('pass')('E327824(0)')).toBeUndefined(); + }); + }); }); From 3707a1bc04fba537432019ebc5b8f74f28227a60 Mon Sep 17 00:00:00 2001 From: Jenni Nurmi Date: Mon, 10 Dec 2018 11:28:07 +0200 Subject: [PATCH 11/13] Update translations --- src/translations/en.json | 5 ++-- src/translations/fr.json | 51 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/src/translations/en.json b/src/translations/en.json index 4f239168..4dfbba64 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -481,8 +481,8 @@ "PayoutDetailsForm.countryNames.IT": "Italy", "PayoutDetailsForm.countryNames.LU": "Luxembourg", "PayoutDetailsForm.countryNames.NL": "Netherlands", - "PayoutDetailsForm.countryNames.NZ": "New Zealand", "PayoutDetailsForm.countryNames.NO": "Norway", + "PayoutDetailsForm.countryNames.NZ": "New Zealand", "PayoutDetailsForm.countryNames.PT": "Portugal", "PayoutDetailsForm.countryNames.SE": "Sweden", "PayoutDetailsForm.countryNames.US": "United States", @@ -502,6 +502,7 @@ "PayoutDetailsForm.personalIdNumberLabel.HK": "Hong Kong Identity Card Number (HKID)", "PayoutDetailsForm.personalIdNumberLabel.US": "Last 4 digits of social security number (SSN)", "PayoutDetailsForm.personalIdNumberPlaceholder.HK": "XY123456", + "PayoutDetailsForm.personalIdNumberPlaceholder.US": "1234", "PayoutDetailsForm.personalIdNumberRequired": "This field is required", "PayoutDetailsForm.personalIdNumberValid": "Invalid value", "PayoutDetailsForm.postalCodeLabel": "Postal code", @@ -689,11 +690,11 @@ "StripeBankAccountTokenInputField.sortCode.label": "Sort code", "StripeBankAccountTokenInputField.sortCode.placeholder": "Type in sort code…", "StripeBankAccountTokenInputField.sortCode.required": "Sort code is required", - "StripeBankAccountTokenInputField.unsupportedCountry": "Country not supported: {country}", "StripeBankAccountTokenInputField.transitNumber.inline": "transit number", "StripeBankAccountTokenInputField.transitNumber.label": "Transit number", "StripeBankAccountTokenInputField.transitNumber.placeholder": "Type in transit number", "StripeBankAccountTokenInputField.transitNumber.required": "Transit number is required", + "StripeBankAccountTokenInputField.unsupportedCountry": "Country not supported: {country}", "StripePaymentForm.creditCardDetails": "Credit card details", "StripePaymentForm.genericError": "Could not handle payment data. Please try again.", "StripePaymentForm.messageHeading": "Message", diff --git a/src/translations/fr.json b/src/translations/fr.json index 34b68493..39e42e1a 100644 --- a/src/translations/fr.json +++ b/src/translations/fr.json @@ -445,6 +445,22 @@ "PayoutDetailsForm.birthdayMonthPlaceholder": "mm", "PayoutDetailsForm.birthdayRequired": "La date de naissance est requise et doit être valide.", "PayoutDetailsForm.birthdayYearPlaceholder": "aaaa", + "PayoutDetailsForm.canadianProvinceLabel": "Province", + "PayoutDetailsForm.canadianProvinceNames.AB": "Alberta", + "PayoutDetailsForm.canadianProvinceNames.BC": "British Columbia", + "PayoutDetailsForm.canadianProvinceNames.MB": "Manitoba", + "PayoutDetailsForm.canadianProvinceNames.NB": "New Brunswick", + "PayoutDetailsForm.canadianProvinceNames.NL": "Newfoundland and Labrador", + "PayoutDetailsForm.canadianProvinceNames.NS": "Nova Scotia", + "PayoutDetailsForm.canadianProvinceNames.NT": "Northwest Territories", + "PayoutDetailsForm.canadianProvinceNames.NU": "Nunavut", + "PayoutDetailsForm.canadianProvinceNames.ON": "Ontario", + "PayoutDetailsForm.canadianProvinceNames.PE": "Prince Edward Island", + "PayoutDetailsForm.canadianProvinceNames.QC": "Quebec", + "PayoutDetailsForm.canadianProvinceNames.SK": "Saskatchewan", + "PayoutDetailsForm.canadianProvinceNames.YT": "Yukon", + "PayoutDetailsForm.canadianProvincePlaceholder": "Province", + "PayoutDetailsForm.canadianProvinceRequired": "This field is required", "PayoutDetailsForm.cityLabel": "Ville", "PayoutDetailsForm.cityPlaceholder": "Helsinki", "PayoutDetailsForm.cityRequired": "Ce champ est requis.", @@ -452,16 +468,21 @@ "PayoutDetailsForm.countryNames.AT": "Autriche", "PayoutDetailsForm.countryNames.AU": "Australie", "PayoutDetailsForm.countryNames.BE": "Belgique", + "PayoutDetailsForm.countryNames.CA": "Canada", + "PayoutDetailsForm.countryNames.CH": "Switzerland", "PayoutDetailsForm.countryNames.DE": "Allemagne", "PayoutDetailsForm.countryNames.DK": "Danemark", "PayoutDetailsForm.countryNames.ES": "Espagne", "PayoutDetailsForm.countryNames.FI": "Finlande", "PayoutDetailsForm.countryNames.FR": "France", "PayoutDetailsForm.countryNames.GB": "Royaune-Uni", + "PayoutDetailsForm.countryNames.HK": "Hong Kong", "PayoutDetailsForm.countryNames.IE": "Irelande", "PayoutDetailsForm.countryNames.IT": "Italie", "PayoutDetailsForm.countryNames.LU": "Luxembourg", "PayoutDetailsForm.countryNames.NL": "Pays-Bas", + "PayoutDetailsForm.countryNames.NO": "Norway", + "PayoutDetailsForm.countryNames.NZ": "New Zealand", "PayoutDetailsForm.countryNames.PT": "Portugal", "PayoutDetailsForm.countryNames.SE": "Suède", "PayoutDetailsForm.countryNames.US": "États-Unis", @@ -477,9 +498,19 @@ "PayoutDetailsForm.lastNamePlaceholder": "Nom", "PayoutDetailsForm.lastNameRequired": "Ce champ est requis.", "PayoutDetailsForm.personalDetailsTitle": "Détails", + "PayoutDetailsForm.personalIdNumberLabel.HK": "Hong Kong Identity Card Number (HKID)", + "PayoutDetailsForm.personalIdNumberLabel.US": "Last 4 digits of social security number (SSN)", + "PayoutDetailsForm.personalIdNumberPlaceholder.HK": "XY123456", + "PayoutDetailsForm.personalIdNumberPlaceholder.US": "1234", + "PayoutDetailsForm.personalIdNumberRequired": "This field is required", + "PayoutDetailsForm.personalIdNumberTitle": "Personal id number", + "PayoutDetailsForm.personalIdNumberValid": "Invalid value", "PayoutDetailsForm.postalCodeLabel": "Code postal", "PayoutDetailsForm.postalCodePlaceholder": "00100", "PayoutDetailsForm.postalCodeRequired": "Ce champ est requis.", + "PayoutDetailsForm.stateLabel": "State", + "PayoutDetailsForm.statePlaceholder": "Enter your state", + "PayoutDetailsForm.stateRequired": "This field is required", "PayoutDetailsForm.streetAddressLabel": "Adresse", "PayoutDetailsForm.streetAddressPlaceholder": "Entrez votre adresse", "PayoutDetailsForm.streetAddressRequired": "Ce champ est requis.", @@ -499,8 +530,8 @@ "PayoutPreferencesPage.title": "Paiements", "PriceFilter.clear": "Effacer", "PriceFilter.label": "Prix", - "PriceFilter.labelSelectedPlain": "Prix : {minPrice} - {maxPrice}", "PriceFilter.labelSelectedButton": "{minPrice} - {maxPrice}", + "PriceFilter.labelSelectedPlain": "Prix : {minPrice} - {maxPrice}", "PriceFilterForm.cancel": "Annuler", "PriceFilterForm.clear": "Effacer", "PriceFilterForm.label": "Gamme de prix :", @@ -629,16 +660,28 @@ "StripeBankAccountTokenInputField.accountNumber.placeholder": "Entrez votre numéro de compte bancaire", "StripeBankAccountTokenInputField.accountNumber.required": "Le numéro de compte bancaire est requis.", "StripeBankAccountTokenInputField.andBeforeLastItemInAList": " et", + "StripeBankAccountTokenInputField.branchCode.inline": "Branch code", + "StripeBankAccountTokenInputField.branchCode.label": "Branch code", + "StripeBankAccountTokenInputField.branchCode.placeholder": "Type in branch code…", + "StripeBankAccountTokenInputField.branchCode.required": "Branch code is required", "StripeBankAccountTokenInputField.bsb.inline": "BSB", "StripeBankAccountTokenInputField.bsb.label": "BSB", "StripeBankAccountTokenInputField.bsb.placeholder": "Entrez le BSB…", "StripeBankAccountTokenInputField.bsb.required": "Le BSB est requis.", + "StripeBankAccountTokenInputField.clearingCode.inline": "Clearing code", + "StripeBankAccountTokenInputField.clearingCode.label": "Clearing code", + "StripeBankAccountTokenInputField.clearingCode.placeholder": "Type in clearing code…", + "StripeBankAccountTokenInputField.clearingCode.required": "Clearing code is required", "StripeBankAccountTokenInputField.genericStripeError": "Impossible de connecter ce numéro de compte bancaire. Veuillez vérifier que {inputs} est valide en {country}", "StripeBankAccountTokenInputField.genericStripeErrorIban": "Impossible de connecter ce numéro de compte bancaire. Veuillez vérifier ce numéro est valide en {country}", "StripeBankAccountTokenInputField.iban.inline": "IBAN", "StripeBankAccountTokenInputField.iban.label": "Numéro de compte bancaire (IBAN)", "StripeBankAccountTokenInputField.iban.placeholder": "Par exemple FR76 3000 6000 0112 3456 7890 189", "StripeBankAccountTokenInputField.iban.required": "Le numéro de compte bancaire (IBAN) est requis.", + "StripeBankAccountTokenInputField.institutionNumber.inline": "institution number", + "StripeBankAccountTokenInputField.institutionNumber.label": "Institution number", + "StripeBankAccountTokenInputField.institutionNumber.placeholder": "Type in institution number", + "StripeBankAccountTokenInputField.institutionNumber.required": "Institution number is required", "StripeBankAccountTokenInputField.routingNumber.inline": "numéro de routage number", "StripeBankAccountTokenInputField.routingNumber.label": "Numéro de routage", "StripeBankAccountTokenInputField.routingNumber.placeholder": "Entrez le numéro de routage…", @@ -647,6 +690,10 @@ "StripeBankAccountTokenInputField.sortCode.label": "Code de tri", "StripeBankAccountTokenInputField.sortCode.placeholder": "Entrez un code de tri…", "StripeBankAccountTokenInputField.sortCode.required": "Un code de tri est requis.", + "StripeBankAccountTokenInputField.transitNumber.inline": "transit number", + "StripeBankAccountTokenInputField.transitNumber.label": "Transit number", + "StripeBankAccountTokenInputField.transitNumber.placeholder": "Type in transit number", + "StripeBankAccountTokenInputField.transitNumber.required": "Transit number is required", "StripeBankAccountTokenInputField.unsupportedCountry": "Pays non supporté : {country}", "StripePaymentForm.creditCardDetails": "Votre carte bancaire", "StripePaymentForm.genericError": "Impossible de traiter ces détails de paiement. Veuillez essayer de nouveau.", @@ -749,4 +796,4 @@ "UserCard.heading": "Bonjour, je suis {name}.", "UserCard.showFullBioLink": "plus", "UserCard.viewProfileLink": "Voir le profil" -} +} \ No newline at end of file From 687cf7bbe9242210e18841852ecc7055c1b362bd Mon Sep 17 00:00:00 2001 From: Jenni Nurmi Date: Mon, 10 Dec 2018 11:28:37 +0200 Subject: [PATCH 12/13] Move Stripe config to separate file --- .env-template | 2 + src/config.js | 293 +----------------------------------------- src/stripe-config.js | 298 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 301 insertions(+), 292 deletions(-) create mode 100644 src/stripe-config.js diff --git a/.env-template b/.env-template index 82e4be59..24066181 100644 --- a/.env-template +++ b/.env-template @@ -1,6 +1,8 @@ # Mandatory configuration # +# Note: You also need to set Stripe secret key in Flex Console. +# REACT_APP_SHARETRIBE_SDK_CLIENT_ID= REACT_APP_STRIPE_PUBLISHABLE_KEY= REACT_APP_MAPBOX_ACCESS_TOKEN= diff --git a/src/config.js b/src/config.js index 32b8401e..b42c7a43 100644 --- a/src/config.js +++ b/src/config.js @@ -1,5 +1,6 @@ import * as custom from './marketplace-custom-config.js'; import defaultLocationSearches from './default-location-searches'; +import { stripePublishableKey, stripeSupportedCountries } from './stripe-config'; const env = process.env.REACT_APP_ENV; const dev = process.env.REACT_APP_ENV === 'development'; @@ -79,298 +80,6 @@ const currencyConfig = { maximumFractionDigits: 2, }; -const stripePublishableKey = process.env.REACT_APP_STRIPE_PUBLISHABLE_KEY; - -// Stripe only supports payments in certain countries, see full list -// at https://stripe.com/global -// -// We currently only support EU countries, US, and AU. -const stripeSupportedCountries = [ - { - // Australia - code: 'AU', - currency: 'AUD', - addressConfig: { - addressLine: true, - city: true, - postalCode: true, - state: true, - }, - accountConfig: { - bsb: true, - accountNumber: true, - }, - }, - { - // Austria - code: 'AT', - currency: 'EUR', - addressConfig: { - addressLine: true, - city: true, - postalCode: true, - }, - accountConfig: { - iban: true, - }, - }, - { - // Belgium - code: 'BE', - currency: 'EUR', - addressConfig: { - addressLine: true, - city: true, - postalCode: true, - }, - accountConfig: { - iban: true, - }, - }, - { - // Canada - code: 'CA', - currency: 'CAD', - addressConfig: { - addressLine: true, - city: true, - postalCode: true, - province: true, - }, - accountConfig: { - transitNumber: true, - institutionNumber: true, - accountNumber: true, - }, - }, - { - // Denmark - code: 'DK', - currency: 'DKK', - addressConfig: { - addressLine: true, - city: true, - postalCode: true, - }, - accountConfig: { - iban: true, - }, - }, - { - // Finland - code: 'FI', - currency: 'EUR', - addressConfig: { - addressLine: true, - city: true, - postalCode: true, - }, - accountConfig: { - iban: true, - }, - }, - { - // France - code: 'FR', - currency: 'EUR', - addressConfig: { - addressLine: true, - city: true, - postalCode: true, - }, - accountConfig: { - iban: true, - }, - }, - { - // Germany - code: 'DE', - currency: 'EUR', - addressConfig: { - addressLine: true, - city: true, - postalCode: true, - }, - accountConfig: { - iban: true, - }, - }, - { - // Hong Kong - code: 'HK', - currency: 'HKD', - addressConfig: { - addressLine: true, - city: true, - }, - accountConfig: { - clearingCode: true, - branchCode: true, - accountNumber: true, - }, - personalIdNumberRequired: true, - }, - { - // Ireland - code: 'IE', - currency: 'EUR', - addressConfig: { - addressLine: true, - city: true, - postalCode: true, - }, - accountConfig: { - iban: true, - }, - }, - { - // Italy - code: 'IT', - currency: 'EUR', - addressConfig: { - addressLine: true, - city: true, - postalCode: true, - }, - accountConfig: { - iban: true, - }, - }, - { - // Luxembourg - code: 'LU', - currency: 'EUR', - addressConfig: { - addressLine: true, - city: true, - postalCode: true, - }, - accountConfig: { - iban: true, - }, - }, - { - // Netherlands - code: 'NL', - currency: 'EUR', - addressConfig: { - addressLine: true, - city: true, - postalCode: true, - }, - accountConfig: { - iban: true, - }, - }, - { - // New Zealand - code: 'NZ', - currency: 'NZD', - addressConfig: { - addressLine: true, - city: true, - postalCode: true, - }, - accountConfig: { - accountNumber: true, - }, - }, - { - // Norway - code: 'NO', - currency: 'EUR', - addressConfig: { - addressLine: true, - city: true, - postalCode: true, - }, - accountConfig: { - iban: true, - }, - }, - { - // Portugal - code: 'PT', - currency: 'EUR', - addressConfig: { - addressLine: true, - city: true, - postalCode: true, - }, - accountConfig: { - iban: true, - }, - }, - { - // Spain - code: 'ES', - currency: 'EUR', - addressConfig: { - addressLine: true, - city: true, - postalCode: true, - }, - accountConfig: { - iban: true, - }, - }, - { - // Sweden - code: 'SE', - currency: 'SEK', - addressConfig: { - addressLine: true, - city: true, - postalCode: true, - }, - accountConfig: { - iban: true, - }, - }, - { - // Switzerland - code: 'CH', - currency: 'CHF', - addressConfig: { - addressLine: true, - city: true, - postalCode: true, - }, - accountConfig: { - iban: true, - }, - }, - { - // United Kingdom - code: 'GB', - currency: 'GBP', - addressConfig: { - addressLine: true, - city: true, - postalCode: true, - }, - accountConfig: { - sortCode: true, - accountNumber: true, - }, - }, - { - // United States - code: 'US', - currency: 'USD', - addressConfig: { - addressLine: true, - city: true, - postalCode: true, - state: true, - }, - accountConfig: { - routingNumber: true, - accountNumber: true, - }, - }, -]; - // Address information is used in SEO schema for Organization (http://schema.org/PostalAddress) const addressCountry = 'FI'; const addressRegion = 'Helsinki'; diff --git a/src/stripe-config.js b/src/stripe-config.js new file mode 100644 index 00000000..ec2a94c6 --- /dev/null +++ b/src/stripe-config.js @@ -0,0 +1,298 @@ +/* + * Stripe related configuration. + */ + +// NOTE: REACT_APP_STRIPE_PUBLISHABLE_KEY is mandatory environment variable. +// This variable is set in a hidden file: .env +// To make Stripe connection work, you also need to set Stripe's private key in the Flex Console. +export const stripePublishableKey = process.env.REACT_APP_STRIPE_PUBLISHABLE_KEY; + +// Stripe only supports payments in certain countries, see full list +// at https://stripe.com/global +// +export const stripeSupportedCountries = [ + { + // Australia + code: 'AU', + currency: 'AUD', + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + state: true, + }, + accountConfig: { + bsb: true, + accountNumber: true, + }, + }, + { + // Austria + code: 'AT', + currency: 'EUR', + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + }, + accountConfig: { + iban: true, + }, + }, + { + // Belgium + code: 'BE', + currency: 'EUR', + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + }, + accountConfig: { + iban: true, + }, + }, + { + // Canada + code: 'CA', + currency: 'CAD', + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + province: true, + }, + accountConfig: { + transitNumber: true, + institutionNumber: true, + accountNumber: true, + }, + }, + { + // Denmark + code: 'DK', + currency: 'DKK', + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + }, + accountConfig: { + iban: true, + }, + }, + { + // Finland + code: 'FI', + currency: 'EUR', + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + }, + accountConfig: { + iban: true, + }, + }, + { + // France + code: 'FR', + currency: 'EUR', + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + }, + accountConfig: { + iban: true, + }, + }, + { + // Germany + code: 'DE', + currency: 'EUR', + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + }, + accountConfig: { + iban: true, + }, + }, + { + // Hong Kong + code: 'HK', + currency: 'HKD', + addressConfig: { + addressLine: true, + city: true, + }, + accountConfig: { + clearingCode: true, + branchCode: true, + accountNumber: true, + }, + personalIdNumberRequired: true, + }, + { + // Ireland + code: 'IE', + currency: 'EUR', + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + }, + accountConfig: { + iban: true, + }, + }, + { + // Italy + code: 'IT', + currency: 'EUR', + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + }, + accountConfig: { + iban: true, + }, + }, + { + // Luxembourg + code: 'LU', + currency: 'EUR', + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + }, + accountConfig: { + iban: true, + }, + }, + { + // Netherlands + code: 'NL', + currency: 'EUR', + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + }, + accountConfig: { + iban: true, + }, + }, + { + // New Zealand + code: 'NZ', + currency: 'NZD', + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + }, + accountConfig: { + accountNumber: true, + }, + }, + { + // Norway + code: 'NO', + currency: 'EUR', + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + }, + accountConfig: { + iban: true, + }, + }, + { + // Portugal + code: 'PT', + currency: 'EUR', + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + }, + accountConfig: { + iban: true, + }, + }, + { + // Spain + code: 'ES', + currency: 'EUR', + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + }, + accountConfig: { + iban: true, + }, + }, + { + // Sweden + code: 'SE', + currency: 'SEK', + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + }, + accountConfig: { + iban: true, + }, + }, + { + // Switzerland + code: 'CH', + currency: 'CHF', + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + }, + accountConfig: { + iban: true, + }, + }, + { + // United Kingdom + code: 'GB', + currency: 'GBP', + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + }, + accountConfig: { + sortCode: true, + accountNumber: true, + }, + }, + { + // United States + code: 'US', + currency: 'USD', + addressConfig: { + addressLine: true, + city: true, + postalCode: true, + state: true, + }, + accountConfig: { + routingNumber: true, + accountNumber: true, + }, + ssnLast4Required: true, + }, +]; From ffa3c7ee2fba5385ae5dc3437ccf222026e24734 Mon Sep 17 00:00:00 2001 From: Jenni Nurmi Date: Mon, 10 Dec 2018 11:28:50 +0200 Subject: [PATCH 13/13] Update changelog --- CHANGELOG.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f5e97ad6..5758c6cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,10 +14,16 @@ way to update this template, but currently, we follow a pattern: ## Upcoming version 2018-XX-XX +- [add] Add Stripe support for new countries: Canada, New Zealand, Switzerland, Norway, and Hong + Kong. Also add more required fields for US and Australia. + - StripeBankAccountTokenInputField component and PayoutDetailsForm have some changes + - Stripe related configuration is separated to new stripe-config.js file. + - Multiple new translation keys were added and they might not be translated into French yet. If + you use French translation check PR for the changed keys. + [#968](https://github.com/sharetribe/flex-template-web/pull/968) - [change] Remove generic perUnit translations and replace them with specific night, day and unit translations depending on booking unit chosen in config. [#970](https://github.com/sharetribe/flex-template-web/pull/970) - - [fix] Formatting docs with newest Prettier - related commit was lost in #967 at some point. [#975](https://github.com/sharetribe/flex-template-web/pull/975) - [change] Improved documents related to onboarding: env.md, deploying-to-production.md,