mirror of
https://github.com/kingomarnajjar/flex-template-web.git
synced 2026-07-26 06:47:17 +10:00
Merge pull request #980 from sharetribe/add-stripe-business-accounts
Add stripe business accounts
This commit is contained in:
commit
400a0d3df2
23 changed files with 987 additions and 261 deletions
|
|
@ -14,6 +14,9 @@ way to update this template, but currently, we follow a pattern:
|
|||
|
||||
## Upcoming version 2019-XX-XX
|
||||
|
||||
- [add] Support for Stripe company accounts. `PayoutDetailsForm` was separated into smaller
|
||||
subcomponents. Multiple new translation keys were added and they might not be translated into
|
||||
French yet. [#980](https://github.com/sharetribe/flex-template-web/pull/980)
|
||||
- Manage availability of listings. This works for listings that have booking unit type:
|
||||
'line-item/night', or 'line-item/day'. There's also 'manage availability' link in the
|
||||
ManageListingCards of "your listings" page.
|
||||
|
|
|
|||
|
|
@ -102,3 +102,14 @@
|
|||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.modalTitle {
|
||||
@apply --marketplaceModalTitleStyles;
|
||||
}
|
||||
|
||||
.modalPayoutDetailsWrapper {
|
||||
@media (--viewportMedium) {
|
||||
width: 604px;
|
||||
padding-top: 11px;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -264,7 +264,7 @@ class EditListingWizard extends Component {
|
|||
onClose={this.handlePayoutModalClose}
|
||||
onManageDisableScrolling={onManageDisableScrolling}
|
||||
>
|
||||
<div className={css.modalHeaderWrapper}>
|
||||
<div className={css.modalPayoutDetailsWrapper}>
|
||||
<h1 className={css.modalTitle}>
|
||||
<FormattedMessage id="EditListingPhotosPanel.payoutModalTitleOneMoreThing" />
|
||||
<br />
|
||||
|
|
@ -273,14 +273,14 @@ class EditListingWizard extends Component {
|
|||
<p className={css.modalMessage}>
|
||||
<FormattedMessage id="EditListingPhotosPanel.payoutModalInfo" />
|
||||
</p>
|
||||
<PayoutDetailsForm
|
||||
className={css.payoutDetails}
|
||||
inProgress={fetchInProgress}
|
||||
createStripeAccountError={errors ? errors.createStripeAccountError : null}
|
||||
onChange={onPayoutDetailsFormChange}
|
||||
onSubmit={this.handlePayoutSubmit}
|
||||
/>
|
||||
</div>
|
||||
<PayoutDetailsForm
|
||||
className={css.payoutDetails}
|
||||
inProgress={fetchInProgress}
|
||||
createStripeAccountError={errors ? errors.createStripeAccountError : null}
|
||||
onChange={onPayoutDetailsFormChange}
|
||||
onSubmit={this.handlePayoutSubmit}
|
||||
/>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -15,6 +15,16 @@
|
|||
display: inline;
|
||||
}
|
||||
|
||||
/* Highlight the borders if the checkbox is hovered, focused or checked */
|
||||
&:hover + label .notChecked,
|
||||
&:hover + label .required,
|
||||
&:focus + label .notChecked,
|
||||
&:focus + label .required,
|
||||
&:checked + label .notChecked,
|
||||
&:checked + label .required {
|
||||
stroke: var(--matterColorDark);
|
||||
}
|
||||
|
||||
/* Hightlight the text on checked, hover and focus */
|
||||
&:focus + label .text,
|
||||
&:hover + label .text,
|
||||
|
|
@ -26,13 +36,13 @@
|
|||
.label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0;
|
||||
padding-top: 6px;
|
||||
}
|
||||
|
||||
.radioButtonWrapper {
|
||||
/* This should follow line-height */
|
||||
height: 32px;
|
||||
margin-top: -1px;
|
||||
margin-top: -2px;
|
||||
margin-right: 12px;
|
||||
align-self: baseline;
|
||||
|
||||
|
|
@ -49,10 +59,16 @@
|
|||
|
||||
.notChecked {
|
||||
stroke: var(--matterColorAnti);
|
||||
&:hover {
|
||||
stroke: pink;
|
||||
}
|
||||
}
|
||||
|
||||
.required {
|
||||
stroke: var(--attentionColor);
|
||||
&:hover {
|
||||
stroke: pink;
|
||||
}
|
||||
}
|
||||
|
||||
.text {
|
||||
|
|
|
|||
5
src/components/IconAdd/IconAdd.css
Normal file
5
src/components/IconAdd/IconAdd.css
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
@import '../../marketplace.css';
|
||||
|
||||
.root {
|
||||
fill: var(--marketplaceColor);
|
||||
}
|
||||
7
src/components/IconAdd/IconAdd.example.js
Normal file
7
src/components/IconAdd/IconAdd.example.js
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import IconAdd from './IconAdd';
|
||||
|
||||
export const Icon = {
|
||||
component: IconAdd,
|
||||
props: {},
|
||||
group: 'icons',
|
||||
};
|
||||
33
src/components/IconAdd/IconAdd.js
Normal file
33
src/components/IconAdd/IconAdd.js
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import css from './IconAdd.css';
|
||||
|
||||
const IconAdd = props => {
|
||||
const { className, rootClassName } = props;
|
||||
const classes = classNames(rootClassName || css.root, className);
|
||||
|
||||
return (
|
||||
<svg className={classes} width="12" height="12" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M6.89 10.4V6.888h3.509a.889.889 0 1 0 0-1.779H6.89V1.6a.89.89 0 0 0-1.778 0v3.511h-3.51a.888.888 0 1 0 0 1.778h3.51v3.51a.889.889 0 1 0 1.778 0"
|
||||
fillRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
const { string } = PropTypes;
|
||||
|
||||
IconAdd.defaultProps = {
|
||||
className: null,
|
||||
rootClassName: null,
|
||||
};
|
||||
|
||||
IconAdd.propTypes = {
|
||||
className: string,
|
||||
rootClassName: string,
|
||||
};
|
||||
|
||||
export default IconAdd;
|
||||
|
|
@ -5,3 +5,11 @@ export const Icon = {
|
|||
props: {},
|
||||
group: 'icons',
|
||||
};
|
||||
|
||||
export const IconSmall = {
|
||||
component: IconClose,
|
||||
props: {
|
||||
size: 'small',
|
||||
},
|
||||
group: 'icons',
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,11 +3,23 @@ import PropTypes from 'prop-types';
|
|||
import classNames from 'classnames';
|
||||
|
||||
import css from './IconClose.css';
|
||||
const SIZE_SMALL = 'small';
|
||||
|
||||
const IconClose = props => {
|
||||
const { className, rootClassName } = props;
|
||||
const { className, rootClassName, size } = props;
|
||||
const classes = classNames(rootClassName || css.root, className);
|
||||
|
||||
if (size === SIZE_SMALL) {
|
||||
return (
|
||||
<svg className={classes} width="9" height="9" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M2.175 8.396l2.482-2.482 2.482 2.482a.889.889 0 1 0 1.258-1.257L5.914 4.657l2.482-2.483A.89.89 0 0 0 7.139.917L4.657 3.4 2.175.918A.888.888 0 1 0 .917 2.174L3.4 4.657.918 7.139a.889.889 0 1 0 1.257 1.257"
|
||||
fillRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<svg
|
||||
className={classes}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ export { default as FieldSelect } from './FieldSelect/FieldSelect';
|
|||
export { default as FieldTextInput } from './FieldTextInput/FieldTextInput';
|
||||
export { default as Footer } from './Footer/Footer';
|
||||
export { default as Form } from './Form/Form';
|
||||
export { default as IconAdd } from './IconAdd/IconAdd';
|
||||
export { default as IconArrowHead } from './IconArrowHead/IconArrowHead';
|
||||
export { default as IconBannedUser } from './IconBannedUser/IconBannedUser';
|
||||
export { default as IconCheckmark } from './IconCheckmark/IconCheckmark';
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@
|
|||
padding-top: 40px;
|
||||
|
||||
@media (--viewportMedium) {
|
||||
width: 571px;
|
||||
width: 604px;
|
||||
padding-top: 11px;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -389,29 +389,67 @@ export const createStripeAccount = payoutDetails => (dispatch, getState, sdk) =>
|
|||
|
||||
dispatch(stripeAccountCreateRequest());
|
||||
|
||||
const { accountType, country } = payoutDetails;
|
||||
|
||||
let payoutDetailValues;
|
||||
if (accountType === 'company') {
|
||||
payoutDetailValues = payoutDetails['company'];
|
||||
} else if (accountType === 'individual') {
|
||||
payoutDetailValues = payoutDetails['individual'];
|
||||
}
|
||||
|
||||
const {
|
||||
firstName,
|
||||
lastName,
|
||||
birthDate,
|
||||
country,
|
||||
streetAddress,
|
||||
postalCode,
|
||||
city,
|
||||
state,
|
||||
province,
|
||||
address,
|
||||
bankAccountToken,
|
||||
personalIdNumber,
|
||||
} = payoutDetails;
|
||||
companyName,
|
||||
companyTaxId,
|
||||
personalAddress,
|
||||
additionalOwners,
|
||||
} = payoutDetailValues;
|
||||
|
||||
const hasProvince = province && !state;
|
||||
const hasProvince = address.province && !address.state;
|
||||
|
||||
const address = {
|
||||
city,
|
||||
line1: streetAddress,
|
||||
postal_code: postalCode,
|
||||
state: hasProvince ? province : state,
|
||||
const addressValue = {
|
||||
city: address.city,
|
||||
line1: address.streetAddress,
|
||||
postal_code: address.postalCode,
|
||||
state: hasProvince ? address.province : address.state ? address.state : '',
|
||||
};
|
||||
|
||||
let personalAddressValue;
|
||||
if (personalAddress) {
|
||||
personalAddressValue = {
|
||||
city: personalAddress.city,
|
||||
line1: personalAddress.streetAddress,
|
||||
postal_code: personalAddress.postalCode,
|
||||
state: hasProvince
|
||||
? personalAddress.province
|
||||
: personalAddress.state
|
||||
? personalAddress.state
|
||||
: '',
|
||||
};
|
||||
}
|
||||
|
||||
const additionalOwnersValue = additionalOwners
|
||||
? additionalOwners.map(owner => {
|
||||
return {
|
||||
first_name: owner.firstName,
|
||||
last_name: owner.lastName,
|
||||
dob: owner.birthDate,
|
||||
address: {
|
||||
city: owner.city,
|
||||
line1: owner.streetAddress,
|
||||
postal_code: owner.postalCode,
|
||||
state: hasProvince ? owner.province : owner.state ? owner.state : '',
|
||||
},
|
||||
};
|
||||
})
|
||||
: [];
|
||||
|
||||
const idNumber =
|
||||
country === 'US' ? { ssn_last_4: personalIdNumber } : { personal_id_number: personalIdNumber };
|
||||
|
||||
|
|
@ -420,9 +458,13 @@ export const createStripeAccount = payoutDetails => (dispatch, getState, sdk) =>
|
|||
legal_entity: {
|
||||
first_name: firstName,
|
||||
last_name: lastName,
|
||||
address: omitBy(address, isUndefined),
|
||||
address: omitBy(addressValue, isUndefined),
|
||||
dob: birthDate,
|
||||
type: 'individual',
|
||||
type: accountType,
|
||||
business_name: companyName,
|
||||
business_tax_id: companyTaxId,
|
||||
personal_address: personalAddressValue,
|
||||
additional_owners: additionalOwnersValue,
|
||||
...idNumber,
|
||||
},
|
||||
tos_shown_and_accepted: true,
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import * as FieldReviewRating from './components/FieldReviewRating/FieldReviewRa
|
|||
import * as FieldSelect from './components/FieldSelect/FieldSelect.example';
|
||||
import * as FieldTextInput from './components/FieldTextInput/FieldTextInput.example';
|
||||
import * as Footer from './components/Footer/Footer.example';
|
||||
import * as IconAdd from './components/IconAdd/IconAdd.example';
|
||||
import * as IconBannedUser from './components/IconBannedUser/IconBannedUser.example';
|
||||
import * as IconCheckmark from './components/IconCheckmark/IconCheckmark.example';
|
||||
import * as IconClose from './components/IconClose/IconClose.example';
|
||||
|
|
@ -118,6 +119,7 @@ export {
|
|||
FieldSelect,
|
||||
FieldTextInput,
|
||||
Footer,
|
||||
IconAdd,
|
||||
IconBannedUser,
|
||||
IconCheckmark,
|
||||
IconClose,
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import React from 'react';
|
|||
import { bool, object, string } from 'prop-types';
|
||||
import { FieldSelect, FieldTextInput } from '../../components';
|
||||
import * as validators from '../../util/validators';
|
||||
import { intlShape } from 'react-intl';
|
||||
|
||||
import { stripeCountryConfigs } from './PayoutDetailsForm';
|
||||
import css from './PayoutDetailsForm.css';
|
||||
|
|
@ -23,13 +24,24 @@ const CANADIAN_PROVINCES = [
|
|||
];
|
||||
|
||||
const PayoutDetailsAddress = props => {
|
||||
const { country, intl, disabled, form } = props;
|
||||
const { className, country, intl, disabled, form, fieldId } = props;
|
||||
const countryConfig = country ? stripeCountryConfigs(country).addressConfig : null;
|
||||
|
||||
const isRequired = (countryConfig, field) => {
|
||||
return countryConfig[field];
|
||||
};
|
||||
|
||||
const showTitle =
|
||||
fieldId === 'company.address' ||
|
||||
fieldId === 'individual' ||
|
||||
fieldId === 'company.personalAddress';
|
||||
const addressTitle = intl.formatMessage({
|
||||
id:
|
||||
fieldId === 'company.address'
|
||||
? 'PayoutDetailsForm.companyAddressTitle'
|
||||
: 'PayoutDetailsForm.streetAddressLabel',
|
||||
});
|
||||
|
||||
const showAddressLine = country && isRequired(countryConfig, 'addressLine');
|
||||
|
||||
const streetAddressLabel = intl.formatMessage({
|
||||
|
|
@ -89,11 +101,13 @@ const PayoutDetailsAddress = props => {
|
|||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={className ? className : css.sectionContainer}>
|
||||
{showTitle ? <h3 className={css.subTitle}>{addressTitle}</h3> : null}
|
||||
|
||||
{showAddressLine ? (
|
||||
<FieldTextInput
|
||||
id="streetAddress"
|
||||
name="streetAddress"
|
||||
id={`${fieldId}.streetAddress`}
|
||||
name={`${fieldId}.streetAddress`}
|
||||
disabled={disabled}
|
||||
className={css.field}
|
||||
type="text"
|
||||
|
|
@ -101,14 +115,14 @@ const PayoutDetailsAddress = props => {
|
|||
label={streetAddressLabel}
|
||||
placeholder={streetAddressPlaceholder}
|
||||
validate={streetAddressRequired}
|
||||
onUnmount={() => form.change('streetAddress', undefined)}
|
||||
onUnmount={() => form.change(`${fieldId}.streetAddress`, undefined)}
|
||||
/>
|
||||
) : null}
|
||||
<div className={css.formRow}>
|
||||
{showPostalCode ? (
|
||||
<FieldTextInput
|
||||
id="postalCode"
|
||||
name="postalCode"
|
||||
id={`${fieldId}.postalCode`}
|
||||
name={`${fieldId}.postalCode`}
|
||||
disabled={disabled}
|
||||
className={css.postalCode}
|
||||
type="text"
|
||||
|
|
@ -116,13 +130,13 @@ const PayoutDetailsAddress = props => {
|
|||
label={postalCodeLabel}
|
||||
placeholder={postalCodePlaceholder}
|
||||
validate={postalCodeRequired}
|
||||
onUnmount={() => form.change('postalCode', undefined)}
|
||||
onUnmount={() => form.change(`${fieldId}.postalCode`, undefined)}
|
||||
/>
|
||||
) : null}
|
||||
{showCity ? (
|
||||
<FieldTextInput
|
||||
id="city"
|
||||
name="city"
|
||||
id={`${fieldId}.city`}
|
||||
name={`${fieldId}.city`}
|
||||
disabled={disabled}
|
||||
className={css.city}
|
||||
type="text"
|
||||
|
|
@ -130,14 +144,14 @@ const PayoutDetailsAddress = props => {
|
|||
label={cityLabel}
|
||||
placeholder={cityPlaceholder}
|
||||
validate={cityRequired}
|
||||
onUnmount={() => form.change('city', undefined)}
|
||||
onUnmount={() => form.change(`${fieldId}.city`, undefined)}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
{showState ? (
|
||||
<FieldTextInput
|
||||
id="state"
|
||||
name="state"
|
||||
id={`${fieldId}.state`}
|
||||
name={`${fieldId}.state`}
|
||||
disabled={disabled}
|
||||
className={css.state}
|
||||
type="text"
|
||||
|
|
@ -145,14 +159,14 @@ const PayoutDetailsAddress = props => {
|
|||
label={stateLabel}
|
||||
placeholder={statePlaceholder}
|
||||
validate={stateRequired}
|
||||
onUnmount={() => form.change('state', undefined)}
|
||||
onUnmount={() => form.change(`${fieldId}.state`, undefined)}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{showProvince ? (
|
||||
<FieldSelect
|
||||
id="province"
|
||||
name="province"
|
||||
id={`${fieldId}.province`}
|
||||
name={`${fieldId}.province`}
|
||||
disabled={disabled}
|
||||
className={css.selectCountry}
|
||||
autoComplete="province"
|
||||
|
|
@ -175,12 +189,17 @@ const PayoutDetailsAddress = props => {
|
|||
PayoutDetailsAddress.defaultProps = {
|
||||
country: null,
|
||||
disabled: false,
|
||||
fieldId: null,
|
||||
};
|
||||
|
||||
PayoutDetailsAddress.propTypes = {
|
||||
country: string,
|
||||
disabled: bool,
|
||||
form: object.isRequired,
|
||||
fieldId: string,
|
||||
|
||||
// from injectIntl
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
export default PayoutDetailsAddress;
|
||||
|
|
|
|||
52
src/forms/PayoutDetailsForm/PayoutDetailsBankDetails.js
Normal file
52
src/forms/PayoutDetailsForm/PayoutDetailsBankDetails.js
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
import React from 'react';
|
||||
import { bool, string } from 'prop-types';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { StripeBankAccountTokenInputField } from '../../components';
|
||||
import * as validators from '../../util/validators';
|
||||
|
||||
import { stripeCountryConfigs } from './PayoutDetailsForm';
|
||||
import css from './PayoutDetailsForm.css';
|
||||
|
||||
const countryCurrency = countryCode => {
|
||||
const country = stripeCountryConfigs(countryCode);
|
||||
return country.currency;
|
||||
};
|
||||
|
||||
const PayoutDetailsBankDetails = props => {
|
||||
const { country, disabled, fieldId } = props;
|
||||
|
||||
// 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.
|
||||
const bankAccountRequired = validators.required(' ');
|
||||
|
||||
return (
|
||||
<div className={css.sectionContainer}>
|
||||
<h3 className={css.subTitle}>
|
||||
<FormattedMessage id="PayoutDetailsForm.bankDetails" />
|
||||
</h3>
|
||||
<StripeBankAccountTokenInputField
|
||||
className={css.bankDetailsStripeField}
|
||||
disabled={disabled}
|
||||
name={`${fieldId}.bankAccountToken`}
|
||||
formName="PayoutDetailsForm"
|
||||
country={country}
|
||||
currency={countryCurrency(country)}
|
||||
validate={bankAccountRequired}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
PayoutDetailsBankDetails.defaultProps = {
|
||||
country: null,
|
||||
disabled: false,
|
||||
fieldId: null,
|
||||
};
|
||||
|
||||
PayoutDetailsBankDetails.propTypes = {
|
||||
country: string,
|
||||
disabled: bool,
|
||||
fieldId: string,
|
||||
};
|
||||
|
||||
export default PayoutDetailsBankDetails;
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
@import '../../marketplace.css';
|
||||
|
||||
.root {
|
||||
margin-top: 48px;
|
||||
}
|
||||
|
||||
.disabled {
|
||||
|
|
@ -38,6 +39,20 @@
|
|||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.radioButtonRow {
|
||||
display: flex;
|
||||
justify-content: left;
|
||||
flex-shrink: 0;
|
||||
flex-wrap: wrap;
|
||||
width: 100%;
|
||||
margin-bottom: 24px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.radioButtonRow > :first-child {
|
||||
margin-right: 36px;
|
||||
}
|
||||
|
||||
.field {
|
||||
width: 100%;
|
||||
}
|
||||
|
|
@ -64,6 +79,10 @@
|
|||
width: calc(60% - 9px);
|
||||
}
|
||||
|
||||
.taxId {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.error {
|
||||
@apply --marketplaceModalErrorStyles;
|
||||
}
|
||||
|
|
@ -86,3 +105,60 @@
|
|||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.bankDetailsStripeField p {
|
||||
@apply --marketplaceH4FontStyles;
|
||||
}
|
||||
|
||||
.personalAddressContainer {
|
||||
margin-bottom: 28px;
|
||||
}
|
||||
|
||||
.fieldArrayAdd {
|
||||
@apply --marketplaceLinkStyles;
|
||||
@apply --marketplaceSearchFilterSublabelFontStyles;
|
||||
font-weight: var(--fontWeightMedium);
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.fieldArrayRemove {
|
||||
@apply --marketplaceH5FontStyles;
|
||||
color: var(--matterColorAnti);
|
||||
float: right;
|
||||
line-height: 20px;
|
||||
|
||||
&:hover {
|
||||
color: var(--matterColor);
|
||||
}
|
||||
}
|
||||
|
||||
.closeIcon {
|
||||
@apply --marketplaceModalCloseIcon;
|
||||
}
|
||||
|
||||
.additionalOwnerWrapper {
|
||||
margin-bottom: 35px;
|
||||
|
||||
@media (--viewportMedium) {
|
||||
margin-bottom: 56px;
|
||||
}
|
||||
}
|
||||
|
||||
.additionalOwnerWrapper .sectionContainer {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.additionalOwnerLabel {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.closeIcon {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.addIcon {
|
||||
margin-right: 7px;
|
||||
display: inline-block;
|
||||
height: 18px;
|
||||
padding-top: 1px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,25 +3,17 @@ import { bool, object, string } from 'prop-types';
|
|||
import { compose } from 'redux';
|
||||
import { FormattedMessage, injectIntl, intlShape } from 'react-intl';
|
||||
import { Form as FinalForm } from 'react-final-form';
|
||||
import arrayMutators from 'final-form-arrays';
|
||||
import classNames from 'classnames';
|
||||
import config from '../../config';
|
||||
import {
|
||||
Button,
|
||||
ExternalLink,
|
||||
StripeBankAccountTokenInputField,
|
||||
FieldSelect,
|
||||
FieldBirthdayInput,
|
||||
FieldTextInput,
|
||||
Form,
|
||||
} from '../../components';
|
||||
import * as validators from '../../util/validators';
|
||||
import { Button, ExternalLink, FieldRadioButton, FieldSelect, Form } from '../../components';
|
||||
import { isStripeInvalidPostalCode } from '../../util/errors';
|
||||
import * as validators from '../../util/validators';
|
||||
|
||||
import PayoutDetailsAddress from './PayoutDetailsAddress';
|
||||
import PayoutDetailsFormCompany from './PayoutDetailsFormCompany';
|
||||
import PayoutDetailsFormIndividual from './PayoutDetailsFormIndividual';
|
||||
import css from './PayoutDetailsForm.css';
|
||||
|
||||
const MIN_STRIPE_ACCOUNT_AGE = 18;
|
||||
|
||||
const supportedCountries = config.stripe.supportedCountries.map(c => c.code);
|
||||
|
||||
export const stripeCountryConfigs = countryCode => {
|
||||
|
|
@ -33,20 +25,17 @@ export const stripeCountryConfigs = countryCode => {
|
|||
return country;
|
||||
};
|
||||
|
||||
const countryCurrency = countryCode => {
|
||||
const country = stripeCountryConfigs(countryCode);
|
||||
return country.currency;
|
||||
};
|
||||
|
||||
const PayoutDetailsFormComponent = props => (
|
||||
<FinalForm
|
||||
{...props}
|
||||
mutators={{
|
||||
...arrayMutators,
|
||||
}}
|
||||
render={fieldRenderProps => {
|
||||
const {
|
||||
className,
|
||||
createStripeAccountError,
|
||||
disabled,
|
||||
form,
|
||||
handleSubmit,
|
||||
inProgress,
|
||||
intl,
|
||||
|
|
@ -56,49 +45,14 @@ const PayoutDetailsFormComponent = props => (
|
|||
submitButtonText,
|
||||
values,
|
||||
} = fieldRenderProps;
|
||||
const { country } = values;
|
||||
|
||||
const firstNameLabel = intl.formatMessage({ id: 'PayoutDetailsForm.firstNameLabel' });
|
||||
const firstNamePlaceholder = intl.formatMessage({
|
||||
id: 'PayoutDetailsForm.firstNamePlaceholder',
|
||||
});
|
||||
const firstNameRequired = validators.required(
|
||||
intl.formatMessage({
|
||||
id: 'PayoutDetailsForm.firstNameRequired',
|
||||
})
|
||||
);
|
||||
const { country, accountType } = values;
|
||||
|
||||
const lastNameLabel = intl.formatMessage({ id: 'PayoutDetailsForm.lastNameLabel' });
|
||||
const lastNamePlaceholder = intl.formatMessage({
|
||||
id: 'PayoutDetailsForm.lastNamePlaceholder',
|
||||
const individualAccountLabel = intl.formatMessage({
|
||||
id: 'PayoutDetailsForm.individualAccount',
|
||||
});
|
||||
const lastNameRequired = validators.required(
|
||||
intl.formatMessage({
|
||||
id: 'PayoutDetailsForm.lastNameRequired',
|
||||
})
|
||||
);
|
||||
|
||||
const birthdayLabel = intl.formatMessage({ id: 'PayoutDetailsForm.birthdayLabel' });
|
||||
const birthdayLabelMonth = intl.formatMessage({
|
||||
id: 'PayoutDetailsForm.birthdayLabelMonth',
|
||||
});
|
||||
const birthdayLabelYear = intl.formatMessage({ id: 'PayoutDetailsForm.birthdayLabelYear' });
|
||||
const birthdayRequired = validators.required(
|
||||
intl.formatMessage({
|
||||
id: 'PayoutDetailsForm.birthdayRequired',
|
||||
})
|
||||
);
|
||||
const birthdayMinAge = validators.ageAtLeast(
|
||||
intl.formatMessage(
|
||||
{
|
||||
id: 'PayoutDetailsForm.birthdayMinAge',
|
||||
},
|
||||
{
|
||||
minAge: MIN_STRIPE_ACCOUNT_AGE,
|
||||
}
|
||||
),
|
||||
MIN_STRIPE_ACCOUNT_AGE
|
||||
);
|
||||
const companyAccountLabel = intl.formatMessage({ id: 'PayoutDetailsForm.companyAccount' });
|
||||
|
||||
const countryLabel = intl.formatMessage({ id: 'PayoutDetailsForm.countryLabel' });
|
||||
const countryPlaceholder = intl.formatMessage({
|
||||
|
|
@ -110,59 +64,16 @@ const PayoutDetailsFormComponent = props => (
|
|||
})
|
||||
);
|
||||
|
||||
// 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.
|
||||
const bankAccountRequired = validators.required(' ');
|
||||
|
||||
const showPersonalIdNumber =
|
||||
(country && stripeCountryConfigs(country).personalIdNumberRequired) ||
|
||||
(country && stripeCountryConfigs(country).ssnLast4Required);
|
||||
|
||||
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`,
|
||||
})
|
||||
);
|
||||
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`,
|
||||
})
|
||||
);
|
||||
personalIdNumberValid = validators.composeValidators(personalIdNumberRequired, validHKID);
|
||||
}
|
||||
|
||||
const classes = classNames(css.root, className, {
|
||||
[css.disabled]: disabled,
|
||||
});
|
||||
|
||||
const submitInProgress = inProgress;
|
||||
const submitDisabled = pristine || invalid || disabled || submitInProgress;
|
||||
const showAsRequired = pristine;
|
||||
|
||||
const showIndividual = country && accountType && accountType === 'individual';
|
||||
const showCompany = country && accountType && accountType === 'company';
|
||||
|
||||
let error = null;
|
||||
|
||||
|
|
@ -185,130 +96,87 @@ const PayoutDetailsFormComponent = props => (
|
|||
<FormattedMessage id="PayoutDetailsForm.stripeConnectedAccountTermsLink" />
|
||||
</ExternalLink>
|
||||
);
|
||||
|
||||
return (
|
||||
<Form className={classes} onSubmit={handleSubmit}>
|
||||
<div className={css.sectionContainer}>
|
||||
<h3 className={css.subTitle}>
|
||||
<FormattedMessage id="PayoutDetailsForm.personalDetailsTitle" />
|
||||
<FormattedMessage id="PayoutDetailsForm.accountTypeTitle" />
|
||||
</h3>
|
||||
<div className={css.formRow}>
|
||||
<FieldTextInput
|
||||
id="fname"
|
||||
name="fname"
|
||||
disabled={disabled}
|
||||
className={css.firstName}
|
||||
type="text"
|
||||
autoComplete="given-name"
|
||||
label={firstNameLabel}
|
||||
placeholder={firstNamePlaceholder}
|
||||
validate={firstNameRequired}
|
||||
<div className={css.radioButtonRow}>
|
||||
<FieldRadioButton
|
||||
id="individual"
|
||||
name="accountType"
|
||||
label={individualAccountLabel}
|
||||
value="individual"
|
||||
showAsRequired={showAsRequired}
|
||||
/>
|
||||
<FieldTextInput
|
||||
id="lname"
|
||||
name="lname"
|
||||
disabled={disabled}
|
||||
className={css.lastName}
|
||||
type="text"
|
||||
autoComplete="family-name"
|
||||
label={lastNameLabel}
|
||||
placeholder={lastNamePlaceholder}
|
||||
validate={lastNameRequired}
|
||||
<FieldRadioButton
|
||||
id="company"
|
||||
name="accountType"
|
||||
label={companyAccountLabel}
|
||||
value="company"
|
||||
showAsRequired={showAsRequired}
|
||||
/>
|
||||
</div>
|
||||
<FieldBirthdayInput
|
||||
id="birthDate"
|
||||
name="birthDate"
|
||||
disabled={disabled}
|
||||
className={css.field}
|
||||
label={birthdayLabel}
|
||||
labelForMonth={birthdayLabelMonth}
|
||||
labelForYear={birthdayLabelYear}
|
||||
format={null}
|
||||
valueFromForm={values.birthDate}
|
||||
validate={validators.composeValidators(birthdayRequired, birthdayMinAge)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={css.sectionContainer}>
|
||||
<h3 className={css.subTitle}>
|
||||
<FormattedMessage id="PayoutDetailsForm.addressTitle" />
|
||||
</h3>
|
||||
<FieldSelect
|
||||
id="country"
|
||||
name="country"
|
||||
disabled={disabled}
|
||||
className={css.selectCountry}
|
||||
autoComplete="country"
|
||||
label={countryLabel}
|
||||
validate={countryRequired}
|
||||
>
|
||||
<option disabled value="">
|
||||
{countryPlaceholder}
|
||||
</option>
|
||||
{supportedCountries.map(c => (
|
||||
<option key={c} value={c}>
|
||||
{intl.formatMessage({ id: `PayoutDetailsForm.countryNames.${c}` })}
|
||||
</option>
|
||||
))}
|
||||
</FieldSelect>
|
||||
{accountType ? (
|
||||
<React.Fragment>
|
||||
<div className={css.sectionContainer}>
|
||||
<h3 className={css.subTitle}>Country</h3>
|
||||
<FieldSelect
|
||||
id="country"
|
||||
name="country"
|
||||
disabled={disabled}
|
||||
className={css.selectCountry}
|
||||
autoComplete="country"
|
||||
label={countryLabel}
|
||||
validate={countryRequired}
|
||||
>
|
||||
<option disabled value="">
|
||||
{countryPlaceholder}
|
||||
</option>
|
||||
{supportedCountries.map(c => (
|
||||
<option key={c} value={c}>
|
||||
{intl.formatMessage({ id: `PayoutDetailsForm.countryNames.${c}` })}
|
||||
</option>
|
||||
))}
|
||||
</FieldSelect>
|
||||
</div>
|
||||
|
||||
<PayoutDetailsAddress country={country} intl={intl} disabled={disabled} form={form} />
|
||||
</div>
|
||||
{country ? (
|
||||
<div className={css.sectionContainer}>
|
||||
<h3 className={css.subTitle}>
|
||||
<FormattedMessage id="PayoutDetailsForm.bankDetails" />
|
||||
</h3>
|
||||
<StripeBankAccountTokenInputField
|
||||
disabled={disabled}
|
||||
name="bankAccountToken"
|
||||
formName="PayoutDetailsForm"
|
||||
country={country}
|
||||
currency={countryCurrency(country)}
|
||||
validate={bankAccountRequired}
|
||||
/>
|
||||
</div>
|
||||
{showIndividual ? (
|
||||
<PayoutDetailsFormIndividual
|
||||
fieldRenderProps={fieldRenderProps}
|
||||
country={country}
|
||||
/>
|
||||
) : showCompany ? (
|
||||
<PayoutDetailsFormCompany fieldRenderProps={fieldRenderProps} country={country} />
|
||||
) : null}
|
||||
|
||||
{error}
|
||||
|
||||
<p className={css.termsText}>
|
||||
<FormattedMessage
|
||||
id="PayoutDetailsForm.stripeToSText"
|
||||
values={{ stripeConnectedAccountTermsLink }}
|
||||
/>
|
||||
</p>
|
||||
<Button
|
||||
className={css.submitButton}
|
||||
type="submit"
|
||||
inProgress={submitInProgress}
|
||||
disabled={submitDisabled}
|
||||
ready={ready}
|
||||
>
|
||||
{submitButtonText ? (
|
||||
submitButtonText
|
||||
) : (
|
||||
<FormattedMessage id="PayoutDetailsForm.submitButtonText" />
|
||||
)}
|
||||
</Button>
|
||||
</React.Fragment>
|
||||
) : null}
|
||||
|
||||
{showPersonalIdNumber ? (
|
||||
<div className={css.sectionContainer}>
|
||||
<h3 className={css.subTitle}>
|
||||
<FormattedMessage id="PayoutDetailsForm.personalIdNumberTitle" />
|
||||
</h3>
|
||||
<FieldTextInput
|
||||
id="personalIdNumber"
|
||||
name="personalIdNumber"
|
||||
disabled={disabled}
|
||||
className={css.personalIdNumber}
|
||||
type="text"
|
||||
label={personalIdNumberLabel}
|
||||
placeholder={personalIdNumberPlaceholder}
|
||||
validate={personalIdNumberValid}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{error}
|
||||
|
||||
<p className={css.termsText}>
|
||||
<FormattedMessage
|
||||
id="PayoutDetailsForm.stripeToSText"
|
||||
values={{ stripeConnectedAccountTermsLink }}
|
||||
/>
|
||||
</p>
|
||||
<Button
|
||||
className={css.submitButton}
|
||||
type="submit"
|
||||
inProgress={submitInProgress}
|
||||
disabled={submitDisabled}
|
||||
ready={ready}
|
||||
>
|
||||
{submitButtonText ? (
|
||||
submitButtonText
|
||||
) : (
|
||||
<FormattedMessage id="PayoutDetailsForm.submitButtonText" />
|
||||
)}
|
||||
</Button>
|
||||
</Form>
|
||||
);
|
||||
}}
|
||||
|
|
|
|||
211
src/forms/PayoutDetailsForm/PayoutDetailsFormCompany.js
Normal file
211
src/forms/PayoutDetailsForm/PayoutDetailsFormCompany.js
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
import React from 'react';
|
||||
import { bool, string } from 'prop-types';
|
||||
import { compose } from 'redux';
|
||||
import { FormattedMessage, injectIntl, intlShape } from 'react-intl';
|
||||
import { FieldArray } from 'react-final-form-arrays';
|
||||
import { FieldTextInput, IconAdd, IconClose, InlineTextButton } from '../../components';
|
||||
import * as validators from '../../util/validators';
|
||||
|
||||
import PayoutDetailsAddress from './PayoutDetailsAddress';
|
||||
import PayoutDetailsBankDetails from './PayoutDetailsBankDetails';
|
||||
import PayoutDetailsPersonalDetails from './PayoutDetailsPersonalDetails';
|
||||
import { stripeCountryConfigs } from './PayoutDetailsForm';
|
||||
import css from './PayoutDetailsForm.css';
|
||||
|
||||
// In EU, there can be a maximum of 4 additional owners
|
||||
const MAX_NUMBER_OF_ADDITIONAL_OWNERS = 4;
|
||||
|
||||
const PayoutDetailsFormCompanyComponent = ({ fieldRenderProps }) => {
|
||||
const {
|
||||
id,
|
||||
disabled,
|
||||
form,
|
||||
intl,
|
||||
values,
|
||||
form: {
|
||||
mutators: { push },
|
||||
},
|
||||
} = fieldRenderProps;
|
||||
const { country } = values;
|
||||
|
||||
const companyNameLabel = intl.formatMessage({ id: 'PayoutDetailsForm.companyNameLabel' });
|
||||
const companyNamePlaceholder = intl.formatMessage({
|
||||
id: 'PayoutDetailsForm.companyNamePlaceholder',
|
||||
});
|
||||
const companyNameRequired = validators.required(
|
||||
intl.formatMessage({
|
||||
id: 'PayoutDetailsForm.companyNameRequired',
|
||||
})
|
||||
);
|
||||
|
||||
const companyTaxIdLabel = intl.formatMessage({
|
||||
id: `PayoutDetailsForm.companyTaxIdLabel.${country}`,
|
||||
});
|
||||
const companyTaxIdPlaceholder = intl.formatMessage(
|
||||
{
|
||||
id: 'PayoutDetailsForm.companyTaxIdPlaceholder',
|
||||
},
|
||||
{
|
||||
idName: companyTaxIdLabel,
|
||||
}
|
||||
);
|
||||
const companyTaxIdRequired = validators.required(
|
||||
intl.formatMessage(
|
||||
{
|
||||
id: 'PayoutDetailsForm.companyTaxIdRequired',
|
||||
},
|
||||
{
|
||||
idName: companyTaxIdLabel,
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
const showPersonalAddressField =
|
||||
country &&
|
||||
stripeCountryConfigs(country).companyConfig &&
|
||||
stripeCountryConfigs(country).companyConfig.personalAddress;
|
||||
|
||||
const showAdditionalOwnersField =
|
||||
country &&
|
||||
stripeCountryConfigs(country).companyConfig &&
|
||||
stripeCountryConfigs(country).companyConfig.additionalOwners;
|
||||
|
||||
const hasAdditionalOwners = values.company && values.company.additionalOwners;
|
||||
const hasMaxNumberOfAdditionalOwners =
|
||||
hasAdditionalOwners &&
|
||||
values.company.additionalOwners.length >= MAX_NUMBER_OF_ADDITIONAL_OWNERS;
|
||||
return (
|
||||
<React.Fragment>
|
||||
{country ? (
|
||||
<React.Fragment>
|
||||
<div className={css.sectionContainer}>
|
||||
<h3 className={css.subTitle}>
|
||||
<FormattedMessage id="PayoutDetailsForm.companyDetailsTitle" />
|
||||
</h3>
|
||||
<FieldTextInput
|
||||
id="company.companyName"
|
||||
name="company.companyName"
|
||||
disabled={disabled}
|
||||
type="text"
|
||||
autoComplete="company-name"
|
||||
label={companyNameLabel}
|
||||
placeholder={companyNamePlaceholder}
|
||||
validate={companyNameRequired}
|
||||
/>
|
||||
|
||||
<FieldTextInput
|
||||
id="company.companyTaxId"
|
||||
name="company.companyTaxId"
|
||||
className={css.taxId}
|
||||
disabled={disabled}
|
||||
type="text"
|
||||
autoComplete="company-tax-id"
|
||||
label={companyTaxIdLabel}
|
||||
placeholder={companyTaxIdPlaceholder}
|
||||
validate={companyTaxIdRequired}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<PayoutDetailsAddress
|
||||
country={country}
|
||||
intl={intl}
|
||||
disabled={disabled}
|
||||
form={form}
|
||||
fieldId="company.address"
|
||||
/>
|
||||
|
||||
<PayoutDetailsBankDetails country={country} disabled={disabled} fieldId="company" />
|
||||
|
||||
<PayoutDetailsPersonalDetails
|
||||
intl={intl}
|
||||
disabled={disabled}
|
||||
values={values}
|
||||
country={country}
|
||||
fieldId="company"
|
||||
/>
|
||||
|
||||
{showPersonalAddressField ? (
|
||||
<PayoutDetailsAddress
|
||||
className={css.personalAddressContainer}
|
||||
country={country}
|
||||
intl={intl}
|
||||
disabled={disabled}
|
||||
form={form}
|
||||
fieldId="company.personalAddress"
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{showAdditionalOwnersField ? (
|
||||
<div className={css.additionalOwnerWrapper}>
|
||||
<FieldArray id={id} name={'company.additionalOwners'}>
|
||||
{({ fields }) =>
|
||||
fields.map((name, index) => (
|
||||
<div className={css.additionalOwnerWrapper} key={name}>
|
||||
<div
|
||||
className={css.fieldArrayRemove}
|
||||
onClick={() => fields.remove(index)}
|
||||
style={{ cursor: 'pointer' }}
|
||||
>
|
||||
<span className={css.additionalOwnerLabel}>
|
||||
<IconClose rootClassName={css.closeIcon} size="small" />
|
||||
<FormattedMessage id="PayoutDetailsForm.additionalOwnerRemove" />
|
||||
</span>
|
||||
</div>
|
||||
<PayoutDetailsPersonalDetails
|
||||
intl={intl}
|
||||
disabled={disabled}
|
||||
values={values}
|
||||
country={country}
|
||||
fieldId={`company.additionalOwners.${index}`}
|
||||
/>
|
||||
{showPersonalAddressField ? (
|
||||
<PayoutDetailsAddress
|
||||
className={css.personalAddressContainer}
|
||||
country={country}
|
||||
intl={intl}
|
||||
disabled={disabled}
|
||||
form={form}
|
||||
fieldId={`company.additionalOwners.${index}`}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</FieldArray>
|
||||
|
||||
{!hasAdditionalOwners || !hasMaxNumberOfAdditionalOwners ? (
|
||||
<InlineTextButton
|
||||
type="button"
|
||||
className={css.fieldArrayAdd}
|
||||
onClick={() => push('company.additionalOwners', undefined)}
|
||||
>
|
||||
<span className={css.additionalOwnerLabel}>
|
||||
<IconAdd rootClassName={css.addIcon} />
|
||||
<FormattedMessage id="PayoutDetailsForm.additionalOwnerLabel" />
|
||||
</span>
|
||||
</InlineTextButton>
|
||||
) : null}
|
||||
</div>
|
||||
) : null}
|
||||
</React.Fragment>
|
||||
) : null}
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
PayoutDetailsFormCompanyComponent.defaultProps = {
|
||||
id: null,
|
||||
disabled: false,
|
||||
};
|
||||
|
||||
PayoutDetailsFormCompanyComponent.propTypes = {
|
||||
id: string,
|
||||
disabled: bool,
|
||||
|
||||
// from injectIntl
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
const PayoutDetailsFormCompany = compose(injectIntl)(PayoutDetailsFormCompanyComponent);
|
||||
|
||||
export default PayoutDetailsFormCompany;
|
||||
48
src/forms/PayoutDetailsForm/PayoutDetailsFormIndividual.js
Normal file
48
src/forms/PayoutDetailsForm/PayoutDetailsFormIndividual.js
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
import React from 'react';
|
||||
import { bool } from 'prop-types';
|
||||
import { compose } from 'redux';
|
||||
import { injectIntl, intlShape } from 'react-intl';
|
||||
|
||||
import PayoutDetailsAddress from './PayoutDetailsAddress';
|
||||
import PayoutDetailsBankDetails from './PayoutDetailsBankDetails';
|
||||
import PayoutDetailsPersonalDetails from './PayoutDetailsPersonalDetails';
|
||||
|
||||
const PayoutDetailsFormIndividualComponent = ({ fieldRenderProps }) => {
|
||||
const { disabled, form, intl, values } = fieldRenderProps;
|
||||
const { country } = values;
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<PayoutDetailsPersonalDetails
|
||||
intl={intl}
|
||||
disabled={disabled}
|
||||
values={values}
|
||||
country={country}
|
||||
fieldId="individual"
|
||||
/>
|
||||
<PayoutDetailsAddress
|
||||
country={country}
|
||||
intl={intl}
|
||||
disabled={disabled}
|
||||
form={form}
|
||||
fieldId="individual.address"
|
||||
/>
|
||||
<PayoutDetailsBankDetails country={country} disabled={disabled} fieldId="individual" />
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
PayoutDetailsFormIndividualComponent.defaultProps = {
|
||||
disabled: false,
|
||||
};
|
||||
|
||||
PayoutDetailsFormIndividualComponent.propTypes = {
|
||||
disabled: bool,
|
||||
|
||||
// from injectIntl
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
const PayoutDetailsFormIndividual = compose(injectIntl)(PayoutDetailsFormIndividualComponent);
|
||||
|
||||
export default PayoutDetailsFormIndividual;
|
||||
177
src/forms/PayoutDetailsForm/PayoutDetailsPersonalDetails.js
Normal file
177
src/forms/PayoutDetailsForm/PayoutDetailsPersonalDetails.js
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
import React from 'react';
|
||||
import { bool, string } from 'prop-types';
|
||||
import { FieldBirthdayInput, FieldTextInput } from '../../components';
|
||||
import * as validators from '../../util/validators';
|
||||
import { intlShape } from 'react-intl';
|
||||
|
||||
import { stripeCountryConfigs } from './PayoutDetailsForm';
|
||||
import css from './PayoutDetailsForm.css';
|
||||
|
||||
const MIN_STRIPE_ACCOUNT_AGE = 18;
|
||||
|
||||
const PayoutDetailsPersonalDetails = props => {
|
||||
const { intl, disabled, values, country, fieldId } = props;
|
||||
|
||||
const personalDetailsTitle = intl.formatMessage({
|
||||
id:
|
||||
fieldId === 'company' || fieldId === 'individual'
|
||||
? 'PayoutDetailsForm.personalDetailsTitle'
|
||||
: 'PayoutDetailsForm.personalDetailsAdditionalOwnerTitle',
|
||||
});
|
||||
|
||||
const firstNameLabel = intl.formatMessage({ id: 'PayoutDetailsForm.firstNameLabel' });
|
||||
const firstNamePlaceholder = intl.formatMessage({
|
||||
id: 'PayoutDetailsForm.firstNamePlaceholder',
|
||||
});
|
||||
const firstNameRequired = validators.required(
|
||||
intl.formatMessage({
|
||||
id: 'PayoutDetailsForm.firstNameRequired',
|
||||
})
|
||||
);
|
||||
|
||||
const lastNameLabel = intl.formatMessage({ id: 'PayoutDetailsForm.lastNameLabel' });
|
||||
const lastNamePlaceholder = intl.formatMessage({
|
||||
id: 'PayoutDetailsForm.lastNamePlaceholder',
|
||||
});
|
||||
const lastNameRequired = validators.required(
|
||||
intl.formatMessage({
|
||||
id: 'PayoutDetailsForm.lastNameRequired',
|
||||
})
|
||||
);
|
||||
|
||||
const birthdayLabel = intl.formatMessage({ id: 'PayoutDetailsForm.birthdayLabel' });
|
||||
const birthdayLabelMonth = intl.formatMessage({
|
||||
id: 'PayoutDetailsForm.birthdayLabelMonth',
|
||||
});
|
||||
const birthdayLabelYear = intl.formatMessage({ id: 'PayoutDetailsForm.birthdayLabelYear' });
|
||||
const birthdayRequired = validators.required(
|
||||
intl.formatMessage({
|
||||
id: 'PayoutDetailsForm.birthdayRequired',
|
||||
})
|
||||
);
|
||||
const birthdayMinAge = validators.ageAtLeast(
|
||||
intl.formatMessage(
|
||||
{
|
||||
id: 'PayoutDetailsForm.birthdayMinAge',
|
||||
},
|
||||
{
|
||||
minAge: MIN_STRIPE_ACCOUNT_AGE,
|
||||
}
|
||||
),
|
||||
MIN_STRIPE_ACCOUNT_AGE
|
||||
);
|
||||
|
||||
const showPersonalIdNumber =
|
||||
(country && stripeCountryConfigs(country).personalIdNumberRequired) ||
|
||||
(country && stripeCountryConfigs(country).ssnLast4Required);
|
||||
|
||||
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`,
|
||||
})
|
||||
);
|
||||
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`,
|
||||
})
|
||||
);
|
||||
personalIdNumberValid = validators.composeValidators(personalIdNumberRequired, validHKID);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={css.sectionContainer}>
|
||||
<h3 className={css.subTitle}>{personalDetailsTitle}</h3>
|
||||
<div className={css.formRow}>
|
||||
<FieldTextInput
|
||||
id={`${fieldId}.firstName`}
|
||||
name={`${fieldId}.firstName`}
|
||||
disabled={disabled}
|
||||
className={css.firstName}
|
||||
type="text"
|
||||
autoComplete="given-name"
|
||||
label={firstNameLabel}
|
||||
placeholder={firstNamePlaceholder}
|
||||
validate={firstNameRequired}
|
||||
/>
|
||||
<FieldTextInput
|
||||
id={`${fieldId}.lastName`}
|
||||
name={`${fieldId}.lastName`}
|
||||
disabled={disabled}
|
||||
className={css.lastName}
|
||||
type="text"
|
||||
autoComplete="family-name"
|
||||
label={lastNameLabel}
|
||||
placeholder={lastNamePlaceholder}
|
||||
validate={lastNameRequired}
|
||||
/>
|
||||
</div>
|
||||
<div className={css.formRow}>
|
||||
<FieldBirthdayInput
|
||||
id={`${fieldId}.birthDate`}
|
||||
name={`${fieldId}.birthDate`}
|
||||
disabled={disabled}
|
||||
className={css.field}
|
||||
label={birthdayLabel}
|
||||
labelForMonth={birthdayLabelMonth}
|
||||
labelForYear={birthdayLabelYear}
|
||||
format={null}
|
||||
valueFromForm={values.birthDate}
|
||||
validate={validators.composeValidators(birthdayRequired, birthdayMinAge)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{showPersonalIdNumber ? (
|
||||
<FieldTextInput
|
||||
id={`${fieldId}.personalIdNumber`}
|
||||
name={`${fieldId}.personalIdNumber`}
|
||||
disabled={disabled}
|
||||
className={css.personalIdNumber}
|
||||
type="text"
|
||||
label={personalIdNumberLabel}
|
||||
placeholder={personalIdNumberPlaceholder}
|
||||
validate={personalIdNumberValid}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
PayoutDetailsPersonalDetails.defaultProps = {
|
||||
country: null,
|
||||
disabled: false,
|
||||
fieldId: null,
|
||||
};
|
||||
|
||||
PayoutDetailsPersonalDetails.propTypes = {
|
||||
country: string,
|
||||
disabled: bool,
|
||||
fieldId: string,
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
export default PayoutDetailsPersonalDetails;
|
||||
|
|
@ -38,6 +38,10 @@ export const stripeSupportedCountries = [
|
|||
accountConfig: {
|
||||
iban: true,
|
||||
},
|
||||
companyConfig: {
|
||||
personalAddress: true,
|
||||
additionalOwners: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
// Belgium
|
||||
|
|
@ -51,6 +55,10 @@ export const stripeSupportedCountries = [
|
|||
accountConfig: {
|
||||
iban: true,
|
||||
},
|
||||
companyConfig: {
|
||||
personalAddress: true,
|
||||
additionalOwners: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
// Canada
|
||||
|
|
@ -80,6 +88,10 @@ export const stripeSupportedCountries = [
|
|||
accountConfig: {
|
||||
iban: true,
|
||||
},
|
||||
companyConfig: {
|
||||
personalAddress: true,
|
||||
additionalOwners: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
// Finland
|
||||
|
|
@ -93,6 +105,10 @@ export const stripeSupportedCountries = [
|
|||
accountConfig: {
|
||||
iban: true,
|
||||
},
|
||||
companyConfig: {
|
||||
personalAddress: true,
|
||||
additionalOwners: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
// France
|
||||
|
|
@ -106,6 +122,10 @@ export const stripeSupportedCountries = [
|
|||
accountConfig: {
|
||||
iban: true,
|
||||
},
|
||||
companyConfig: {
|
||||
personalAddress: true,
|
||||
additionalOwners: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
// Germany
|
||||
|
|
@ -119,6 +139,10 @@ export const stripeSupportedCountries = [
|
|||
accountConfig: {
|
||||
iban: true,
|
||||
},
|
||||
companyConfig: {
|
||||
personalAddress: true,
|
||||
additionalOwners: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
// Hong Kong
|
||||
|
|
@ -134,6 +158,9 @@ export const stripeSupportedCountries = [
|
|||
accountNumber: true,
|
||||
},
|
||||
personalIdNumberRequired: true,
|
||||
companyConfig: {
|
||||
personalAddress: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
// Ireland
|
||||
|
|
@ -147,6 +174,10 @@ export const stripeSupportedCountries = [
|
|||
accountConfig: {
|
||||
iban: true,
|
||||
},
|
||||
companyConfig: {
|
||||
personalAddress: true,
|
||||
additionalOwners: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
// Italy
|
||||
|
|
@ -160,6 +191,10 @@ export const stripeSupportedCountries = [
|
|||
accountConfig: {
|
||||
iban: true,
|
||||
},
|
||||
companyConfig: {
|
||||
personalAddress: true,
|
||||
additionalOwners: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
// Luxembourg
|
||||
|
|
@ -173,6 +208,10 @@ export const stripeSupportedCountries = [
|
|||
accountConfig: {
|
||||
iban: true,
|
||||
},
|
||||
companyConfig: {
|
||||
personalAddress: true,
|
||||
additionalOwners: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
// Netherlands
|
||||
|
|
@ -186,6 +225,10 @@ export const stripeSupportedCountries = [
|
|||
accountConfig: {
|
||||
iban: true,
|
||||
},
|
||||
companyConfig: {
|
||||
personalAddress: true,
|
||||
additionalOwners: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
// New Zealand
|
||||
|
|
@ -212,6 +255,10 @@ export const stripeSupportedCountries = [
|
|||
accountConfig: {
|
||||
iban: true,
|
||||
},
|
||||
companyConfig: {
|
||||
personalAddress: true,
|
||||
additionalOwners: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
// Portugal
|
||||
|
|
@ -225,6 +272,10 @@ export const stripeSupportedCountries = [
|
|||
accountConfig: {
|
||||
iban: true,
|
||||
},
|
||||
companyConfig: {
|
||||
personalAddress: true,
|
||||
additionalOwners: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
// Spain
|
||||
|
|
@ -238,6 +289,10 @@ export const stripeSupportedCountries = [
|
|||
accountConfig: {
|
||||
iban: true,
|
||||
},
|
||||
companyConfig: {
|
||||
personalAddress: true,
|
||||
additionalOwners: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
// Sweden
|
||||
|
|
@ -251,6 +306,10 @@ export const stripeSupportedCountries = [
|
|||
accountConfig: {
|
||||
iban: true,
|
||||
},
|
||||
companyConfig: {
|
||||
personalAddress: true,
|
||||
additionalOwners: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
// Switzerland
|
||||
|
|
@ -264,6 +323,10 @@ export const stripeSupportedCountries = [
|
|||
accountConfig: {
|
||||
iban: true,
|
||||
},
|
||||
companyConfig: {
|
||||
personalAddress: true,
|
||||
additionalOwners: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
// United Kingdom
|
||||
|
|
@ -278,6 +341,10 @@ export const stripeSupportedCountries = [
|
|||
sortCode: true,
|
||||
accountNumber: true,
|
||||
},
|
||||
companyConfig: {
|
||||
personalAddress: true,
|
||||
additionalOwners: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
// United States
|
||||
|
|
|
|||
|
|
@ -452,6 +452,9 @@
|
|||
"PasswordResetPage.recoveryLinkText": "password recovery page",
|
||||
"PasswordResetPage.resetFailed": "Reset failed. Please try again.",
|
||||
"PasswordResetPage.title": "Reset password",
|
||||
"PayoutDetailsForm.accountTypeTitle": "Account type",
|
||||
"PayoutDetailsForm.additionalOwnerLabel": "Add additional owner",
|
||||
"PayoutDetailsForm.additionalOwnerRemove": "Remove additional owner",
|
||||
"PayoutDetailsForm.addressTitle": "Address",
|
||||
"PayoutDetailsForm.bankDetails": "Bank details",
|
||||
"PayoutDetailsForm.birthdayDatePlaceholder": "dd",
|
||||
|
|
@ -481,6 +484,35 @@
|
|||
"PayoutDetailsForm.cityLabel": "City",
|
||||
"PayoutDetailsForm.cityPlaceholder": "Helsinki",
|
||||
"PayoutDetailsForm.cityRequired": "This field is required",
|
||||
"PayoutDetailsForm.companyAccount": "I represent a company",
|
||||
"PayoutDetailsForm.companyAddressTitle": "Company address",
|
||||
"PayoutDetailsForm.companyDetailsTitle": "Company details",
|
||||
"PayoutDetailsForm.companyNameLabel": "Company name",
|
||||
"PayoutDetailsForm.companyNamePlaceholder": "Enter company name...",
|
||||
"PayoutDetailsForm.companyNameRequired": "Company name is required",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.AT": "Firmenbuchnummer (FN)",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.AU": "Company ACN/ABN - TFN",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.BE": "TVA/BTW/CBE",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.CA": "Business Number (Tax ID)",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.CH": "VAT number UID/MWST/TVA/IVA",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.DE": "Handelsregisternummer (HRB) ",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.DK": "Momsregistreringsnummer (CVR)",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.ES": "Número de Identificación Fiscal (NIF)",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.FI": "Y-tunnus",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.FR": "Numéro SIREN",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.GB": "Companies House Registration Number (CRN)",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.HK": "Registration Number",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.IE": "Company Number",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.IT": "Numero RI/ REA",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.LU": "Company/RCS number",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.NL": "KVK number",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.NO": "Organisasjonsnummer (Orgnr)",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.NZ": "NZBN",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.PT": "N.º Contribuinte",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.SE": "Organisationsnummer",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.US": "Tax ID",
|
||||
"PayoutDetailsForm.companyTaxIdPlaceholder": "Enter {idName}...",
|
||||
"PayoutDetailsForm.companyTaxIdRequired": "{idName} is required",
|
||||
"PayoutDetailsForm.countryLabel": "Country",
|
||||
"PayoutDetailsForm.countryNames.AT": "Austria",
|
||||
"PayoutDetailsForm.countryNames.AU": "Australia",
|
||||
|
|
@ -510,10 +542,12 @@
|
|||
"PayoutDetailsForm.firstNameLabel": "First name",
|
||||
"PayoutDetailsForm.firstNamePlaceholder": "John",
|
||||
"PayoutDetailsForm.firstNameRequired": "This field is required",
|
||||
"PayoutDetailsForm.individualAccount": "I'm an individual",
|
||||
"PayoutDetailsForm.information": "Since this was your first listing, we need to know bit more about you in order to send you money. We only ask these once.",
|
||||
"PayoutDetailsForm.lastNameLabel": "Last name",
|
||||
"PayoutDetailsForm.lastNamePlaceholder": "Doe",
|
||||
"PayoutDetailsForm.lastNameRequired": "This field is required",
|
||||
"PayoutDetailsForm.personalDetailsAdditionalOwnerTitle": "Additional owner details",
|
||||
"PayoutDetailsForm.personalDetailsTitle": "Personal details",
|
||||
"PayoutDetailsForm.personalIdNumberTitle": "Personal id number",
|
||||
"PayoutDetailsForm.personalIdNumberLabel.HK": "Hong Kong Identity Card Number (HKID)",
|
||||
|
|
|
|||
|
|
@ -452,6 +452,9 @@
|
|||
"PasswordResetPage.recoveryLinkText": "la page de réinitialisation du mot de passe",
|
||||
"PasswordResetPage.resetFailed": "La réinitialisation a échoué.",
|
||||
"PasswordResetPage.title": "Réinitialiser le mot de passe",
|
||||
"PayoutDetailsForm.accountTypeTitle": "Account type",
|
||||
"PayoutDetailsForm.additionalOwnerLabel": "+ Add additional owner",
|
||||
"PayoutDetailsForm.additionalOwnerRemove": "Remove additional owner",
|
||||
"PayoutDetailsForm.addressTitle": "Adresse",
|
||||
"PayoutDetailsForm.bankDetails": "Détail du compte bancaire",
|
||||
"PayoutDetailsForm.birthdayDatePlaceholder": "jj",
|
||||
|
|
@ -481,6 +484,35 @@
|
|||
"PayoutDetailsForm.cityLabel": "Ville",
|
||||
"PayoutDetailsForm.cityPlaceholder": "Helsinki",
|
||||
"PayoutDetailsForm.cityRequired": "Ce champ est requis.",
|
||||
"PayoutDetailsForm.companyAccount": "I represent a company",
|
||||
"PayoutDetailsForm.companyAddressTitle": "Company address",
|
||||
"PayoutDetailsForm.companyDetailsTitle": "Company details",
|
||||
"PayoutDetailsForm.companyNameLabel": "Company name",
|
||||
"PayoutDetailsForm.companyNamePlaceholder": "Enter company name...",
|
||||
"PayoutDetailsForm.companyNameRequired": "Company name is required",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.AT": "Firmenbuchnummer (FN)",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.AU": "Company ACN/ABN - TFN",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.BE": "TVA/BTW/CBE",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.CA": "Business Number (Tax ID)",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.CH": "VAT number UID/MWST/TVA/IVA",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.DE": "Handelsregisternummer (HRB) ",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.DK": "Momsregistreringsnummer (CVR)",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.ES": "Número de Identificación Fiscal (NIF)",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.FI": "Y-tunnus",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.FR": "Numéro SIREN",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.GB": "Companies House Registration Number (CRN)",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.HK": "Registration Number",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.IE": "Company Number",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.IT": "Numero RI/ REA",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.LU": "Company/RCS number",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.NL": "KVK number",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.NO": "Organisasjonsnummer (Orgnr)",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.NZ": "NZBN",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.PT": "N.º Contribuinte",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.SE": "Organisationsnummer",
|
||||
"PayoutDetailsForm.companyTaxIdLabel.US": "Tax ID",
|
||||
"PayoutDetailsForm.companyTaxIdPlaceholder": "Enter {idName}...",
|
||||
"PayoutDetailsForm.companyTaxIdRequired": "{idName} is required",
|
||||
"PayoutDetailsForm.countryLabel": "Pays",
|
||||
"PayoutDetailsForm.countryNames.AT": "Autriche",
|
||||
"PayoutDetailsForm.countryNames.AU": "Australie",
|
||||
|
|
@ -510,10 +542,12 @@
|
|||
"PayoutDetailsForm.firstNameLabel": "Prénom",
|
||||
"PayoutDetailsForm.firstNamePlaceholder": "Prénom",
|
||||
"PayoutDetailsForm.firstNameRequired": "Ce champ est requis.",
|
||||
"PayoutDetailsForm.individualAccount": "I'm an individual",
|
||||
"PayoutDetailsForm.information": "Puisque c'est votre première annonce, nous devons en savoir un peu plus pour pouvoir vous transférer vos gains. Nous ne vous les demanderons qu'une seule fois.",
|
||||
"PayoutDetailsForm.lastNameLabel": "Nom",
|
||||
"PayoutDetailsForm.lastNamePlaceholder": "Nom",
|
||||
"PayoutDetailsForm.lastNameRequired": "Ce champ est requis.",
|
||||
"PayoutDetailsForm.personalDetailsAdditionalOwnerTitle": "Additional owner details",
|
||||
"PayoutDetailsForm.personalDetailsTitle": "Détails",
|
||||
"PayoutDetailsForm.personalIdNumberLabel.HK": "Hong Kong Identity Card Number (HKID)",
|
||||
"PayoutDetailsForm.personalIdNumberLabel.US": "Quatre derniers chiffres du numéro de sécurité sociale (SSN)",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue