diff --git a/packages/frontend/core/src/components/affine/setting-modal/general-setting/plans/ai/actions/subscribe.tsx b/packages/frontend/core/src/components/affine/setting-modal/general-setting/plans/ai/actions/subscribe.tsx
index c44cdd6243..c8d7e5a359 100644
--- a/packages/frontend/core/src/components/affine/setting-modal/general-setting/plans/ai/actions/subscribe.tsx
+++ b/packages/frontend/core/src/components/affine/setting-modal/general-setting/plans/ai/actions/subscribe.tsx
@@ -1,7 +1,6 @@
import { Button, type ButtonProps } from '@affine/component';
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
import { SubscriptionService } from '@affine/core/modules/cloud';
-import { getAffineCloudBaseUrl } from '@affine/core/modules/cloud/services/fetch';
import { popupWindow } from '@affine/core/utils';
import { SubscriptionPlan, SubscriptionRecurring } from '@affine/graphql';
import { useAFFiNEI18N } from '@affine/i18n/hooks';
@@ -43,7 +42,7 @@ export const AISubscribe = ({ ...btnProps }: AISubscribeProps) => {
idempotencyKey,
plan: SubscriptionPlan.AI,
coupon: null,
- successCallbackLink: getAffineCloudBaseUrl() + '/ai-upgrade-success',
+ successCallbackLink: null,
});
popupWindow(session);
setOpenedExternalWindow(true);
diff --git a/packages/frontend/core/src/components/affine/subscription-landing/index.tsx b/packages/frontend/core/src/components/affine/subscription-landing/index.tsx
index 1da4f1ee23..026d66460a 100644
--- a/packages/frontend/core/src/components/affine/subscription-landing/index.tsx
+++ b/packages/frontend/core/src/components/affine/subscription-landing/index.tsx
@@ -4,6 +4,7 @@ import { useNavigateHelper } from '@affine/core/hooks/use-navigate-helper';
import { Trans } from '@affine/i18n';
import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { type ReactNode, useCallback } from 'react';
+import { useSearchParams } from 'react-router-dom';
import * as styles from './styles.css';
@@ -15,11 +16,16 @@ const UpgradeSuccessLayout = ({
description?: ReactNode;
}) => {
const t = useAFFiNEI18N();
+ const [params] = useSearchParams();
- const { jumpToIndex } = useNavigateHelper();
+ const { jumpToIndex, openInApp } = useNavigateHelper();
const openAffine = useCallback(() => {
- jumpToIndex();
- }, [jumpToIndex]);
+ if (params.get('schema')) {
+ openInApp(params.get('schema') ?? 'affine', 'bring-to-front');
+ } else {
+ jumpToIndex();
+ }
+ }, [jumpToIndex, openInApp, params]);
const subtitle = (
diff --git a/packages/frontend/core/src/hooks/use-navigate-helper.ts b/packages/frontend/core/src/hooks/use-navigate-helper.ts
index 5c86cdd4af..c15a2a5218 100644
--- a/packages/frontend/core/src/hooks/use-navigate-helper.ts
+++ b/packages/frontend/core/src/hooks/use-navigate-helper.ts
@@ -155,6 +155,14 @@ export function useNavigateHelper() {
[navigate]
);
+ const openInApp = useCallback(
+ (schema: string, path: string) => {
+ const encodedUrl = encodeURIComponent(`${schema}://${path}`);
+ return navigate(`/open-app/url?schema=${schema}&url=${encodedUrl}`);
+ },
+ [navigate]
+ );
+
return useMemo(
() => ({
jumpToPage,
@@ -169,6 +177,7 @@ export function useNavigateHelper() {
jumpToCollections,
jumpToTags,
jumpToTag,
+ openInApp,
}),
[
jumpToPage,
@@ -183,6 +192,7 @@ export function useNavigateHelper() {
jumpToCollections,
jumpToTags,
jumpToTag,
+ openInApp,
]
);
}
diff --git a/packages/frontend/core/src/modules/cloud/stores/subscription.ts b/packages/frontend/core/src/modules/cloud/stores/subscription.ts
index 8524ee0e9d..fa49ba043d 100644
--- a/packages/frontend/core/src/modules/cloud/stores/subscription.ts
+++ b/packages/frontend/core/src/modules/cloud/stores/subscription.ts
@@ -1,6 +1,5 @@
import type {
CreateCheckoutSessionInput,
- SubscriptionPlan,
SubscriptionRecurring,
} from '@affine/graphql';
import {
@@ -8,6 +7,7 @@ import {
createCheckoutSessionMutation,
pricesQuery,
resumeSubscriptionMutation,
+ SubscriptionPlan,
subscriptionQuery,
updateSubscriptionMutation,
} from '@affine/graphql';
@@ -15,10 +15,24 @@ import type { GlobalCacheService } from '@toeverything/infra';
import { Store } from '@toeverything/infra';
import type { SubscriptionType } from '../entities/subscription';
+import { getAffineCloudBaseUrl } from '../services/fetch';
import type { GraphQLService } from '../services/graphql';
const SUBSCRIPTION_CACHE_KEY = 'subscription:';
+const getDefaultSubscriptionSuccessCallbackLink = (
+ plan: SubscriptionPlan | null
+) => {
+ const path =
+ plan === SubscriptionPlan.AI ? '/ai-upgrade-success' : '/upgrade-success';
+ const urlString = getAffineCloudBaseUrl() + path;
+ const url = new URL(urlString);
+ if (environment.isDesktop) {
+ url.searchParams.set('schema', window.appInfo.schema);
+ }
+ return url.toString();
+};
+
export class SubscriptionStore extends Store {
constructor(
private readonly gqlService: GraphQLService,
@@ -112,7 +126,14 @@ export class SubscriptionStore extends Store {
async createCheckoutSession(input: CreateCheckoutSessionInput) {
const data = await this.gqlService.gql({
query: createCheckoutSessionMutation,
- variables: { input },
+ variables: {
+ input: {
+ ...input,
+ successCallbackLink:
+ input.successCallbackLink ||
+ getDefaultSubscriptionSuccessCallbackLink(input.plan),
+ },
+ },
});
return data.createCheckoutSession;
}
diff --git a/packages/frontend/electron/renderer/app.tsx b/packages/frontend/electron/renderer/app.tsx
index c0e0f09f73..240f354529 100644
--- a/packages/frontend/electron/renderer/app.tsx
+++ b/packages/frontend/electron/renderer/app.tsx
@@ -32,6 +32,7 @@ import { RouterProvider } from 'react-router-dom';
const desktopWhiteList = [
'/desktop-signin',
'/open-app/signin-redirect',
+ '/open-app/url',
'/upgrade-success',
'/ai-upgrade-success',
];
diff --git a/packages/frontend/electron/src/main/deep-link.ts b/packages/frontend/electron/src/main/deep-link.ts
index e0c88af7fb..df762d7161 100644
--- a/packages/frontend/electron/src/main/deep-link.ts
+++ b/packages/frontend/electron/src/main/deep-link.ts
@@ -67,6 +67,12 @@ async function handleAffineUrl(url: string) {
if (urlObj.hostname === 'signin-redirect') {
await handleOauthJwt(url);
}
+ if (urlObj.hostname === 'bring-to-front') {
+ const mainWindow = await getMainWindow();
+ if (mainWindow) {
+ mainWindow.show();
+ }
+ }
}
async function handleOauthJwt(url: string) {