mirror of
https://github.com/kingomarnajjar/flex-template-web.git
synced 2026-07-28 12:43:11 +10:00
Separate PayoutDetailsForm to PayoutDetailsFormIndividual and PayoutDetailsFormCompany
This commit is contained in:
parent
abe973337c
commit
1e5e70a5c2
3 changed files with 605 additions and 389 deletions
|
|
@ -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>
|
||||
);
|
||||
}}
|
||||
|
|
|
|||
319
src/forms/PayoutDetailsForm/PayoutDetailsFormCompany.js
Normal file
319
src/forms/PayoutDetailsForm/PayoutDetailsFormCompany.js
Normal 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;
|
||||
259
src/forms/PayoutDetailsForm/PayoutDetailsFormIndividual.js
Normal file
259
src/forms/PayoutDetailsForm/PayoutDetailsFormIndividual.js
Normal 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;
|
||||
Loading…
Add table
Reference in a new issue