feat(chat): handle credit-gated send responses
This commit is contained in:
@@ -84,8 +84,26 @@ export function getChatPaywallSubscriptionUrl(): string {
|
||||
});
|
||||
}
|
||||
|
||||
export function getChatPaywallNavigationUrl(loginStatus: LoginStatus): string {
|
||||
const subscriptionUrl = getChatPaywallSubscriptionUrl();
|
||||
export function getChatCreditsTopUpSubscriptionUrl(): string {
|
||||
return ROUTE_BUILDERS.subscription("topup", {
|
||||
returnTo: "chat",
|
||||
});
|
||||
}
|
||||
|
||||
export function getInsufficientCreditsSubscriptionType(
|
||||
isVip: boolean,
|
||||
): "vip" | "topup" {
|
||||
return isVip ? "topup" : "vip";
|
||||
}
|
||||
|
||||
export function getChatPaywallNavigationUrl(
|
||||
loginStatus: LoginStatus,
|
||||
type: "vip" | "topup" = "vip",
|
||||
): string {
|
||||
const subscriptionUrl =
|
||||
type === "topup"
|
||||
? getChatCreditsTopUpSubscriptionUrl()
|
||||
: getChatPaywallSubscriptionUrl();
|
||||
if (deriveIsGuest(loginStatus)) {
|
||||
return ROUTE_BUILDERS.authWithRedirect(subscriptionUrl);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import { useRouter } from "next/navigation";
|
||||
|
||||
import { useAuthState } from "@/stores/auth/auth-context";
|
||||
import { useChatDispatch, useChatState } from "@/stores/chat/chat-context";
|
||||
import { useUserState } from "@/stores/user/user-context";
|
||||
|
||||
import { MobileShell } from "@/app/_components/core";
|
||||
|
||||
@@ -22,6 +23,7 @@ import {
|
||||
import {
|
||||
deriveIsGuest,
|
||||
getChatPaywallNavigationUrl,
|
||||
getInsufficientCreditsSubscriptionType,
|
||||
isChatDevelopmentEnvironment,
|
||||
openChatInExternalBrowser,
|
||||
recordExternalBrowserPromptShown,
|
||||
@@ -34,6 +36,7 @@ export function ChatScreen() {
|
||||
const state = useChatState();
|
||||
const chatDispatch = useChatDispatch();
|
||||
const authState = useAuthState();
|
||||
const userState = useUserState();
|
||||
const router = useRouter();
|
||||
const [showExternalBrowserDialog, setShowExternalBrowserDialog] =
|
||||
useState(false);
|
||||
@@ -43,8 +46,17 @@ export function ChatScreen() {
|
||||
|
||||
// 消息数量限制由后端统一返回 lockDetail,前端不再处理本地额度。
|
||||
const showMessageLimitBanner =
|
||||
state.upgradePromptVisible && state.upgradeReason === "weekly_limit";
|
||||
const messageLimitTitle = "The limit for free chat times\nhas been reached";
|
||||
state.upgradePromptVisible &&
|
||||
(state.upgradeReason === "weekly_limit" ||
|
||||
state.upgradeReason === "insufficient_credits");
|
||||
const messageLimitTitle =
|
||||
state.upgradeReason === "insufficient_credits"
|
||||
? "Insufficient credits\nTop up to continue chatting"
|
||||
: "The limit for free chat times\nhas been reached";
|
||||
const messageLimitCtaLabel =
|
||||
state.upgradeReason === "insufficient_credits"
|
||||
? "Top up credits to continue"
|
||||
: "Unlock your membership to continue";
|
||||
|
||||
const externalBrowserPromptShownRef = useRef(false);
|
||||
|
||||
@@ -102,7 +114,17 @@ export function ChatScreen() {
|
||||
}
|
||||
|
||||
function handleMessageLimitUnlock(): void {
|
||||
openChatPaywallSubscription();
|
||||
const subscriptionType =
|
||||
state.upgradeReason === "insufficient_credits"
|
||||
? getInsufficientCreditsSubscriptionType(userState.isVip)
|
||||
: "vip";
|
||||
|
||||
router.push(
|
||||
getChatPaywallNavigationUrl(
|
||||
authState.loginStatus,
|
||||
subscriptionType,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
function handleUnlockVoiceMessage(): void {
|
||||
@@ -137,6 +159,7 @@ export function ChatScreen() {
|
||||
{showMessageLimitBanner ? (
|
||||
<ChatQuotaExhaustedBanner
|
||||
title={messageLimitTitle}
|
||||
ctaLabel={messageLimitCtaLabel}
|
||||
onUnlock={handleMessageLimitUnlock}
|
||||
/>
|
||||
) : (
|
||||
|
||||
Reference in New Issue
Block a user