[CLD-6219] Add Company Name field to Purchase Modal (#24428)

Automatic Merge
Этот коммит содержится в:
Nick Misasi
2023-09-06 16:27:35 -04:00
коммит произвёл GitHub
родитель b540ed5d30
Коммит fcfcbd9909
8 изменённых файлов: 259 добавлений и 286 удалений

Просмотреть файл

@@ -4,11 +4,10 @@
import type {
StripeCardElementChangeEvent,
} from '@stripe/stripe-js';
import {getName} from 'country-list';
import React from 'react';
import {FormattedMessage} from 'react-intl';
import React, {useRef} from 'react';
import {FormattedMessage, useIntl} from 'react-intl';
import type {PaymentMethod} from '@mattermost/types/cloud';
import type {CloudCustomer, PaymentMethod} from '@mattermost/types/cloud';
import type {Theme} from 'mattermost-redux/selectors/entities/preferences';
@@ -16,7 +15,6 @@ import DropdownInput from 'components/dropdown_input';
import Input from 'components/widgets/inputs/input/input';
import {COUNTRIES} from 'utils/countries';
import * as Utils from 'utils/utils';
import type {BillingDetails} from 'types/cloud/sku';
@@ -37,6 +35,7 @@ type Props = {
onInputChange?: (billing: BillingDetails) => void;
onInputBlur?: (billing: BillingDetails) => void;
buttonFooter?: JSX.Element;
customer?: CloudCustomer | undefined;
};
type State = {
@@ -48,57 +47,27 @@ type State = {
postalCode: string;
name: string;
changePaymentMethod: boolean;
company_name: string;
}
export default class PaymentForm extends React.PureComponent<Props, State> {
static defaultProps = {
showSaveCard: false,
className: '',
};
const PaymentForm: React.FC<Props> = (props: Props) => {
const {className, paymentMethod, buttonFooter, theme} = props;
const {formatMessage} = useIntl();
const cardRef = useRef<CardInputType>(null);
cardRef: React.RefObject<CardInputType>;
const [state, setState] = React.useState<State>({
address: '',
address2: '',
city: '',
state: '',
country: '',
postalCode: '',
name: '',
changePaymentMethod: paymentMethod == null,
company_name: props.customer?.name || '',
});
public constructor(props: Props) {
super(props);
this.cardRef = React.createRef<CardInputType>();
this.state = this.getResetState(props);
}
public componentDidUpdate(prevProps: Props) {
if (prevProps.paymentMethod == null && this.props.paymentMethod != null) {
this.resetState();
return;
}
if (prevProps.initialBillingDetails === undefined && this.props.initialBillingDetails !== undefined) {
this.resetState();
}
}
private resetState = () => {
this.setState(this.getResetState());
};
private getResetState = (props = this.props) => {
const {initialBillingDetails, paymentMethod} = props;
const billingDetails = initialBillingDetails || {} as BillingDetails;
return {
address: billingDetails.address,
address2: billingDetails.address2,
city: billingDetails.city,
state: billingDetails.state,
country: getName(billingDetails.country || '') || getName('US') || '',
postalCode: billingDetails.postalCode,
name: billingDetails.name,
changePaymentMethod: paymentMethod == null,
};
};
private handleInputChange = (event: React.ChangeEvent<HTMLInputElement> | React.ChangeEvent<HTMLSelectElement>) => {
const handleInputChange = (event: React.ChangeEvent<HTMLInputElement> | React.ChangeEvent<HTMLSelectElement>) => {
const target = event.target;
const name = target.name;
const value = target.value;
@@ -107,277 +76,268 @@ export default class PaymentForm extends React.PureComponent<Props, State> {
[name]: value,
} as unknown as Pick<State, keyof State>;
this.setState(newStateValue);
setState({...state, ...newStateValue});
const {onInputChange} = this.props;
const {onInputChange} = props;
if (onInputChange) {
onInputChange({...this.state, ...newStateValue, card: this.cardRef.current?.getCard()} as BillingDetails);
onInputChange({...state, ...newStateValue, card: cardRef.current?.getCard()} as BillingDetails);
}
};
private handleCardInputChange = (event: StripeCardElementChangeEvent) => {
if (this.props.onCardInputChange) {
this.props.onCardInputChange(event);
const handleCardInputChange = (event: StripeCardElementChangeEvent) => {
if (props.onCardInputChange) {
props.onCardInputChange(event);
}
};
private handleStateChange = (stateValue: string) => {
const handleStateChange = (stateValue: string) => {
const newStateValue = {
state: stateValue,
} as unknown as Pick<State, keyof State>;
this.setState(newStateValue);
setState({...state, ...newStateValue});
if (this.props.onInputChange) {
this.props.onInputChange({...this.state, ...newStateValue, card: this.cardRef.current?.getCard()} as BillingDetails);
if (props.onInputChange) {
props.onInputChange({...state, ...newStateValue, card: cardRef.current?.getCard()} as BillingDetails);
}
};
private handleCountryChange = (option: any) => {
const handleCountryChange = (option: any) => {
const newStateValue = {
country: option.value,
} as unknown as Pick<State, keyof State>;
this.setState(newStateValue);
setState({...state, ...newStateValue});
if (this.props.onInputChange) {
this.props.onInputChange({...this.state, ...newStateValue, card: this.cardRef.current?.getCard()} as BillingDetails);
if (props.onInputChange) {
props.onInputChange({...state, ...newStateValue, card: cardRef.current?.getCard()} as BillingDetails);
}
};
private onBlur = () => {
const {onInputBlur} = this.props;
const onBlur = () => {
const {onInputBlur} = props;
if (onInputBlur) {
onInputBlur({...this.state, card: this.cardRef.current?.getCard()} as BillingDetails);
onInputBlur({...state, card: cardRef.current?.getCard()} as BillingDetails);
}
};
private changePaymentMethod = (event: React.MouseEvent<HTMLElement>) => {
const changePaymentMethod = (event: React.MouseEvent<HTMLElement>) => {
event.preventDefault();
this.setState({changePaymentMethod: true});
setState({...state, changePaymentMethod: true});
};
public render() {
const {className, paymentMethod, buttonFooter, theme} = this.props;
const {changePaymentMethod} = this.state;
let paymentDetails: JSX.Element;
if (changePaymentMethod) {
paymentDetails = (
<React.Fragment>
<div className='form-row'>
<CardInput
forwardedRef={this.cardRef}
required={true}
onBlur={this.onBlur}
onCardInputChange={this.handleCardInputChange}
theme={theme}
/>
</div>
<div className='form-row'>
<Input
name='name'
type='text'
value={this.state.name}
onChange={this.handleInputChange}
onBlur={this.onBlur}
placeholder={Utils.localizeMessage(
'payment_form.name_on_card',
'Name on Card',
)}
required={true}
/>
</div>
<div className='section-title'>
<FormattedMessage
id='payment_form.billing_address'
defaultMessage='Billing address'
/>
</div>
<DropdownInput
onChange={this.handleCountryChange}
value={
this.state.country ? {value: this.state.country, label: this.state.country} : undefined
}
options={COUNTRIES.map((country) => ({
value: country.name,
label: country.name,
}))}
legend={Utils.localizeMessage(
'payment_form.country',
'Country',
)}
placeholder={Utils.localizeMessage(
'payment_form.country',
'Country',
)}
name={'billing_dropdown'}
let paymentDetails: JSX.Element;
if (state.changePaymentMethod) {
paymentDetails = (
<React.Fragment>
<div className='form-row'>
<Input
name='company_name'
type='text'
value={state.company_name}
onChange={handleInputChange}
onBlur={onBlur}
placeholder={formatMessage({id: 'payment_form.company_name', defaultMessage: 'Company Name'})}
required={true}
/>
<div className='form-row'>
<Input
name='address'
type='text'
value={this.state.address}
onChange={this.handleInputChange}
onBlur={this.onBlur}
placeholder={Utils.localizeMessage(
'payment_form.address',
'Address',
)}
required={true}
/>
</div>
<div className='form-row'>
<Input
name='address2'
type='text'
value={this.state.address2}
onChange={this.handleInputChange}
onBlur={this.onBlur}
placeholder={Utils.localizeMessage(
'payment_form.address_2',
'Address 2',
)}
/>
</div>
<div className='form-row'>
<Input
name='city'
type='text'
value={this.state.city}
onChange={this.handleInputChange}
onBlur={this.onBlur}
placeholder={Utils.localizeMessage(
'payment_form.city',
'City',
)}
required={true}
/>
</div>
<div className='form-row'>
<div className='form-row-third-1 selector second-dropdown-sibling-wrapper'>
<StateSelector
country={this.state.country}
state={this.state.state}
onChange={this.handleStateChange}
onBlur={this.onBlur}
/>
</div>
<div className='form-row-third-2'>
<Input
name='postalCode'
type='text'
value={this.state.postalCode}
onChange={this.handleInputChange}
onBlur={this.onBlur}
placeholder={Utils.localizeMessage(
'payment_form.zipcode',
'Zip/Postal Code',
)}
required={true}
/>
</div>
</div>
{changePaymentMethod ? buttonFooter : null}
</React.Fragment>
);
} else {
let cardContent: JSX.Element | null = null;
if (paymentMethod) {
let cardDetails = (
</div>
<div className='form-row'>
<CardInput
forwardedRef={cardRef}
required={true}
onBlur={onBlur}
onCardInputChange={handleCardInputChange}
theme={theme}
/>
</div>
<div className='form-row'>
<Input
name='name'
type='text'
value={state.name}
onChange={handleInputChange}
onBlur={onBlur}
placeholder={formatMessage({id: 'payment_form.name_on_card', defaultMessage: 'Name on Card'})}
required={true}
/>
</div>
<div className='section-title'>
<FormattedMessage
id='payment_form.no_credit_card'
defaultMessage='No credit card added'
id='payment_form.billing_address'
defaultMessage='Billing address'
/>
);
if (paymentMethod.last_four) {
cardDetails = (
<React.Fragment>
<CardImage brand={paymentMethod.card_brand}/>
{`Card ending in ${paymentMethod.last_four}`}
<br/>
{`Expires ${paymentMethod.exp_month}/${paymentMethod.exp_year}`}
</React.Fragment>
);
}
let addressDetails = (
<i>
<FormattedMessage
id='payment_form.no_billing_address'
defaultMessage='No billing address added'
</div>
<DropdownInput
onChange={handleCountryChange}
value={
state.country ? {value: state.country, label: state.country} : undefined
}
options={COUNTRIES.map((country) => ({
value: country.name,
label: country.name,
}))}
legend={formatMessage({id: 'payment_form.country', defaultMessage: 'Country'})}
placeholder={formatMessage({id: 'payment_form.country', defaultMessage: 'Country'})}
name={'billing_dropdown'}
/>
<div className='form-row'>
<Input
name='address'
type='text'
value={state.address}
onChange={handleInputChange}
onBlur={onBlur}
placeholder={formatMessage({id: 'payment_form.address', defaultMessage: 'Address'})}
required={true}
/>
</div>
<div className='form-row'>
<Input
name='address2'
type='text'
value={state.address2}
onChange={handleInputChange}
onBlur={onBlur}
placeholder={formatMessage({id: 'payment_form.address_2', defaultMessage: 'Address 2'})}
/>
</div>
<div className='form-row'>
<Input
name='city'
type='text'
value={state.city}
onChange={handleInputChange}
onBlur={onBlur}
placeholder={formatMessage({id: 'payment_form.city', defaultMessage: 'City'})}
required={true}
/>
</div>
<div className='form-row'>
<div className='form-row-third-1 selector second-dropdown-sibling-wrapper'>
<StateSelector
country={state.country}
state={state.state}
onChange={handleStateChange}
onBlur={onBlur}
/>
</i>);
if (this.state.state) {
addressDetails = (
<React.Fragment>
{this.state.address}
{this.state.address2}
<br/>
{`${this.state.city}, ${this.state.state}, ${this.state.country}`}
<br/>
{this.state.postalCode}
</React.Fragment>
);
}
</div>
<div className='form-row-third-2'>
<Input
name='postalCode'
type='text'
value={state.postalCode}
onChange={handleInputChange}
onBlur={onBlur}
placeholder={formatMessage({id: 'payment_form.zipcode', defaultMessage: 'Zip/Postal Code'})}
required={true}
/>
</div>
</div>
{state.changePaymentMethod ? buttonFooter : null}
</React.Fragment>
);
} else {
let cardContent: JSX.Element | null = null;
cardContent = (
if (paymentMethod) {
let cardDetails = (
<FormattedMessage
id='payment_form.no_credit_card'
defaultMessage='No credit card added'
/>
);
if (paymentMethod.last_four) {
cardDetails = (
<React.Fragment>
<div className='PaymentForm-saved-card'>
{cardDetails}
</div>
<div className='PaymentForm-saved-address'>
{addressDetails}
</div>
<CardImage brand={paymentMethod.card_brand}/>
{`Card ending in ${paymentMethod.last_four}`}
<br/>
{`Expires ${paymentMethod.exp_month}/${paymentMethod.exp_year}`}
</React.Fragment>
);
}
let addressDetails = (
<i>
<FormattedMessage
id='payment_form.no_billing_address'
defaultMessage='No billing address added'
/>
</i>);
if (state.state) {
addressDetails = (
<React.Fragment>
{state.address}
{state.address2}
<br/>
{`${state.city}, ${state.state}, ${state.country}`}
<br/>
{state.postalCode}
</React.Fragment>
);
}
paymentDetails = (
<div
id='console_payment_saved'
className='PaymentForm-saved'
>
<div className='PaymentForm-saved-title'>
<FormattedMessage
id='payment_form.saved_payment_method'
defaultMessage='Saved Payment Method'
/>
cardContent = (
<React.Fragment>
<div className='PaymentForm-saved-card'>
{cardDetails}
</div>
{cardContent}
<button
className='Form-btn-link PaymentForm-change'
onClick={this.changePaymentMethod}
>
<FormattedMessage
id='payment_form.change_payment_method'
defaultMessage='Change Payment Method'
/>
</button>
</div>
<div className='PaymentForm-saved-address'>
{addressDetails}
</div>
</React.Fragment>
);
}
return (
<form
id='payment_form'
className={`PaymentForm ${className}`}
paymentDetails = (
<div
id='console_payment_saved'
className='PaymentForm-saved'
>
<GatherIntent
typeGatherIntent='monthlySubscription'
modalComponent={GatherIntentModal}
gatherIntentText={
<FormattedMessage
id='payment_form.gather_wire_transfer_intent'
defaultMessage='Looking for other payment options?'
/>}
/>
<div className='section-title'>
<div className='PaymentForm-saved-title'>
<FormattedMessage
id='payment_form.credit_card'
defaultMessage='Credit Card'
id='payment_form.saved_payment_method'
defaultMessage='Saved Payment Method'
/>
</div>
{paymentDetails}
</form>
{cardContent}
<button
className='Form-btn-link PaymentForm-change'
onClick={changePaymentMethod}
>
<FormattedMessage
id='payment_form.change_payment_method'
defaultMessage='Change Payment Method'
/>
</button>
</div>
);
}
}
return (
<form
id='payment_form'
className={`PaymentForm ${className}`}
>
<GatherIntent
typeGatherIntent='monthlySubscription'
modalComponent={GatherIntentModal}
gatherIntentText={
<FormattedMessage
id='payment_form.gather_wire_transfer_intent'
defaultMessage='Looking for other payment options?'
/>}
/>
<div className='section-title'>
<FormattedMessage
id='payment_form.credit_card'
defaultMessage='Credit Card'
/>
</div>
{paymentDetails}
</form>
);
};
PaymentForm.defaultProps = {
className: '',
};
export default PaymentForm;