refactor(chat): launch external browser without dialog

This commit is contained in:
2026-07-09 14:25:20 +08:00
parent 0106fba877
commit 0659e52d29
5 changed files with 19 additions and 164 deletions
+1 -8
View File
@@ -17,7 +17,6 @@ import {
ChatInputBar, ChatInputBar,
ChatInsufficientCreditsBanner, ChatInsufficientCreditsBanner,
ChatUnlockDialogs, ChatUnlockDialogs,
ExternalBrowserDialog,
FirstRechargeOfferBanner, FirstRechargeOfferBanner,
FullscreenImageViewer, FullscreenImageViewer,
PwaInstallOverlay, PwaInstallOverlay,
@@ -92,7 +91,7 @@ export function ChatScreen() {
loginStatus: authState.loginStatus, loginStatus: authState.loginStatus,
}); });
const shouldShowPwaInstall = state.historyLoaded && state.messages.length >= 10; const shouldShowPwaInstall = state.historyLoaded && state.messages.length >= 10;
const externalBrowserPrompt = useExternalBrowserPrompt({ useExternalBrowserPrompt({
hasInitialized: authState.hasInitialized, hasInitialized: authState.hasInitialized,
isLoading: authState.isLoading, isLoading: authState.isLoading,
loginStatus: authState.loginStatus, loginStatus: authState.loginStatus,
@@ -198,12 +197,6 @@ export function ChatScreen() {
{/* PWA 安装提示触发器(聊天消息数量达到阈值后才允许弹出) */} {/* PWA 安装提示触发器(聊天消息数量达到阈值后才允许弹出) */}
<PwaInstallOverlay enabled={shouldShowPwaInstall} /> <PwaInstallOverlay enabled={shouldShowPwaInstall} />
<ExternalBrowserDialog
open={externalBrowserPrompt.open}
onClose={externalBrowserPrompt.close}
onConfirm={() => void externalBrowserPrompt.confirm()}
/>
<ChatUnlockDialogs <ChatUnlockDialogs
unlockPaywallRequest={unlockPaywallRequest} unlockPaywallRequest={unlockPaywallRequest}
onCloseInsufficientCreditsDialog={closeInsufficientCreditsDialog} onCloseInsufficientCreditsDialog={closeInsufficientCreditsDialog}
@@ -1,79 +0,0 @@
.overlay {
position: fixed;
inset: 0;
z-index: 70;
display: flex;
align-items: center;
justify-content: center;
background: rgba(0, 0, 0, 0.5);
padding:
calc(var(--dialog-safe-margin, 16px) + var(--app-safe-top, 0px))
calc(var(--dialog-safe-margin, 16px) + var(--app-safe-right, 0px))
calc(var(--dialog-safe-margin, 16px) + var(--app-safe-bottom, 0px))
calc(var(--dialog-safe-margin, 16px) + var(--app-safe-left, 0px));
}
.dialog {
width: 100%;
max-width: var(--pwa-install-dialog-max-width, 360px);
padding:
var(--responsive-card-padding-lg, 24px)
var(--responsive-card-padding, 16px)
var(--responsive-card-padding, 16px);
text-align: center;
background: var(--color-page-background, #ffffff);
border-radius: var(--responsive-card-radius, 40px);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
}
.title {
margin: 0 0 10px;
font-size: var(--responsive-page-title, var(--font-size-22, 22px));
font-weight: 700;
line-height: 1.2;
color: var(--color-text-foreground, #171717);
}
.content {
margin:
0
var(--responsive-card-padding-lg, 24px)
var(--page-section-gap-lg, 24px);
font-size: var(--responsive-body, var(--font-size-lg, 16px));
line-height: 1.5;
text-align: left;
color: #393939;
white-space: pre-line;
}
.actions {
display: flex;
gap: var(--spacing-md, 12px);
width: 100%;
}
.button {
flex: 1 1 auto;
min-height: var(--pwa-button-height, 44px);
border: 0;
border-radius: var(--radius-bottom-sheet, 28px);
font-size: var(--responsive-body, var(--font-size-lg, 16px));
font-weight: 600;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
}
.secondary {
color: var(--color-page-background, #ffffff);
background: var(--color-text-secondary, #9e9e9e);
}
.primary {
color: var(--color-page-background, #ffffff);
background: linear-gradient(
var(--color-button-gradient-start, #ff67e0),
var(--color-button-gradient-end, #ff52a2)
);
}
@@ -1,51 +0,0 @@
"use client";
import styles from "./external-browser-dialog.module.css";
export interface ExternalBrowserDialogProps {
open: boolean;
onClose: () => void;
onConfirm: () => void;
}
export function ExternalBrowserDialog({
open,
onClose,
onConfirm,
}: ExternalBrowserDialogProps) {
if (!open) return null;
return (
<div
className={styles.overlay}
role="dialog"
aria-modal="true"
aria-labelledby="external-browser-title"
>
<div className={styles.dialog}>
<h2 id="external-browser-title" className={styles.title}>
Open in browser
</h2>
<p className={styles.content}>
Sync your Facebook profile to an external browser for the best chat experience.
</p>
<div className={styles.actions}>
<button
type="button"
className={`${styles.button} ${styles.secondary}`}
onClick={onClose}
>
Later
</button>
<button
type="button"
className={`${styles.button} ${styles.primary}`}
onClick={onConfirm}
>
Continue
</button>
</div>
</div>
</div>
);
}
-1
View File
@@ -12,7 +12,6 @@ export * from "./chat-input-text-field";
export * from "./chat-send-button"; export * from "./chat-send-button";
export * from "./chat-unlock-dialogs"; export * from "./chat-unlock-dialogs";
export * from "./date-header"; export * from "./date-header";
export * from "./external-browser-dialog";
export * from "./first-recharge-offer-banner"; export * from "./first-recharge-offer-banner";
export * from "./fullscreen-image-viewer"; export * from "./fullscreen-image-viewer";
export * from "./history-unlock-dialog"; export * from "./history-unlock-dialog";
@@ -1,6 +1,6 @@
"use client"; "use client";
import { useCallback, useEffect, useRef, useState } from "react"; import { useEffect, useRef } from "react";
import { import {
openChatInExternalBrowser, openChatInExternalBrowser,
@@ -15,18 +15,11 @@ import {
const EXTERNAL_BROWSER_PROMPT_DELAY_MS = 3000; const EXTERNAL_BROWSER_PROMPT_DELAY_MS = 3000;
export interface ExternalBrowserPromptController {
open: boolean;
close: () => void;
confirm: () => Promise<void>;
}
export function useExternalBrowserPrompt({ export function useExternalBrowserPrompt({
hasInitialized, hasInitialized,
isLoading, isLoading,
loginStatus, loginStatus,
}: ExternalBrowserPromptState): ExternalBrowserPromptController { }: ExternalBrowserPromptState): void {
const [open, setOpen] = useState(false);
const promptShownRef = useRef(false); const promptShownRef = useRef(false);
useEffect(() => { useEffect(() => {
@@ -52,8 +45,22 @@ export function useExternalBrowserPrompt({
promptShownRef.current = true; promptShownRef.current = true;
timer = window.setTimeout(() => { timer = window.setTimeout(() => {
if (!mounted) return; if (!mounted) return;
setOpen(true); void (async () => {
void recordExternalBrowserPromptShown(eligibility.today); try {
await recordExternalBrowserPromptShown(eligibility.today);
} catch (error) {
console.warn(
"[chat] Failed to record external browser auto launch",
error,
);
}
if (!mounted) return;
try {
await openChatInExternalBrowser();
} catch (error) {
console.warn("[chat] Failed to open external browser", error);
}
})();
}, EXTERNAL_BROWSER_PROMPT_DELAY_MS); }, EXTERNAL_BROWSER_PROMPT_DELAY_MS);
}; };
@@ -65,18 +72,4 @@ export function useExternalBrowserPrompt({
}; };
}, [hasInitialized, isLoading, loginStatus]); }, [hasInitialized, isLoading, loginStatus]);
const close = useCallback(() => {
setOpen(false);
}, []);
const confirm = useCallback(async () => {
setOpen(false);
await openChatInExternalBrowser();
}, []);
return {
open,
close,
confirm,
};
} }