refactor(chat): centralize unlock coordination

This commit is contained in:
2026-07-15 19:11:59 +08:00
parent 590dee417b
commit 47876484fc
5 changed files with 546 additions and 387 deletions
+11 -81
View File
@@ -33,7 +33,7 @@ import {
shouldStartExternalBrowserPrompt,
} from "./chat-screen.helpers";
import { useFirstRechargeOfferBanner } from "./hooks/use-first-recharge-offer-banner";
import { useChatUnlockNavigationFlow } from "./hooks/use-chat-unlock-navigation-flow";
import { useChatUnlockCoordinator } from "./hooks/use-chat-unlock-coordinator";
import { useChatGuestLogin } from "./hooks/use-chat-guest-login";
import { useChatMessageLimitBanner } from "./hooks/use-chat-message-limit-banner";
import { useChatPromotionBootstrap } from "./hooks/use-chat-promotion-bootstrap";
@@ -64,40 +64,13 @@ export function ChatScreen() {
const imageReturnUrl = imageMessageId
? buildChatImageOverlayUrl(imageMessageId)
: ROUTES.chat;
const {
unlockPaywallRequest,
requestMessageUnlock,
closeInsufficientCreditsDialog,
confirmInsufficientCreditsDialog,
} = useChatUnlockNavigationFlow({
returnUrl: ROUTES.chat,
ignoredKind: "image",
promotionScope: "exclude",
const unlockCoordinator = useChatUnlockCoordinator({
defaultReturnUrl: ROUTES.chat,
imageMessageId,
imageReturnUrl,
promotion: state.promotion,
enabled: isPromotionBootstrapReady,
});
const {
unlockPaywallRequest: imageUnlockPaywallRequest,
requestMessageUnlock: requestImageUnlock,
closeInsufficientCreditsDialog: closeImageInsufficientCreditsDialog,
confirmInsufficientCreditsDialog: confirmImageInsufficientCreditsDialog,
} = useChatUnlockNavigationFlow({
returnUrl: imageReturnUrl,
expectedKind: "image",
expectedMessageId: imageMessageId ?? undefined,
promotionScope: "exclude",
enabled: isPromotionBootstrapReady && imageMessageId !== null,
});
const {
unlockPaywallRequest: promotionUnlockPaywallRequest,
requestMessageUnlock: requestPromotionUnlock,
closeInsufficientCreditsDialog: closePromotionInsufficientCreditsDialog,
confirmInsufficientCreditsDialog:
confirmPromotionInsufficientCreditsDialog,
} = useChatUnlockNavigationFlow({
returnUrl: ROUTES.chat,
promotionScope: "only",
enabled: isPromotionBootstrapReady && state.promotion !== null,
});
const selectedImageMessage = useMemo(
() =>
imageMessageId
@@ -152,36 +125,15 @@ export function ChatScreen() {
]);
function handleUnlockPrivateMessage(messageId: string): void {
if (requestPromotionMessageUnlock(messageId, "private")) return;
requestMessageUnlock(messageId, "private");
unlockCoordinator.requestMessageUnlock(messageId, "private");
}
function handleUnlockVoiceMessage(messageId: string): void {
if (requestPromotionMessageUnlock(messageId, "voice")) return;
requestMessageUnlock(messageId, "voice");
unlockCoordinator.requestMessageUnlock(messageId, "voice");
}
function handleUnlockImageMessage(messageId: string): void {
if (requestPromotionMessageUnlock(messageId, "image")) return;
requestMessageUnlock(messageId, "image");
}
function requestPromotionMessageUnlock(
messageId: string,
kind: "private" | "voice" | "image",
): boolean {
const promotion = state.promotion;
if (!promotion || promotion.message.id !== messageId) return false;
const temporaryMessageId = `promotion:${promotion.session.clientLockId}`;
requestPromotionUnlock(messageId, kind, {
remoteMessageId:
messageId === temporaryMessageId ? undefined : messageId,
lockType: promotion.session.lockType,
clientLockId: promotion.session.clientLockId,
promotion: promotion.session,
});
return true;
unlockCoordinator.requestMessageUnlock(messageId, "image");
}
function handleOpenImage(messageId: string): void {
@@ -196,7 +148,7 @@ export function ChatScreen() {
function handleUnlockImagePaywall(): void {
if (!imageMessageId) return;
requestImageUnlock(imageMessageId, "image");
unlockCoordinator.requestMessageUnlock(imageMessageId, "image");
}
return (
@@ -264,29 +216,7 @@ export function ChatScreen() {
{/* PWA 安装提示触发器(聊天消息数量达到阈值后才允许弹出) */}
<PwaInstallOverlay enabled={shouldShowPwaInstall} />
<ChatUnlockDialogs
unlockPaywallRequest={unlockPaywallRequest}
onCloseInsufficientCreditsDialog={closeInsufficientCreditsDialog}
onConfirmInsufficientCreditsDialog={confirmInsufficientCreditsDialog}
/>
<ChatUnlockDialogs
unlockPaywallRequest={promotionUnlockPaywallRequest}
includeHistoryUnlock={false}
onCloseInsufficientCreditsDialog={
closePromotionInsufficientCreditsDialog
}
onConfirmInsufficientCreditsDialog={
confirmPromotionInsufficientCreditsDialog
}
/>
<ChatUnlockDialogs
unlockPaywallRequest={imageUnlockPaywallRequest}
includeHistoryUnlock={false}
onCloseInsufficientCreditsDialog={closeImageInsufficientCreditsDialog}
onConfirmInsufficientCreditsDialog={
confirmImageInsufficientCreditsDialog
}
/>
<ChatUnlockDialogs model={unlockCoordinator.dialogs} />
{selectedImageMessage?.imageUrl ? (
<FullscreenImageViewer