refactor(router): centralize app route transitions
This commit is contained in:
@@ -5,11 +5,11 @@
|
||||
*
|
||||
*/
|
||||
import { useEffect, useSyncExternalStore } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
import { MobileShell } from "@/app/_components/core";
|
||||
import { useAuthDispatch, useAuthState } from "@/stores/auth/auth-context";
|
||||
import { ROUTES } from "@/router/routes";
|
||||
import { useAppNavigator } from "@/router/use-app-navigator";
|
||||
|
||||
import { AuthBackground, AuthPanel } from "./components";
|
||||
import styles from "./components/auth-screen.module.css";
|
||||
@@ -20,7 +20,7 @@ const log = new Logger("AppAuthAuthScreen");
|
||||
export function AuthScreen() {
|
||||
const state = useAuthState();
|
||||
const authDispatch = useAuthDispatch();
|
||||
const router = useRouter();
|
||||
const navigator = useAppNavigator();
|
||||
const redirectTo = useSyncExternalStore(
|
||||
subscribeLocationSnapshot,
|
||||
readRedirectFromLocation,
|
||||
@@ -40,17 +40,17 @@ export function AuthScreen() {
|
||||
});
|
||||
|
||||
if (state.pendingRedirect && state.loginStatus !== "notLoggedIn") {
|
||||
log.debug("[auth-screen] useEffect → router.replace [via pendingRedirect flag]", {
|
||||
log.debug("[auth-screen] useEffect → navigator.replace [via pendingRedirect flag]", {
|
||||
redirectTo: safeRedirectTo,
|
||||
});
|
||||
authDispatch({ type: "AuthClearPendingRedirect" });
|
||||
router.replace(safeRedirectTo);
|
||||
navigator.replace(safeRedirectTo);
|
||||
}
|
||||
}, [
|
||||
state.loginStatus,
|
||||
state.pendingRedirect,
|
||||
authDispatch,
|
||||
router,
|
||||
navigator,
|
||||
safeRedirectTo,
|
||||
]);
|
||||
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
/**
|
||||
* 认证面板:顶层 switch(Facebook / Email)+ 悬浮返回按钮
|
||||
*/
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
import { BackButton } from "@/app/_components";
|
||||
import { useAppNavigator } from "@/router/use-app-navigator";
|
||||
import { useAuthDispatch, useAuthState } from "@/stores/auth/auth-context";
|
||||
|
||||
import { AuthEmailPanel } from "./auth-email-panel";
|
||||
@@ -14,7 +13,7 @@ import styles from "./auth-panel.module.css";
|
||||
export function AuthPanel() {
|
||||
const state = useAuthState();
|
||||
const dispatch = useAuthDispatch();
|
||||
const router = useRouter();
|
||||
const navigator = useAppNavigator();
|
||||
|
||||
const switchToFacebook = () =>
|
||||
dispatch({ type: "AuthPanelModeChanged", mode: "facebook" });
|
||||
@@ -25,7 +24,7 @@ export function AuthPanel() {
|
||||
if (state.authPanelMode === "email") {
|
||||
switchToFacebook();
|
||||
} else {
|
||||
router.back();
|
||||
navigator.back();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -9,10 +9,9 @@
|
||||
* - 错误占位符(broken image icon)
|
||||
*/
|
||||
import Image from "next/image";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useState } from "react";
|
||||
|
||||
import { ROUTE_BUILDERS } from "@/router/routes";
|
||||
import { useAppNavigator } from "@/router/use-app-navigator";
|
||||
import {
|
||||
isBrowserLocalChatImageSource,
|
||||
normalizeChatImageSource,
|
||||
@@ -33,7 +32,7 @@ export function ImageBubble({
|
||||
imageUrl,
|
||||
imagePaywalled = false,
|
||||
}: ImageBubbleProps) {
|
||||
const router = useRouter();
|
||||
const navigator = useAppNavigator();
|
||||
const [errorSrc, setErrorSrc] = useState<string | null>(null);
|
||||
const { mediaUrl, isUsingCachedMedia, reportMediaError } =
|
||||
useCachedChatMediaUrl({
|
||||
@@ -58,7 +57,7 @@ export function ImageBubble({
|
||||
const openImage = () => {
|
||||
if (!messageId) return;
|
||||
requestChatScrollSnapshotSave(messageId);
|
||||
router.push(ROUTE_BUILDERS.chatImage(messageId), { scroll: false });
|
||||
navigator.openChatImage(messageId);
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -6,14 +6,13 @@
|
||||
* 设计:
|
||||
* - 不走 Server `redirect()`:避免把 fbid 暴露在 URL 里。
|
||||
* - deviceId / fbid / avatarUrl 统一交给 `lib/chat` 落地。
|
||||
* - 写入完成后 `router.replace('/chat')`,URL 不留深链痕迹。
|
||||
* - 写入完成后通过统一导航回到 `/chat`,URL 不留深链痕迹。
|
||||
*/
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
import { persistExternalBrowserChatDeepLink } from "@/lib/chat/chat_external_browser";
|
||||
import { ROUTES } from "@/router/routes";
|
||||
import { useAppNavigator } from "@/router/use-app-navigator";
|
||||
import { Logger } from "@/utils";
|
||||
|
||||
const log = new Logger("AppChatDeviceidDeviceIdDeepLinkPersist");
|
||||
@@ -29,7 +28,7 @@ export default function DeepLinkPersist({
|
||||
fbid,
|
||||
avatarUrl,
|
||||
}: DeepLinkPersistProps) {
|
||||
const router = useRouter();
|
||||
const navigator = useAppNavigator();
|
||||
const [done, setDone] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -45,10 +44,10 @@ export default function DeepLinkPersist({
|
||||
log.warn("[DeepLinkPersist] failed to persist", err);
|
||||
} finally {
|
||||
setDone(true);
|
||||
router.replace(ROUTES.chat);
|
||||
navigator.openChat({ replace: true });
|
||||
}
|
||||
})();
|
||||
}, [avatarUrl, deviceId, fbid, router]);
|
||||
}, [avatarUrl, deviceId, fbid, navigator]);
|
||||
|
||||
return (
|
||||
<div
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* 对齐 Flutter `lib/router/app_router.dart:60-78` 的 `GoRoute(path: '/chat/deviceid/:deviceId')`:
|
||||
* 把 `deviceId` 路径参数与 `fbid` / `avatarUrl` 查询参数透传给 Client 组件
|
||||
* `<DeepLinkPersist>`,由它把数据写入 localStorage 后 `router.replace('/chat')`。
|
||||
* `<DeepLinkPersist>`,由它把数据写入 localStorage 后通过统一导航回到 `/chat`。
|
||||
*
|
||||
* Next.js 15+ 约定:`params` / `searchParams` 是 Promise,必须 await。
|
||||
* Next.js 16 全局 helper `PageProps<'/literal'>` 由 `next dev` / `next build` /
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
"use client";
|
||||
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
import { MobileShell } from "@/app/_components/core";
|
||||
import { ROUTE_BUILDERS, ROUTES } from "@/router/routes";
|
||||
import { ROUTE_BUILDERS } from "@/router/routes";
|
||||
import { useAppNavigator } from "@/router/use-app-navigator";
|
||||
import { useChatDispatch, useChatState } from "@/stores/chat/chat-context";
|
||||
|
||||
import {
|
||||
@@ -21,7 +20,7 @@ export interface ChatImageViewerScreenProps {
|
||||
export function ChatImageViewerScreen({
|
||||
messageId,
|
||||
}: ChatImageViewerScreenProps) {
|
||||
const router = useRouter();
|
||||
const navigator = useAppNavigator();
|
||||
const chatState = useChatState();
|
||||
const chatDispatch = useChatDispatch();
|
||||
const returnUrl = ROUTE_BUILDERS.chatImage(messageId);
|
||||
@@ -40,7 +39,7 @@ export function ChatImageViewerScreen({
|
||||
);
|
||||
|
||||
const handleClose = () => {
|
||||
router.push(ROUTES.chat, { scroll: false });
|
||||
navigator.openChat({ scroll: false });
|
||||
};
|
||||
|
||||
const handleUnlockImagePaywall = () => {
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
import { MobileShell } from "@/app/_components/core";
|
||||
import { hasBusinessLoginToken } from "@/lib/auth/auth_session";
|
||||
import { useAppNavigator } from "@/router/use-app-navigator";
|
||||
import { useAuthDispatch, useAuthState } from "@/stores/auth/auth-context";
|
||||
import { ROUTES } from "@/router/routes";
|
||||
import { pwaUtil, Logger } from "@/utils";
|
||||
|
||||
import {
|
||||
@@ -25,13 +24,13 @@ if (typeof window !== "undefined") {
|
||||
}
|
||||
|
||||
export function SplashScreen() {
|
||||
const router = useRouter();
|
||||
const navigator = useAppNavigator();
|
||||
const state = useAuthState();
|
||||
const authDispatch = useAuthDispatch();
|
||||
|
||||
const handleSkip = () => {
|
||||
authDispatch({ type: "AuthGuestLoginSubmitted" });
|
||||
router.replace(ROUTES.chat);
|
||||
navigator.openChat({ replace: true });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@@ -49,13 +48,13 @@ export function SplashScreen() {
|
||||
let cancelled = false;
|
||||
void (async () => {
|
||||
if (!cancelled && (await hasBusinessLoginToken())) {
|
||||
router.replace(ROUTES.chat);
|
||||
navigator.openChat({ replace: true });
|
||||
}
|
||||
})();
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [router]);
|
||||
}, [navigator]);
|
||||
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
// useEffect ② 按钮刚派了事件(pendingRedirect=true) +
|
||||
@@ -76,12 +75,12 @@ export function SplashScreen() {
|
||||
|
||||
if (state.pendingRedirect && state.loginStatus !== "notLoggedIn") {
|
||||
log.debug(
|
||||
"[splash] useEffect ② → router.replace(/chat) [via pendingRedirect flag]",
|
||||
"[splash] useEffect ② → navigator.openChat [via pendingRedirect flag]",
|
||||
);
|
||||
authDispatch({ type: "AuthClearPendingRedirect" });
|
||||
router.replace(ROUTES.chat);
|
||||
navigator.openChat({ replace: true });
|
||||
}
|
||||
}, [state.loginStatus, state.pendingRedirect, authDispatch, router]);
|
||||
}, [state.loginStatus, state.pendingRedirect, authDispatch, navigator]);
|
||||
|
||||
return (
|
||||
<MobileShell background="var(--color-sidebar-background)">
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
import { MobileShell } from "@/app/_components/core";
|
||||
import {
|
||||
@@ -9,11 +8,12 @@ import {
|
||||
getPendingPaymentOrder,
|
||||
} from "@/lib/payment/pending_payment_order";
|
||||
import { ROUTES } from "@/router/routes";
|
||||
import { useAppNavigator } from "@/router/use-app-navigator";
|
||||
|
||||
type ReturnStatus = "loading" | "missing";
|
||||
|
||||
export default function SubscriptionReturnPage() {
|
||||
const router = useRouter();
|
||||
const navigator = useAppNavigator();
|
||||
const [status, setStatus] = useState<ReturnStatus>("loading");
|
||||
|
||||
useEffect(() => {
|
||||
@@ -24,7 +24,7 @@ export default function SubscriptionReturnPage() {
|
||||
if (cancelled) return;
|
||||
|
||||
if (result.success && result.data !== null) {
|
||||
router.replace(buildPendingPaymentSubscriptionUrl(result.data));
|
||||
navigator.replace(buildPendingPaymentSubscriptionUrl(result.data));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ export default function SubscriptionReturnPage() {
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [router]);
|
||||
}, [navigator]);
|
||||
|
||||
return (
|
||||
<MobileShell>
|
||||
@@ -62,7 +62,7 @@ export default function SubscriptionReturnPage() {
|
||||
{status === "missing" ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => router.replace(ROUTES.subscription)}
|
||||
onClick={() => navigator.replace(ROUTES.subscription)}
|
||||
style={{
|
||||
marginTop: "0.5rem",
|
||||
padding: "0.75rem 1.5rem",
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
import {
|
||||
consumeSubscriptionExitUrl,
|
||||
peekSubscriptionExplicitExitUrl,
|
||||
} from "@/lib/navigation/subscription_exit";
|
||||
import {
|
||||
clearPendingPaymentOrder,
|
||||
getPendingPaymentOrderForType,
|
||||
} from "@/lib/payment/pending_payment_order";
|
||||
import { useAppNavigator } from "@/router/use-app-navigator";
|
||||
import {
|
||||
usePaymentDispatch,
|
||||
usePaymentState,
|
||||
@@ -33,7 +29,7 @@ export function useSubscriptionPaymentFlow({
|
||||
returnTo,
|
||||
initialPayChannel,
|
||||
}: UseSubscriptionPaymentFlowInput) {
|
||||
const router = useRouter();
|
||||
const navigator = useAppNavigator();
|
||||
const userDispatch = useUserDispatch();
|
||||
const payment = usePaymentState();
|
||||
const paymentDispatch = usePaymentDispatch();
|
||||
@@ -148,22 +144,13 @@ export function useSubscriptionPaymentFlow({
|
||||
}, [payment.currentOrderId, payment.isPaid, payment.status]);
|
||||
|
||||
const handleBackClick = () => {
|
||||
void (async () => {
|
||||
router.replace(await consumeSubscriptionExitUrl(returnTo));
|
||||
})();
|
||||
navigator.exitSubscription(returnTo);
|
||||
};
|
||||
|
||||
const handlePaymentSuccessClose = () => {
|
||||
void (async () => {
|
||||
setShowPaymentSuccessDialog(false);
|
||||
paymentDispatch({ type: "PaymentReset" });
|
||||
const pendingExitUrl = await peekSubscriptionExplicitExitUrl();
|
||||
if (pendingExitUrl) {
|
||||
router.replace(pendingExitUrl);
|
||||
return;
|
||||
}
|
||||
router.replace(await consumeSubscriptionExitUrl(returnTo));
|
||||
})();
|
||||
setShowPaymentSuccessDialog(false);
|
||||
paymentDispatch({ type: "PaymentReset" });
|
||||
navigator.exitSubscriptionAfterSuccess(returnTo);
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
+148
-75
@@ -1,8 +1,14 @@
|
||||
"use client";
|
||||
|
||||
import { useCallback, useMemo } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
import { NavigationStorage } from "@/data/storage/navigation";
|
||||
import type { SubscriptionReturnTo } from "@/lib/navigation/subscription_exit";
|
||||
import {
|
||||
consumeSubscriptionExitUrl,
|
||||
peekSubscriptionExplicitExitUrl,
|
||||
} from "@/lib/navigation/subscription_exit";
|
||||
import { getDefaultPayChannelForCountryCode } from "@/lib/payment/default_pay_channel";
|
||||
import { useAuthState } from "@/stores/auth/auth-context";
|
||||
import { useUserState } from "@/stores/user/user-context";
|
||||
@@ -25,8 +31,13 @@ import type {
|
||||
export interface AppNavigator {
|
||||
push: (href: string, options?: { scroll?: boolean }) => void;
|
||||
replace: (href: string, options?: { scroll?: boolean }) => void;
|
||||
back: () => void;
|
||||
openAuth: (redirectTo?: string) => void;
|
||||
openChat: (options?: { replace?: boolean; scroll?: boolean }) => void;
|
||||
openChatImage: (messageId: string) => void;
|
||||
openSubscription: (input: OpenSubscriptionInput) => void;
|
||||
exitSubscription: (returnTo: SubscriptionReturnTo) => void;
|
||||
exitSubscriptionAfterSuccess: (returnTo: SubscriptionReturnTo) => void;
|
||||
startMessageUnlock: (input: StartMessageUnlockInput) => void;
|
||||
openSubscriptionForPendingUnlock: (
|
||||
input: OpenSubscriptionForPendingUnlockInput,
|
||||
@@ -41,100 +52,162 @@ export function useAppNavigator(): AppNavigator {
|
||||
const userState = useUserState();
|
||||
const isAuthenticatedUser = resolveIsAuthenticatedUser(authState.loginStatus);
|
||||
|
||||
function push(href: string, options?: { scroll?: boolean }): void {
|
||||
const push = useCallback((href: string, options?: { scroll?: boolean }): void => {
|
||||
router.push(href, options);
|
||||
}
|
||||
}, [router]);
|
||||
|
||||
function replace(href: string, options?: { scroll?: boolean }): void {
|
||||
const replace = useCallback((href: string, options?: { scroll?: boolean }): void => {
|
||||
router.replace(href, options);
|
||||
}
|
||||
}, [router]);
|
||||
|
||||
function openAuth(redirectTo: string = ROUTES.chat): void {
|
||||
const back = useCallback((): void => {
|
||||
router.back();
|
||||
}, [router]);
|
||||
|
||||
const openAuth = useCallback((redirectTo: string = ROUTES.chat): void => {
|
||||
router.push(ROUTE_BUILDERS.authWithRedirect(redirectTo));
|
||||
}
|
||||
}, [router]);
|
||||
|
||||
function getDefaultPayChannel() {
|
||||
const openChat = useCallback((options: { replace?: boolean; scroll?: boolean } = {}): void => {
|
||||
const navOptions = { scroll: options.scroll ?? false };
|
||||
if (options.replace) {
|
||||
router.replace(ROUTES.chat, navOptions);
|
||||
return;
|
||||
}
|
||||
router.push(ROUTES.chat, navOptions);
|
||||
}, [router]);
|
||||
|
||||
const openChatImage = useCallback((messageId: string): void => {
|
||||
router.push(ROUTE_BUILDERS.chatImage(messageId), { scroll: false });
|
||||
}, [router]);
|
||||
|
||||
const getDefaultPayChannel = useCallback(() => {
|
||||
return getDefaultPayChannelForCountryCode(userState.currentUser?.countryCode);
|
||||
}
|
||||
}, [userState.currentUser?.countryCode]);
|
||||
|
||||
function openSubscription({
|
||||
type,
|
||||
payChannel = getDefaultPayChannel(),
|
||||
returnTo = null,
|
||||
replace: shouldReplace = false,
|
||||
}: OpenSubscriptionInput): void {
|
||||
const target = ROUTE_BUILDERS.subscription(type, {
|
||||
payChannel,
|
||||
returnTo: returnTo ?? undefined,
|
||||
});
|
||||
|
||||
const nextUrl = resolveAuthenticatedNavigation({
|
||||
loginStatus: authState.loginStatus,
|
||||
targetUrl: target,
|
||||
});
|
||||
|
||||
if (shouldReplace) {
|
||||
router.replace(nextUrl);
|
||||
return;
|
||||
}
|
||||
router.push(nextUrl);
|
||||
}
|
||||
|
||||
function startMessageUnlock({
|
||||
messageId,
|
||||
kind,
|
||||
returnUrl,
|
||||
stage = "auth",
|
||||
onAuthenticated,
|
||||
}: StartMessageUnlockInput): void {
|
||||
if (isAuthenticatedUser) {
|
||||
onAuthenticated();
|
||||
return;
|
||||
}
|
||||
|
||||
void (async () => {
|
||||
await NavigationStorage.savePendingChatUnlock({
|
||||
messageId,
|
||||
kind,
|
||||
returnUrl,
|
||||
stage,
|
||||
});
|
||||
router.push(ROUTE_BUILDERS.authWithRedirect(returnUrl));
|
||||
})();
|
||||
}
|
||||
|
||||
function openSubscriptionForPendingUnlock({
|
||||
messageId,
|
||||
kind,
|
||||
returnUrl,
|
||||
type,
|
||||
payChannel = getDefaultPayChannel(),
|
||||
}: OpenSubscriptionForPendingUnlockInput): void {
|
||||
void (async () => {
|
||||
await NavigationStorage.savePendingChatUnlock({
|
||||
messageId,
|
||||
kind,
|
||||
returnUrl,
|
||||
stage: "payment",
|
||||
});
|
||||
openSubscription({
|
||||
type,
|
||||
const openSubscription = useCallback(
|
||||
({
|
||||
type,
|
||||
payChannel = getDefaultPayChannel(),
|
||||
returnTo = null,
|
||||
replace: shouldReplace = false,
|
||||
}: OpenSubscriptionInput): void => {
|
||||
const target = ROUTE_BUILDERS.subscription(type, {
|
||||
payChannel,
|
||||
returnTo: "chat",
|
||||
returnTo: returnTo ?? undefined,
|
||||
});
|
||||
})();
|
||||
}
|
||||
|
||||
return {
|
||||
const nextUrl = resolveAuthenticatedNavigation({
|
||||
loginStatus: authState.loginStatus,
|
||||
targetUrl: target,
|
||||
});
|
||||
|
||||
if (shouldReplace) {
|
||||
router.replace(nextUrl);
|
||||
return;
|
||||
}
|
||||
router.push(nextUrl);
|
||||
},
|
||||
[authState.loginStatus, getDefaultPayChannel, router],
|
||||
);
|
||||
|
||||
const startMessageUnlock = useCallback(
|
||||
({
|
||||
messageId,
|
||||
kind,
|
||||
returnUrl,
|
||||
stage = "auth",
|
||||
onAuthenticated,
|
||||
}: StartMessageUnlockInput): void => {
|
||||
if (isAuthenticatedUser) {
|
||||
onAuthenticated();
|
||||
return;
|
||||
}
|
||||
|
||||
void (async () => {
|
||||
await NavigationStorage.savePendingChatUnlock({
|
||||
messageId,
|
||||
kind,
|
||||
returnUrl,
|
||||
stage,
|
||||
});
|
||||
router.push(ROUTE_BUILDERS.authWithRedirect(returnUrl));
|
||||
})();
|
||||
},
|
||||
[isAuthenticatedUser, router],
|
||||
);
|
||||
|
||||
const openSubscriptionForPendingUnlock = useCallback(
|
||||
({
|
||||
messageId,
|
||||
kind,
|
||||
returnUrl,
|
||||
type,
|
||||
payChannel = getDefaultPayChannel(),
|
||||
}: OpenSubscriptionForPendingUnlockInput): void => {
|
||||
void (async () => {
|
||||
await NavigationStorage.savePendingChatUnlock({
|
||||
messageId,
|
||||
kind,
|
||||
returnUrl,
|
||||
stage: "payment",
|
||||
});
|
||||
openSubscription({
|
||||
type,
|
||||
payChannel,
|
||||
returnTo: "chat",
|
||||
});
|
||||
})();
|
||||
},
|
||||
[getDefaultPayChannel, openSubscription],
|
||||
);
|
||||
|
||||
const exitSubscription = useCallback((returnTo: SubscriptionReturnTo): void => {
|
||||
void (async () => {
|
||||
router.replace(await consumeSubscriptionExitUrl(returnTo));
|
||||
})();
|
||||
}, [router]);
|
||||
|
||||
const exitSubscriptionAfterSuccess = useCallback((returnTo: SubscriptionReturnTo): void => {
|
||||
void (async () => {
|
||||
const pendingExitUrl = await peekSubscriptionExplicitExitUrl();
|
||||
if (pendingExitUrl) {
|
||||
router.replace(pendingExitUrl);
|
||||
return;
|
||||
}
|
||||
router.replace(await consumeSubscriptionExitUrl(returnTo));
|
||||
})();
|
||||
}, [router]);
|
||||
|
||||
return useMemo(() => ({
|
||||
push,
|
||||
replace,
|
||||
back,
|
||||
openAuth,
|
||||
openChat,
|
||||
openChatImage,
|
||||
openSubscription,
|
||||
exitSubscription,
|
||||
exitSubscriptionAfterSuccess,
|
||||
startMessageUnlock,
|
||||
openSubscriptionForPendingUnlock,
|
||||
getDefaultPayChannel,
|
||||
isAuthenticatedUser,
|
||||
};
|
||||
}), [
|
||||
back,
|
||||
exitSubscription,
|
||||
exitSubscriptionAfterSuccess,
|
||||
getDefaultPayChannel,
|
||||
isAuthenticatedUser,
|
||||
openAuth,
|
||||
openChat,
|
||||
openChatImage,
|
||||
openSubscription,
|
||||
openSubscriptionForPendingUnlock,
|
||||
push,
|
||||
replace,
|
||||
startMessageUnlock,
|
||||
]);
|
||||
}
|
||||
|
||||
export type { Route };
|
||||
|
||||
Reference in New Issue
Block a user