fix(core): adjust onetime subscription ui for billing and pricing (#8591)
close AF-1534
This commit is contained in:
@@ -42,6 +42,7 @@ import { AICancel, AIResume, AISubscribe } from '../plans/ai/actions';
|
|||||||
import { AIRedeemCodeButton } from '../plans/ai/actions/redeem';
|
import { AIRedeemCodeButton } from '../plans/ai/actions/redeem';
|
||||||
import { BelieverCard } from '../plans/lifetime/believer-card';
|
import { BelieverCard } from '../plans/lifetime/believer-card';
|
||||||
import { BelieverBenefits } from '../plans/lifetime/benefits';
|
import { BelieverBenefits } from '../plans/lifetime/benefits';
|
||||||
|
import { RedeemCode } from '../plans/plan-card';
|
||||||
import * as styles from './style.css';
|
import * as styles from './style.css';
|
||||||
|
|
||||||
const DescriptionI18NKey = {
|
const DescriptionI18NKey = {
|
||||||
@@ -146,20 +147,23 @@ const SubscriptionSettings = () => {
|
|||||||
spreadCol={false}
|
spreadCol={false}
|
||||||
name={t['com.affine.payment.billing-setting.current-plan']()}
|
name={t['com.affine.payment.billing-setting.current-plan']()}
|
||||||
desc={
|
desc={
|
||||||
<Trans
|
<>
|
||||||
i18nKey={getMessageKey(currentPlan, currentRecurring)}
|
<Trans
|
||||||
values={{
|
i18nKey={getMessageKey(currentPlan, currentRecurring)}
|
||||||
planName: currentPlan,
|
values={{
|
||||||
}}
|
planName: currentPlan,
|
||||||
components={{
|
}}
|
||||||
1: (
|
components={{
|
||||||
<span
|
1: (
|
||||||
onClick={gotoCloudPlansSetting}
|
<span
|
||||||
className={styles.currentPlanName}
|
onClick={gotoCloudPlansSetting}
|
||||||
/>
|
className={styles.currentPlanName}
|
||||||
),
|
/>
|
||||||
}}
|
),
|
||||||
/>
|
}}
|
||||||
|
/>
|
||||||
|
<CloudExpirationInfo />
|
||||||
|
</>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<PlanAction
|
<PlanAction
|
||||||
@@ -196,28 +200,6 @@ const SubscriptionSettings = () => {
|
|||||||
>
|
>
|
||||||
<PaymentMethodUpdater />
|
<PaymentMethodUpdater />
|
||||||
</SettingRow>
|
</SettingRow>
|
||||||
{proSubscription.nextBillAt && (
|
|
||||||
<SettingRow
|
|
||||||
name={t['com.affine.payment.billing-setting.renew-date']()}
|
|
||||||
desc={t[
|
|
||||||
'com.affine.payment.billing-setting.renew-date.description'
|
|
||||||
]({
|
|
||||||
renewDate: new Date(
|
|
||||||
proSubscription.nextBillAt
|
|
||||||
).toLocaleDateString(),
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{isOnetime && proSubscription.end && (
|
|
||||||
<SettingRow
|
|
||||||
name={t['com.affine.payment.billing-setting.due-date']()}
|
|
||||||
desc={t[
|
|
||||||
'com.affine.payment.billing-setting.due-date.description'
|
|
||||||
]({
|
|
||||||
dueDate: new Date(proSubscription.end).toLocaleDateString(),
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{isBeliever || isOnetime ? null : proSubscription.end &&
|
{isBeliever || isOnetime ? null : proSubscription.end &&
|
||||||
proSubscription.canceledAt ? (
|
proSubscription.canceledAt ? (
|
||||||
<SettingRow
|
<SettingRow
|
||||||
@@ -263,6 +245,34 @@ const SubscriptionSettings = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const CloudExpirationInfo = () => {
|
||||||
|
const t = useI18n();
|
||||||
|
const subscriptionService = useService(SubscriptionService);
|
||||||
|
const subscription = useLiveData(subscriptionService.subscription.pro$);
|
||||||
|
|
||||||
|
let text = '';
|
||||||
|
if (subscription?.nextBillAt) {
|
||||||
|
text = t['com.affine.payment.billing-setting.renew-date.description']({
|
||||||
|
renewDate: i18nTime(subscription.nextBillAt, {
|
||||||
|
absolute: { accuracy: 'day' },
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
} else if (subscription?.end) {
|
||||||
|
text = t['com.affine.payment.billing-setting.due-date.description']({
|
||||||
|
dueDate: i18nTime(subscription.end, {
|
||||||
|
absolute: { accuracy: 'day' },
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return text ? (
|
||||||
|
<>
|
||||||
|
<br />
|
||||||
|
{text}
|
||||||
|
</>
|
||||||
|
) : null;
|
||||||
|
};
|
||||||
|
|
||||||
const TypeFormLink = () => {
|
const TypeFormLink = () => {
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
const subscriptionService = useService(SubscriptionService);
|
const subscriptionService = useService(SubscriptionService);
|
||||||
@@ -375,7 +385,7 @@ const AIPlanCard = ({ onClick }: { onClick: () => void }) => {
|
|||||||
absolute: { accuracy: 'day' },
|
absolute: { accuracy: 'day' },
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
) : subscription?.canceledAt && subscription.end ? (
|
) : (isOnetime || subscription?.canceledAt) && subscription.end ? (
|
||||||
t['com.affine.payment.ai.billing-tip.end-at']({
|
t['com.affine.payment.ai.billing-tip.end-at']({
|
||||||
end: i18nTime(subscription.end, { absolute: { accuracy: 'day' } }),
|
end: i18nTime(subscription.end, { absolute: { accuracy: 'day' } }),
|
||||||
})
|
})
|
||||||
@@ -422,6 +432,13 @@ const PlanAction = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
|
|
||||||
|
const subscription = useService(SubscriptionService).subscription;
|
||||||
|
const isOnetimePro = useLiveData(subscription.isOnetimePro$);
|
||||||
|
|
||||||
|
if (isOnetimePro) {
|
||||||
|
return <RedeemCode variant="primary" className={styles.planAction} />;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
className={styles.planAction}
|
className={styles.planAction}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ export const currentPlan = style({
|
|||||||
flex: '1 0 0',
|
flex: '1 0 0',
|
||||||
});
|
});
|
||||||
export const planAction = style({
|
export const planAction = style({
|
||||||
|
width: 'auto',
|
||||||
marginTop: '8px',
|
marginTop: '8px',
|
||||||
});
|
});
|
||||||
export const planPrice = style({
|
export const planPrice = style({
|
||||||
|
|||||||
@@ -174,6 +174,9 @@ export const CloudPlans = () => {
|
|||||||
const prices = useLiveData(subscriptionService.prices.prices$);
|
const prices = useLiveData(subscriptionService.prices.prices$);
|
||||||
const loggedIn = useLiveData(authService.session.status$) === 'authenticated';
|
const loggedIn = useLiveData(authService.session.status$) === 'authenticated';
|
||||||
const proSubscription = useLiveData(subscriptionService.subscription.pro$);
|
const proSubscription = useLiveData(subscriptionService.subscription.pro$);
|
||||||
|
const isOnetimePro = useLiveData(
|
||||||
|
subscriptionService.subscription.isOnetimePro$
|
||||||
|
);
|
||||||
|
|
||||||
const [recurring, setRecurring] = useState<SubscriptionRecurring>(
|
const [recurring, setRecurring] = useState<SubscriptionRecurring>(
|
||||||
proSubscription?.recurring ?? SubscriptionRecurring.Yearly
|
proSubscription?.recurring ?? SubscriptionRecurring.Yearly
|
||||||
@@ -334,7 +337,7 @@ export const CloudPlans = () => {
|
|||||||
toggle={cloudToggle}
|
toggle={cloudToggle}
|
||||||
scroll={cloudScroll}
|
scroll={cloudScroll}
|
||||||
scrollRef={scrollWrapper}
|
scrollRef={scrollWrapper}
|
||||||
lifetime={<LifetimePlan />}
|
lifetime={isOnetimePro ? null : <LifetimePlan />}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { SubscriptionRecurring } from '@affine/graphql';
|
|||||||
import { Trans, useI18n } from '@affine/i18n';
|
import { Trans, useI18n } from '@affine/i18n';
|
||||||
import { useLiveData, useService } from '@toeverything/infra';
|
import { useLiveData, useService } from '@toeverything/infra';
|
||||||
|
|
||||||
import { RedeemCode, Upgrade } from '../plan-card';
|
import { Upgrade } from '../plan-card';
|
||||||
import { BelieverCard } from './believer-card';
|
import { BelieverCard } from './believer-card';
|
||||||
import { BelieverBenefits } from './benefits';
|
import { BelieverBenefits } from './benefits';
|
||||||
import * as styles from './style.css';
|
import * as styles from './style.css';
|
||||||
@@ -17,7 +17,6 @@ export const LifetimePlan = () => {
|
|||||||
subscriptionService.prices.readableLifetimePrice$
|
subscriptionService.prices.readableLifetimePrice$
|
||||||
);
|
);
|
||||||
const isBeliever = useLiveData(subscriptionService.subscription.isBeliever$);
|
const isBeliever = useLiveData(subscriptionService.subscription.isBeliever$);
|
||||||
const isOnetime = useLiveData(subscriptionService.subscription.isOnetimePro$);
|
|
||||||
|
|
||||||
if (!readableLifetimePrice) return null;
|
if (!readableLifetimePrice) return null;
|
||||||
|
|
||||||
@@ -37,8 +36,6 @@ export const LifetimePlan = () => {
|
|||||||
<Button className={styles.purchase} size="default" disabled>
|
<Button className={styles.purchase} size="default" disabled>
|
||||||
{t['com.affine.payment.lifetime.purchased']()}
|
{t['com.affine.payment.lifetime.purchased']()}
|
||||||
</Button>
|
</Button>
|
||||||
) : isOnetime ? (
|
|
||||||
<RedeemCode className={styles.purchase} size="default" />
|
|
||||||
) : (
|
) : (
|
||||||
<Upgrade
|
<Upgrade
|
||||||
className={styles.purchase}
|
className={styles.purchase}
|
||||||
|
|||||||
Reference in New Issue
Block a user