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) {