feat(chat): prompt before credit top up

This commit is contained in:
2026-07-01 13:01:35 +08:00
parent abc0faf197
commit d1ccf3631e
5 changed files with 237 additions and 35 deletions
+20 -11
View File
@@ -30,6 +30,7 @@ import {
ChatQuotaExhaustedBanner,
ExternalBrowserDialog,
HistoryUnlockDialog,
InsufficientCreditsDialog,
PwaInstallOverlay,
} from "./components";
import {
@@ -49,6 +50,7 @@ export function ChatScreen() {
const router = useRouter();
const [showExternalBrowserDialog, setShowExternalBrowserDialog] =
useState(false);
const unlockPaywallRequest = state.unlockPaywallRequest;
// isGuest 派生(chat-screen 是唯一知道这个值的地方 —— chat 机器无 isGuest 字段)
const isGuest = deriveIsGuest(authState.loginStatus);
@@ -132,13 +134,16 @@ export function ChatScreen() {
state.historyLoaded,
]);
useEffect(() => {
const request = state.unlockPaywallRequest;
if (!request) return;
function handleCloseInsufficientCreditsDialog(): void {
chatDispatch({ type: "ChatUnlockPaywallNavigationConsumed" });
}
function handleConfirmInsufficientCreditsDialog(): void {
if (!unlockPaywallRequest) return;
savePendingChatUnlock({
messageId: request.messageId,
kind: request.kind,
messageId: unlockPaywallRequest.messageId,
kind: unlockPaywallRequest.kind,
returnUrl: ROUTES.chat,
stage: "payment",
});
@@ -149,12 +154,7 @@ export function ChatScreen() {
{ returnTo: "chat" },
),
);
}, [
chatDispatch,
router,
state.unlockPaywallRequest,
userState.isVip,
]);
}
async function handleOpenExternalBrowser(): Promise<void> {
setShowExternalBrowserDialog(false);
@@ -263,6 +263,15 @@ export function ChatScreen() {
onClose={() => chatDispatch({ type: "ChatUnlockHistoryDismissed" })}
onConfirm={() => chatDispatch({ type: "ChatUnlockHistoryConfirmed" })}
/>
<InsufficientCreditsDialog
open={unlockPaywallRequest !== null}
creditBalance={unlockPaywallRequest?.creditBalance ?? 0}
requiredCredits={unlockPaywallRequest?.requiredCredits ?? 0}
shortfallCredits={unlockPaywallRequest?.shortfallCredits ?? 0}
onClose={handleCloseInsufficientCreditsDialog}
onConfirm={handleConfirmInsufficientCreditsDialog}
/>
</div>
</MobileShell>
);