259 lines
8.3 KiB
JavaScript
Executable file
259 lines
8.3 KiB
JavaScript
Executable file
import React from 'react';
|
|
import i18n from '../../i18n';
|
|
import classNames from 'classnames';
|
|
import moment from 'moment';
|
|
import BillingActionCreators from '../../actions/BillingActionCreators';
|
|
import PaymentModalActionCreators from '../../actions/PaymentModalActionCreators';
|
|
import AnalyticsUtils from '../../utils/AnalyticsUtils';
|
|
import FormText, {Types} from '../../uikit/form/FormText';
|
|
import FormDivider from '../../uikit/form/FormDivider';
|
|
import Button, {ButtonLooks, ButtonColors} from '../../uikit/Button';
|
|
import {
|
|
CurrencyCodes,
|
|
CurrencySymbols,
|
|
PaymentModelModes,
|
|
PremiumPlanPrices,
|
|
PremiumPlans,
|
|
PremiumStatusTypes,
|
|
} from '../../Constants';
|
|
|
|
const PremiumStatusClasses = {
|
|
[PremiumStatusTypes.UNPAID]: 'active',
|
|
[PremiumStatusTypes.ACTIVE]: 'active',
|
|
[PremiumStatusTypes.PAST_DUE]: 'past-due',
|
|
[PremiumStatusTypes.CANCELED]: 'cancelled',
|
|
};
|
|
|
|
class SubscriptionDetails extends React.PureComponent {
|
|
constructor(props) {
|
|
super(props);
|
|
(this: any).unsubscribe = this.unsubscribe.bind(this);
|
|
(this: any).resubscribe = this.resubscribe.bind(this);
|
|
(this: any).upgradeYearly = this.upgradeYearly.bind(this);
|
|
}
|
|
|
|
addCard() {
|
|
PaymentModalActionCreators.show(PaymentModelModes.CHANGE);
|
|
}
|
|
|
|
removeCard() {
|
|
BillingActionCreators.removeCard();
|
|
}
|
|
|
|
unsubscribe() {
|
|
const {premiumSubscription} = this.props;
|
|
const date = new Date(premiumSubscription.current_period_end);
|
|
const subscriptionLength = moment().diff(moment(premiumSubscription.created_at), 'days');
|
|
BillingActionCreators.unsubscribe(i18n.Messages.PREMIUM_CANCEL_CONFIRM_BODY_DETAILED.format({date})).then(() => {
|
|
AnalyticsUtils.track('premium_canceled', {
|
|
/* eslint-disable camelcase */
|
|
cancellation_type: 'User Cancellation',
|
|
subscription_length: subscriptionLength,
|
|
/* eslint-enable camelcase */
|
|
plan: premiumSubscription.plan,
|
|
});
|
|
});
|
|
}
|
|
|
|
changeCard() {
|
|
PaymentModalActionCreators.show(PaymentModelModes.CHANGE);
|
|
}
|
|
|
|
resubscribe() {
|
|
const {paymentSource} = this.props;
|
|
if (paymentSource) {
|
|
BillingActionCreators.resubscribe();
|
|
} else {
|
|
PaymentModalActionCreators.show(PaymentModelModes.RESUBSCRIBE);
|
|
}
|
|
}
|
|
|
|
upgradeYearly() {
|
|
const {premiumSubscription} = this.props;
|
|
const start = moment(premiumSubscription.current_period_start);
|
|
const end = moment(premiumSubscription.current_period_end);
|
|
const totalSeconds = end.diff(start, 'seconds');
|
|
const secondsRemaining = end.diff(moment(), 'seconds');
|
|
const proratedAmount = secondsRemaining / totalSeconds * parseFloat(PremiumPlanPrices.MONTHLY);
|
|
const amount = (parseFloat(PremiumPlanPrices.YEARLY) - proratedAmount).toFixed(2);
|
|
AnalyticsUtils.track('premium_upgrade_started', {
|
|
plan: PremiumPlans.YEARLY,
|
|
// eslint-disable-next-line camelcase
|
|
price_shown: +amount.replace('.', ''),
|
|
});
|
|
BillingActionCreators.upgrade(
|
|
PremiumPlans.YEARLY,
|
|
i18n.Messages.PREMIUM_UPGRADE_CONFIRM_BODY_DETAILED.format({
|
|
currencySymbol: CurrencySymbols.USD,
|
|
currencyCode: CurrencyCodes.USD,
|
|
amount,
|
|
})
|
|
);
|
|
}
|
|
|
|
renderSubscriptionDetails() {
|
|
const {premiumSubscription, busy} = this.props;
|
|
const date = new Date(premiumSubscription.current_period_end);
|
|
const {status, plan} = premiumSubscription;
|
|
let subscriptionInfo;
|
|
switch (status) {
|
|
case PremiumStatusTypes.PAST_DUE:
|
|
subscriptionInfo = i18n.Messages.PREMIUM_PAST_DUE;
|
|
break;
|
|
case PremiumStatusTypes.CANCELED:
|
|
subscriptionInfo = i18n.Messages.PREMIUM_CANCELED.format({date});
|
|
break;
|
|
default:
|
|
subscriptionInfo = i18n.Messages.PREMIUM_INFO.format({
|
|
currencySymbol: CurrencySymbols.USD,
|
|
currencyCode: CurrencyCodes.USD,
|
|
amount: plan === PremiumPlans.YEARLY ? PremiumPlanPrices.YEARLY : PremiumPlanPrices.MONTHLY,
|
|
date,
|
|
});
|
|
}
|
|
|
|
let buttons;
|
|
if (status !== PremiumStatusTypes.CANCELED) {
|
|
buttons = [
|
|
<Button
|
|
key="cancel"
|
|
className="premium-tools-button"
|
|
look={ButtonLooks.INVERTED}
|
|
color={ButtonColors.BRAND}
|
|
disabled={busy}
|
|
submitting={busy}
|
|
onClick={this.unsubscribe}>
|
|
{i18n.Messages.CANCEL}
|
|
</Button>,
|
|
];
|
|
if (plan === PremiumPlans.MONTHLY) {
|
|
buttons.unshift(
|
|
<Button
|
|
key="upgradeYearly"
|
|
className="premium-tools-button"
|
|
look={ButtonLooks.INVERTED}
|
|
color={ButtonColors.BRAND}
|
|
disabled={busy}
|
|
submitting={busy}
|
|
onClick={this.upgradeYearly}>
|
|
{i18n.Messages.UPGRADE_YEARLY}
|
|
</Button>
|
|
);
|
|
}
|
|
} else {
|
|
buttons = [
|
|
<Button
|
|
key="resubscribe"
|
|
className="premium-tools-button"
|
|
look={ButtonLooks.INVERTED}
|
|
color={ButtonColors.YELLOW}
|
|
disabled={busy}
|
|
submitting={busy}
|
|
onClick={this.resubscribe}>
|
|
{i18n.Messages.RESUBSCRIBE}
|
|
</Button>,
|
|
];
|
|
}
|
|
|
|
return (
|
|
<div className={classNames('subscription', PremiumStatusClasses[status])}>
|
|
<div className="premium-details">
|
|
<div className="payment-subhead premium-title">{i18n.Messages.PREMIUM_TITLE}</div>
|
|
<div className="premium-info">{subscriptionInfo}</div>
|
|
</div>
|
|
<div className="premium-tools">{buttons}</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
renderPaymentSource() {
|
|
const {paymentSource, locale, premiumSubscription, busy} = this.props;
|
|
if (!paymentSource && premiumSubscription.status === PremiumStatusTypes.CANCELED) {
|
|
return null;
|
|
}
|
|
let button;
|
|
let description;
|
|
let details;
|
|
let cardType;
|
|
let invalid;
|
|
if (paymentSource) {
|
|
invalid = paymentSource.invalid;
|
|
const date = new Date();
|
|
date.setMonth(paymentSource.expires_month - 1);
|
|
const shortMonth = date.toLocaleString(locale, {month: 'short'});
|
|
cardType = paymentSource.brand.toLowerCase();
|
|
if (premiumSubscription.status === PremiumStatusTypes.CANCELED) {
|
|
button = (
|
|
<Button
|
|
disabled={busy}
|
|
submitting={busy}
|
|
look={ButtonLooks.OUTLINED}
|
|
className="card-tools-button btn-stroked"
|
|
onClick={this.removeCard}>
|
|
{i18n.Messages.PAYMENT_METHOD_REMOVE_CARD}
|
|
</Button>
|
|
);
|
|
} else {
|
|
button = (
|
|
<Button
|
|
className="card-tools-button"
|
|
disabled={busy}
|
|
submitting={busy}
|
|
look={ButtonLooks.OUTLINED}
|
|
onClick={this.changeCard}>
|
|
{i18n.Messages.PAYMENT_METHOD_CHANGE_CARD}
|
|
</Button>
|
|
);
|
|
}
|
|
if (invalid) {
|
|
description = i18n.Messages.PAYMENT_METHOD_INVALID.format(paymentSource);
|
|
details = i18n.Messages.PAYMENT_METHOD_INVALID_DETAILS;
|
|
} else {
|
|
description = i18n.Messages.PAYMENT_METHOD_CARD_ENDING.format(paymentSource);
|
|
details = i18n.Messages.PAYMENT_METHOD_CARD_EXPIRES.format({
|
|
month: shortMonth,
|
|
year: paymentSource.expires_year,
|
|
});
|
|
}
|
|
} else {
|
|
cardType = 'disabled';
|
|
button = (
|
|
<Button className="card-tools-button" disabled={busy} look={ButtonLooks.OUTLINED} onClick={this.addCard}>
|
|
{i18n.Messages.PREMIUM_ADD_CARD}
|
|
</Button>
|
|
);
|
|
description = i18n.Messages.PREMIUM_NO_CARD;
|
|
details = i18n.Messages.PREMIUM_NO_CARD_DETAILS;
|
|
}
|
|
|
|
return (
|
|
<div className={classNames('payment-method', 'margin-top-40', 'margin-bottom-40', {invalid})}>
|
|
<div className="payment-info">
|
|
<div className={classNames('card-icon', cardType)} />
|
|
<div className="card-info">
|
|
<FormText className="card-description">{description}</FormText>
|
|
<FormText type={Types.DESCRIPTION} className="card-details">{details}</FormText>
|
|
</div>
|
|
<div className="card-tools">{button}</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
render() {
|
|
return (
|
|
<div className="premium-header">
|
|
{this.renderSubscriptionDetails()}
|
|
{this.renderPaymentSource()}
|
|
<FormDivider className="margin-top-40 margin-bottom-40" />
|
|
</div>
|
|
);
|
|
}
|
|
}
|
|
|
|
export default SubscriptionDetails;
|
|
|
|
|
|
|
|
// WEBPACK FOOTER //
|
|
// ./discord_app/components/premium/SubscriptionDetails.js
|