Separate PayoutDetailsForm to PayoutDetailsFormIndividual and PayoutDetailsFormCompany

This commit is contained in:
Jenni Nurmi 2018-12-18 10:02:41 +02:00
parent abe973337c
commit 1e5e70a5c2
3 changed files with 605 additions and 389 deletions

View file

@ -5,26 +5,13 @@ import { FormattedMessage, injectIntl, intlShape } from 'react-intl';
import { Form as FinalForm } from 'react-final-form';
import classNames from 'classnames';
import config from '../../config';
import {
Button,
ExternalLink,
StripeBankAccountTokenInputField,
FieldSelect,
FieldBirthdayInput,
FieldRadioButton,
FieldTextInput,
Form,
} from '../../components';
import * as validators from '../../util/validators';
import { Button, ExternalLink, FieldRadioButton, Form } from '../../components';
import { isStripeInvalidPostalCode } from '../../util/errors';
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 => {
const country = config.stripe.supportedCountries.find(c => c.code === countryCode);
@ -34,11 +21,6 @@ export const stripeCountryConfigs = countryCode => {
return country;
};
const countryCurrency = countryCode => {
const country = stripeCountryConfigs(countryCode);
return country.currency;
};
const PayoutDetailsFormComponent = props => (
<FinalForm
{...props}
@ -47,7 +29,6 @@ const PayoutDetailsFormComponent = props => (
className,
createStripeAccountError,
disabled,
form,
handleSubmit,
inProgress,
intl,
@ -64,130 +45,12 @@ const PayoutDetailsFormComponent = props => (
id: 'PayoutDetailsForm.individualAccount',
});
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 companyAccountLabel = intl.formatMessage({ id: 'PayoutDetailsForm.companyAccount' });
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' });
const companyTaxIdPlaceholder = intl.formatMessage({
id: 'PayoutDetailsForm.companyTaxIdPlaceholder',
});
const companyTaxIdRequired = validators.required(
intl.formatMessage({
id: 'PayoutDetailsForm.companyTaxIdRequired',
})
);
const countryLabel = intl.formatMessage({ id: 'PayoutDetailsForm.countryLabel' });
const countryPlaceholder = intl.formatMessage({
id: 'PayoutDetailsForm.countryPlaceholder',
});
const countryRequired = validators.required(
intl.formatMessage({
id: 'PayoutDetailsForm.countryRequired',
})
);
// 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;
@ -242,257 +105,32 @@ const PayoutDetailsFormComponent = props => (
</div>
{showIndividual ? (
<React.Fragment>
<div className={css.sectionContainer}>
<h3 className={css.subTitle}>
<FormattedMessage id="PayoutDetailsForm.personalDetailsTitle" />
</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}
/>
<FieldTextInput
id="lname"
name="lname"
disabled={disabled}
className={css.lastName}
type="text"
autoComplete="family-name"
label={lastNameLabel}
placeholder={lastNamePlaceholder}
validate={lastNameRequired}
/>
</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>
<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>
) : 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>
</React.Fragment>
<PayoutDetailsFormIndividual fieldRenderProps={fieldRenderProps} />
) : showCompany ? (
<PayoutDetailsFormCompany fieldRenderProps={fieldRenderProps} />
) : null}
{showCompany === 'company' ? (
<React.Fragment>
<div className={css.sectionContainer}>
<h3 className={css.subTitle}>
<FormattedMessage id="PayoutDetailsForm.companyDetailsTitle" />
</h3>
<div className={css.formRow}>
<FieldTextInput
id="companyName"
name="companyName"
disabled={disabled}
type="text"
autoComplete="company-name"
label={companyNameLabel}
placeholder={companyNamePlaceholder}
validate={companyNameRequired}
/>
<FieldTextInput
id="companyTaxId"
name="companyTaxId"
disabled={disabled}
className={css.taxId}
type="text"
autoComplete="company-tax-id"
label={companyTaxIdLabel}
placeholder={companyTaxIdPlaceholder}
validate={companyTaxIdRequired}
/>
</div>
</div>
<div className={css.sectionContainer}>
<h3 className={css.subTitle}>
<FormattedMessage id="PayoutDetailsForm.companyAddressTitle" />
</h3>
{error}
<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>
<PayoutDetailsAddress
country={country}
intl={intl}
disabled={disabled}
form={form}
/>
</div>
{country ? (
<React.Fragment>
<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>
</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>
</React.Fragment>
) : null}
<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>
);
}}

View file

@ -0,0 +1,319 @@
import React from 'react';
import { bool, object, string } from 'prop-types';
import { compose } from 'redux';
import { FormattedMessage, injectIntl, intlShape } from 'react-intl';
import config from '../../config';
import {
StripeBankAccountTokenInputField,
FieldSelect,
FieldBirthdayInput,
FieldTextInput,
} from '../../components';
import * as validators from '../../util/validators';
import PayoutDetailsAddress from './PayoutDetailsAddress';
import css from './PayoutDetailsForm.css';
const MIN_STRIPE_ACCOUNT_AGE = 18;
const supportedCountries = config.stripe.supportedCountries.map(c => c.code);
export const stripeCountryConfigs = countryCode => {
const country = config.stripe.supportedCountries.find(c => c.code === countryCode);
if (!country) {
throw new Error(`Country code not found in Stripe config ${countryCode}`);
}
return country;
};
const countryCurrency = countryCode => {
const country = stripeCountryConfigs(countryCode);
return country.currency;
};
const PayoutDetailsFormCompanyComponent = ({ fieldRenderProps }) => {
const { disabled, form, intl, 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 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 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' });
const companyTaxIdPlaceholder = intl.formatMessage({
id: 'PayoutDetailsForm.companyTaxIdPlaceholder',
});
const companyTaxIdRequired = validators.required(
intl.formatMessage({
id: 'PayoutDetailsForm.companyTaxIdRequired',
})
);
const countryLabel = intl.formatMessage({ id: 'PayoutDetailsForm.countryLabel' });
const countryPlaceholder = intl.formatMessage({
id: 'PayoutDetailsForm.countryPlaceholder',
});
const countryRequired = validators.required(
intl.formatMessage({
id: 'PayoutDetailsForm.countryRequired',
})
);
// 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);
}
return (
<React.Fragment>
<div className={css.sectionContainer}>
<h3 className={css.subTitle}>
<FormattedMessage id="PayoutDetailsForm.companyDetailsTitle" />
</h3>
<div className={css.formRow}>
<FieldTextInput
id="companyName"
name="companyName"
disabled={disabled}
type="text"
autoComplete="company-name"
label={companyNameLabel}
placeholder={companyNamePlaceholder}
validate={companyNameRequired}
/>
<FieldTextInput
id="companyTaxId"
name="companyTaxId"
disabled={disabled}
className={css.taxId}
type="text"
autoComplete="company-tax-id"
label={companyTaxIdLabel}
placeholder={companyTaxIdPlaceholder}
validate={companyTaxIdRequired}
/>
</div>
</div>
<div className={css.sectionContainer}>
<h3 className={css.subTitle}>
<FormattedMessage id="PayoutDetailsForm.companyAddressTitle" />
</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>
<PayoutDetailsAddress country={country} intl={intl} disabled={disabled} form={form} />
</div>
{country ? (
<React.Fragment>
<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>
</React.Fragment>
) : null}
<div className={css.sectionContainer}>
<h3 className={css.subTitle}>
<FormattedMessage id="PayoutDetailsForm.personalDetailsTitle" />
</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}
/>
<FieldTextInput
id="lname"
name="lname"
disabled={disabled}
className={css.lastName}
type="text"
autoComplete="family-name"
label={lastNameLabel}
placeholder={lastNamePlaceholder}
validate={lastNameRequired}
/>
</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>
{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}
</React.Fragment>
);
};
PayoutDetailsFormCompanyComponent.defaultProps = {
className: null,
country: null,
createStripeAccountError: null,
disabled: false,
inProgress: false,
ready: false,
submitButtonText: null,
};
PayoutDetailsFormCompanyComponent.propTypes = {
className: string,
createStripeAccountError: object,
disabled: bool,
inProgress: bool,
ready: bool,
submitButtonText: string,
// from injectIntl
intl: intlShape.isRequired,
};
const PayoutDetailsFormCompany = compose(injectIntl)(PayoutDetailsFormCompanyComponent);
export default PayoutDetailsFormCompany;

View file

@ -0,0 +1,259 @@
import React from 'react';
import { bool, object } from 'prop-types';
import { compose } from 'redux';
import { FormattedMessage, injectIntl, intlShape } from 'react-intl';
import config from '../../config';
import {
StripeBankAccountTokenInputField,
FieldSelect,
FieldBirthdayInput,
FieldTextInput,
} from '../../components';
import * as validators from '../../util/validators';
import PayoutDetailsAddress from './PayoutDetailsAddress';
import css from './PayoutDetailsForm.css';
const MIN_STRIPE_ACCOUNT_AGE = 18;
const supportedCountries = config.stripe.supportedCountries.map(c => c.code);
export const stripeCountryConfigs = countryCode => {
const country = config.stripe.supportedCountries.find(c => c.code === countryCode);
if (!country) {
throw new Error(`Country code not found in Stripe config ${countryCode}`);
}
return country;
};
const countryCurrency = countryCode => {
const country = stripeCountryConfigs(countryCode);
return country.currency;
};
const PayoutDetailsFormIndividualComponent = ({ fieldRenderProps }) => {
const { disabled, form, intl, 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 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 countryLabel = intl.formatMessage({ id: 'PayoutDetailsForm.countryLabel' });
const countryPlaceholder = intl.formatMessage({
id: 'PayoutDetailsForm.countryPlaceholder',
});
const countryRequired = validators.required(
intl.formatMessage({
id: 'PayoutDetailsForm.countryRequired',
})
);
// 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);
}
return (
<React.Fragment>
<div className={css.sectionContainer}>
<h3 className={css.subTitle}>
<FormattedMessage id="PayoutDetailsForm.personalDetailsTitle" />
</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}
/>
<FieldTextInput
id="lname"
name="lname"
disabled={disabled}
className={css.lastName}
type="text"
autoComplete="family-name"
label={lastNameLabel}
placeholder={lastNamePlaceholder}
validate={lastNameRequired}
/>
</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>
<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>
) : 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}
</React.Fragment>
);
};
PayoutDetailsFormIndividualComponent.defaultProps = {
disabled: false,
};
PayoutDetailsFormIndividualComponent.propTypes = {
disabled: bool,
form: object.isRequired,
// from injectIntl
intl: intlShape.isRequired,
};
const PayoutDetailsFormIndividual = compose(injectIntl)(PayoutDetailsFormIndividualComponent);
export default PayoutDetailsFormIndividual;