fix(core): adjust onetime subscription ui for billing and pricing (#8591)

close AF-1534
This commit is contained in:
CatsJuice
2024-10-25 03:59:05 +00:00
parent 8f694aceb7
commit 829361a910
4 changed files with 60 additions and 42 deletions

View File

@@ -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}

View File

@@ -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({

View File

@@ -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 />}
/> />
); );
}; };

View File

@@ -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}