chore: cleanup legacy logic (#15072)

This commit is contained in:
DarkSky
2026-06-03 16:20:15 +08:00
committed by GitHub
parent 8c0e1ba04e
commit 81760fd45c
142 changed files with 3351 additions and 2449 deletions
@@ -184,7 +184,10 @@ Could you make a new website based on these notes and send back just the html fi
? filterStyleToPromptName.get(options.style)
: undefined,
actionVersion: 'v1',
buildContent: options => options.input,
buildContent: options =>
!options.input && options.attachments
? `Apply the ${options.style} to this image.`
: options.input,
},
processImage: {
id: 'processImage',
@@ -200,7 +203,10 @@ Could you make a new website based on these notes and send back just the html fi
},
responseType: 'image',
timeout: 180000,
buildContent: options => options.input,
buildContent: options =>
!options.input && options.attachments
? `Apply ${options.type} processing to this image.`
: options.input,
},
generateCaption: textAction('generateCaption', 'Generate a caption'),
continueWriting: textAction('continueWriting', 'Continue writing'),
@@ -7,7 +7,6 @@ import { useLiveData, useService } from '@toeverything/infra';
import { useEffect, useMemo } from 'react';
import { AICancel, AIResume, AISubscribe } from '../plans/ai/actions';
import { AIRedeemCodeButton } from '../plans/ai/actions/redeem';
import { CardNameLabelRow } from './card-name-label-row';
import { PaymentMethodUpdater } from './payment-method';
import * as styles from './style.css';
@@ -21,7 +20,6 @@ export const AIPlanCard = ({ onClick }: { onClick: () => void }) => {
}, [subscriptionService]);
const price = useLiveData(subscriptionService.prices.aiPrice$);
const subscription = useLiveData(subscriptionService.subscription.ai$);
const isOnetime = useLiveData(subscriptionService.subscription.isOnetimeAI$);
const priceReadable = price?.yearlyAmount
? `$${(price.yearlyAmount / 100).toFixed(2)}`
@@ -53,13 +51,13 @@ export const AIPlanCard = ({ onClick }: { onClick: () => void }) => {
}),
});
}
if ((isOnetime || subscription?.canceledAt) && subscription?.end) {
if (subscription?.canceledAt && subscription?.end) {
return t['com.affine.payment.ai.billing-tip.end-at']({
end: i18nTime(subscription.end, { absolute: { accuracy: 'day' } }),
});
}
return null;
}, [subscription, isOnetime, onClick, t]);
}, [subscription, onClick, t]);
if (subscription === null) {
return <Skeleton height={100} />;
@@ -82,9 +80,7 @@ export const AIPlanCard = ({ onClick }: { onClick: () => void }) => {
<div className={styles.planActionContainer}>
{price?.yearlyAmount ? (
subscription ? (
isOnetime ? (
<AIRedeemCodeButton className={styles.planAction} />
) : subscription.canceledAt ? (
subscription.canceledAt ? (
<AIResume className={styles.planAction} />
) : (
<AICancel className={styles.planAction} />
@@ -59,8 +59,11 @@ export const BillingHistory = () => {
{t['com.affine.payment.billing-setting.no-invoice']()}
</p>
) : (
pageInvoices?.map(invoice => (
<InvoiceLine key={invoice.id} invoice={invoice} />
pageInvoices?.map((invoice, index) => (
<InvoiceLine
key={`${invoice.createdAt}:${invoice.status}:${invoice.amount}:${index}`}
invoice={invoice}
/>
))
)}
</div>
@@ -93,7 +96,6 @@ const InvoiceLine = ({
return (
<SettingRow
key={invoice.id}
name={new Date(invoice.createdAt).toLocaleDateString()}
desc={`${
invoice.status === InvoiceStatus.Paid
@@ -29,7 +29,6 @@ export const PaymentMethod = () => {
const proSubscription = useLiveData(subscriptionService.subscription.pro$);
const isBeliever = useLiveData(subscriptionService.subscription.isBeliever$);
const isOnetime = useLiveData(subscriptionService.subscription.isOnetimeAI$);
const [openCancelModal, setOpenCancelModal] = useState(false);
return (
@@ -43,7 +42,7 @@ export const PaymentMethod = () => {
>
<PaymentMethodUpdater />
</SettingRow>
{isBeliever || isOnetime ? null : proSubscription?.end &&
{isBeliever ? null : proSubscription?.end &&
proSubscription?.canceledAt ? (
<SettingRow
name={t['com.affine.payment.billing-setting.expiration-date']()}
@@ -10,7 +10,6 @@ import { type I18nString, i18nTime, Trans, useI18n } from '@affine/i18n';
import { useLiveData, useService } from '@toeverything/infra';
import { useEffect } from 'react';
import { RedeemCode } from '../plans/plan-card';
import { CardNameLabelRow } from './card-name-label-row';
import { PaymentMethodUpdater } from './payment-method';
import * as styles from './style.css';
@@ -157,13 +156,6 @@ const PlanAction = ({
}) => {
const t = useI18n();
const subscription = useService(SubscriptionService).subscription;
const isOnetimePro = useLiveData(subscription.isOnetimePro$);
if (isOnetimePro) {
return <RedeemCode variant="primary" className={styles.planAction} />;
}
return (
<div className={styles.planActionContainer}>
<Button
@@ -1,52 +0,0 @@
import { Button, type ButtonProps } from '@affine/component';
import { generateSubscriptionCallbackLink } from '@affine/core/components/hooks/affine/use-subscription-notify';
import { AuthService } from '@affine/core/modules/cloud';
import {
SubscriptionPlan,
SubscriptionRecurring,
SubscriptionVariant,
} from '@affine/graphql';
import { useI18n } from '@affine/i18n';
import track from '@affine/track';
import { useService } from '@toeverything/infra';
import { useCallback, useMemo } from 'react';
import { CheckoutSlot } from '../../checkout-slot';
export const AIRedeemCodeButton = (btnProps: ButtonProps) => {
const t = useI18n();
const authService = useService(AuthService);
const onBeforeCheckout = useCallback(() => {
track.$.settingsPanel.plans.checkout({
plan: SubscriptionPlan.AI,
recurring: SubscriptionRecurring.Yearly,
});
}, []);
const checkoutOptions = useMemo(
() => ({
recurring: SubscriptionRecurring.Yearly,
plan: SubscriptionPlan.AI,
variant: SubscriptionVariant.Onetime,
coupon: null,
successCallbackLink: generateSubscriptionCallbackLink(
authService.session.account$.value,
SubscriptionPlan.AI,
SubscriptionRecurring.Yearly
),
}),
[authService.session.account$.value]
);
return (
<CheckoutSlot
onBeforeCheckout={onBeforeCheckout}
checkoutOptions={checkoutOptions}
renderer={props => (
<Button variant="primary" {...btnProps} {...props}>
{t['com.affine.payment.redeem-code']()}
</Button>
)}
/>
);
};
@@ -5,7 +5,6 @@ import { useLiveData, useService } from '@toeverything/infra';
import { useEffect } from 'react';
import { AICancel, AILogin, AIResume, AISubscribe } from './actions';
import { AIRedeemCodeButton } from './actions/redeem';
import * as styles from './ai-plan.css';
import { AIPlanLayout } from './layout';
@@ -18,7 +17,6 @@ export const AIPlan = () => {
const price = useLiveData(subscriptionService.prices.aiPrice$);
const isLoggedIn =
useLiveData(authService.session.status$) === 'authenticated';
const isOnetime = useLiveData(subscriptionService.subscription.isOnetimeAI$);
useEffect(() => {
subscriptionService.subscription.revalidate();
@@ -54,9 +52,7 @@ export const AIPlan = () => {
actionButtons={
isLoggedIn ? (
subscription ? (
isOnetime ? (
<AIRedeemCodeButton className={styles.purchaseButton} />
) : subscription.canceledAt ? (
subscription.canceledAt ? (
<AIResume className={styles.purchaseButton} />
) : (
<AICancel className={styles.purchaseButton} />
@@ -198,9 +198,6 @@ export const CloudPlans = () => {
const prices = useLiveData(subscriptionService.prices.prices$);
const loggedIn = useLiveData(authService.session.status$) === 'authenticated';
const proSubscription = useLiveData(subscriptionService.subscription.pro$);
const isOnetimePro = useLiveData(
subscriptionService.subscription.isOnetimePro$
);
const [recurring, setRecurring] = useState<SubscriptionRecurring>(
proSubscription?.recurring ?? SubscriptionRecurring.Yearly
@@ -352,7 +349,7 @@ export const CloudPlans = () => {
toggle={cloudToggle}
scroll={cloudScroll}
scrollRef={scrollWrapper as RefObject<HTMLDivElement>}
lifetime={isOnetimePro ? null : <LifetimePlan />}
lifetime={<LifetimePlan />}
/>
);
};
@@ -12,9 +12,8 @@ import { UrlService } from '@affine/core/modules/url';
import {
type CreateCheckoutSessionInput,
SubscriptionPlan,
SubscriptionRecurring,
type SubscriptionRecurring,
SubscriptionStatus,
SubscriptionVariant,
} from '@affine/graphql';
import { Trans, useI18n } from '@affine/i18n';
import { track } from '@affine/track';
@@ -119,7 +118,6 @@ const ActionButton = ({ detail, recurring }: PlanCardProps) => {
);
const currentPlan = primarySubscription?.plan ?? SubscriptionPlan.Free;
const currentRecurring = primarySubscription?.recurring;
const isOnetime = useLiveData(subscriptionService.subscription.isOnetimePro$);
const isFree = detail.plan === SubscriptionPlan.Free;
const signUpText = useMemo(
@@ -136,9 +134,6 @@ const ActionButton = ({ detail, recurring }: PlanCardProps) => {
// else
// if team => 'Start 14-day free trial'
// if isBeliever => 'Included in Lifetime'
// if onetime
// if free => 'Included in Pro'
// else => 'Redeem Code'
// if isCurrent
// if canceled => 'Resume'
// else => 'Current Plan'
@@ -165,17 +160,6 @@ const ActionButton = ({ detail, recurring }: PlanCardProps) => {
);
}
// onetime
if (isOnetime) {
return isFree ? (
<Button className={styles.planAction} disabled>
{t['com.affine.payment.cloud.onetime.included']()}
</Button>
) : (
<RedeemCode recurring={recurring} />
);
}
const isCanceled = !!primarySubscription?.canceledAt;
const isCurrent =
detail.plan === currentPlan &&
@@ -471,29 +455,3 @@ const ResumeButton = () => {
</ResumeAction>
);
};
const redeemCodeCheckoutInput = { variant: SubscriptionVariant.Onetime };
export const RedeemCode = ({
className,
recurring = SubscriptionRecurring.Yearly,
plan,
children,
...btnProps
}: ButtonProps & {
recurring?: SubscriptionRecurring;
plan?: SubscriptionPlan;
}) => {
const t = useI18n();
return (
<Upgrade
recurring={recurring}
className={className}
checkoutInput={redeemCodeCheckoutInput}
plan={plan ?? SubscriptionPlan.Pro}
{...btnProps}
>
{children ?? t['com.affine.payment.redeem-code']()}
</Upgrade>
);
};
@@ -55,8 +55,11 @@ export const BillingHistory = () => {
{t['com.affine.payment.billing-setting.no-invoice']()}
</p>
) : (
pageInvoices?.map(invoice => (
<InvoiceLine key={invoice.id} invoice={invoice} />
pageInvoices?.map((invoice, index) => (
<InvoiceLine
key={`${invoice.createdAt}:${invoice.status}:${invoice.amount}:${index}`}
invoice={invoice}
/>
))
)}
</div>
@@ -89,7 +92,6 @@ const InvoiceLine = ({
return (
<SettingRow
key={invoice.id}
name={new Date(invoice.createdAt).toLocaleDateString()}
desc={`${
invoice.status === InvoiceStatus.Paid
@@ -213,21 +213,12 @@ export const CloudWorkspaceMembersPanel = ({
return;
}
const results = await membersService.inviteMembers(uniqueEmails);
const unSuccessInvites = results.reduce<string[]>((acc, result) => {
if (!result.sentSuccess) {
acc.push(result.email);
}
return acc;
}, []);
if (results) {
notify({
title: t['com.affine.payment.member.team.invite.notify.title']({
successCount: (
uniqueEmails.length - unSuccessInvites.length
).toString(),
failedCount: unSuccessInvites.length.toString(),
count: results.length.toString(),
}),
message: <NotifyMessage unSuccessInvites={unSuccessInvites} />,
message: t['Invitation sent hint'](),
});
setOpenInvite(false);
membersService.members.revalidate();
@@ -351,27 +342,6 @@ export const CloudWorkspaceMembersPanel = ({
);
};
const NotifyMessage = ({
unSuccessInvites,
}: {
unSuccessInvites: string[];
}) => {
const t = useI18n();
if (unSuccessInvites.length === 0) {
return t['Invitation sent hint']();
}
return (
<div>
{t['com.affine.payment.member.team.invite.notify.fail-message']()}
{unSuccessInvites.map((email, index) => (
<div key={`${index}:${email}`}>{email}</div>
))}
</div>
);
};
export const MembersPanelFallback = () => {
const t = useI18n();
@@ -1,11 +1,7 @@
import { Button, Loading } from '@affine/component';
import { UrlService } from '@affine/core/modules/url';
import { UserFriendlyError } from '@affine/error';
import {
SubscriptionPlan,
SubscriptionRecurring,
SubscriptionVariant,
} from '@affine/graphql';
import { SubscriptionPlan, SubscriptionRecurring } from '@affine/graphql';
import { track } from '@affine/track';
import { effect, fromPromise, useServices } from '@toeverything/infra';
import { nanoid } from 'nanoid';
@@ -24,7 +20,7 @@ import { container } from './subscribe.css';
interface ProductTriple {
plan: SubscriptionPlan;
recurring: SubscriptionRecurring;
variant: SubscriptionVariant | null;
variant: null;
}
const products = {
@@ -36,9 +32,6 @@ const products = {
'monthly-team': 'team_monthly',
'yearly-selfhost-team': 'selfhost-team_yearly',
'monthly-selfhost-team': 'selfhost-team_monthly',
'oneyear-ai': 'ai_yearly_onetime',
'oneyear-pro': 'pro_yearly_onetime',
'onemonth-pro': 'pro_monthly_onetime',
};
const allowedPlan = {
@@ -53,11 +46,6 @@ const allowedRecurring = {
lifetime: SubscriptionRecurring.Lifetime,
};
const allowedVariant = {
earlyaccess: SubscriptionVariant.EA,
onetime: SubscriptionVariant.Onetime,
};
function getProductTriple(searchParams: URLSearchParams): ProductTriple {
const triple: ProductTriple = {
plan: SubscriptionPlan.Pro,
@@ -72,13 +60,10 @@ function getProductTriple(searchParams: URLSearchParams): ProductTriple {
let recurring = searchParams.get('recurring') as
| keyof typeof allowedRecurring
| null;
let variant = searchParams.get('variant') as
| keyof typeof allowedVariant
| null;
if (productName && products[productName]) {
// @ts-expect-error safe
[plan, recurring, variant] = products[productName].split('_');
[plan, recurring] = products[productName].split('_');
}
if (plan) {
@@ -88,9 +73,6 @@ function getProductTriple(searchParams: URLSearchParams): ProductTriple {
if (recurring) {
triple.recurring = allowedRecurring[recurring];
}
if (variant) {
triple.variant = allowedVariant[variant];
}
return triple;
}
@@ -2,7 +2,6 @@ import {
SubscriptionPlan,
type SubscriptionQuery,
SubscriptionRecurring,
SubscriptionVariant,
} from '@affine/graphql';
import {
catchErrorInto,
@@ -44,12 +43,6 @@ export class Subscription extends Entity {
isBeliever$ = this.pro$.map(
sub => sub?.recurring === SubscriptionRecurring.Lifetime
);
isOnetimePro$ = this.pro$.map(
sub => sub?.variant === SubscriptionVariant.Onetime
);
isOnetimeAI$ = this.ai$.map(
sub => sub?.variant === SubscriptionVariant.Onetime
);
constructor(
private readonly authService: AuthService,
@@ -23,12 +23,6 @@ export class UserFeature extends Entity {
features === null ? null : features?.some(f => f === FeatureType.Admin)
);
isEarlyAccess$ = this.features$.map(features =>
features === null
? null
: features?.some(f => f === FeatureType.EarlyAccess)
);
isRevalidating$ = new LiveData(false);
error$ = new LiveData<any | null>(null);