"use client"; /** * ChatQuotaExhaustedBanner 游客配额耗尽横幅 * * 何时显示: * - 后端返回 lockDetail.reason="daily_limit" 且 showUpgrade=true * * 视觉规格(与设计稿对齐): * - 粉→品红渐变背景(与 splash 渐变一致) * - 大字号粉色/白色提示文案("The limit for free chat times has been reached today") * - 粉→品红渐变 pill 按钮"Unlock your membership to continue" → 跳 /subscription * * 业务关系: * - 与 `src/app/sidebar/components/vip-benefits-card.tsx` 的 "Activate VIP Membership" 行为一致 * - 与 `src/app/sidebar/components/voice-package-card.tsx` 的 "Buy Package" 行为一致 * * 不做的事: * - 不直接管理 state machine(chat 机器不感知 UI 层) * - 不显示具体剩余分钟数(已用 total<=0 表达"耗尽"足够) */ import { useRouter } from "next/navigation"; import { ROUTES } from "@/router/routes"; import styles from "./chat-quota-exhausted-banner.module.css"; export interface ChatQuotaExhaustedBannerProps { title?: string; ctaLabel?: string; /** * 自定义点击回调(不传则默认 router.push(ROUTES.subscription)) * - 测试时可传 mock * - 嵌入其他场景时(如 nested overlay)可传自定义 */ onUnlock?: () => void; } export function ChatQuotaExhaustedBanner({ title = "The limit for free chat times\nhas been reached today", ctaLabel = "Unlock your membership to continue", onUnlock, }: ChatQuotaExhaustedBannerProps) { const router = useRouter(); const titleLines = title.split("\n"); const handleClick = () => { if (onUnlock) { onUnlock(); return; } router.push(`${ROUTES.subscription}?type=vip`); }; return (

{titleLines.map((line, index) => ( {line} {index < titleLines.length - 1 ?
: null}
))}

); }