You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
	
	
		
			190 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			TypeScript
		
	
		
		
			
		
	
	
			190 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			TypeScript
		
	
| 
											9 months ago
										 | import styles from "./auth.module.scss"; | ||
|  | import { IconButton } from "./button"; | ||
|  | import { useState, useEffect } from "react"; | ||
|  | import { useNavigate } from "react-router-dom"; | ||
|  | import { Path, SAAS_CHAT_URL } from "../constant"; | ||
|  | import { useAccessStore } from "../store"; | ||
|  | import Locale from "../locales"; | ||
|  | import Delete from "../icons/close.svg"; | ||
|  | import Arrow from "../icons/arrow.svg"; | ||
|  | import Logo from "../icons/logo.svg"; | ||
|  | import { useMobileScreen } from "@/app/utils"; | ||
|  | import BotIcon from "../icons/bot.svg"; | ||
|  | import { getClientConfig } from "../config/client"; | ||
|  | import { PasswordInput } from "./ui-lib"; | ||
|  | import LeftIcon from "@/app/icons/left.svg"; | ||
|  | import { safeLocalStorage } from "@/app/utils"; | ||
|  | import { | ||
|  |   trackSettingsPageGuideToCPaymentClick, | ||
|  |   trackAuthorizationPageButtonToCPaymentClick, | ||
|  | } from "../utils/auth-settings-events"; | ||
|  | import clsx from "clsx"; | ||
|  | 
 | ||
|  | const storage = safeLocalStorage(); | ||
|  | 
 | ||
|  | export function AuthPage() { | ||
|  |   const navigate = useNavigate(); | ||
|  |   const accessStore = useAccessStore(); | ||
|  |   const goHome = () => navigate(Path.Home); | ||
|  |   const goChat = () => navigate(Path.Chat); | ||
|  |   const goSaas = () => { | ||
|  |     trackAuthorizationPageButtonToCPaymentClick(); | ||
|  |     window.location.href = SAAS_CHAT_URL; | ||
|  |   }; | ||
|  | 
 | ||
|  |   const resetAccessCode = () => { | ||
|  |     accessStore.update((access) => { | ||
|  |       access.openaiApiKey = ""; | ||
|  |       access.accessCode = ""; | ||
|  |     }); | ||
|  |   }; // Reset access code to empty string
 | ||
|  | 
 | ||
|  |   useEffect(() => { | ||
|  |     if (getClientConfig()?.isApp) { | ||
|  |       navigate(Path.Settings); | ||
|  |     } | ||
|  |     // eslint-disable-next-line react-hooks/exhaustive-deps
 | ||
|  |   }, []); | ||
|  | 
 | ||
|  |   return ( | ||
|  |     <div className={styles["auth-page"]}> | ||
|  |       <TopBanner></TopBanner> | ||
|  |       <div className={styles["auth-header"]}> | ||
|  |         <IconButton | ||
|  |           icon={<LeftIcon />} | ||
|  |           text={Locale.Auth.Return} | ||
|  |           onClick={() => navigate(Path.Home)} | ||
|  |         ></IconButton> | ||
|  |       </div> | ||
|  |       <div className={clsx("no-dark", styles["auth-logo"])}> | ||
|  |         <BotIcon /> | ||
|  |       </div> | ||
|  | 
 | ||
|  |       <div className={styles["auth-title"]}>{Locale.Auth.Title}</div> | ||
|  |       <div className={styles["auth-tips"]}>{Locale.Auth.Tips}</div> | ||
|  | 
 | ||
|  |       <PasswordInput | ||
|  |         style={{ marginTop: "3vh", marginBottom: "3vh" }} | ||
|  |         aria={Locale.Settings.ShowPassword} | ||
|  |         aria-label={Locale.Auth.Input} | ||
|  |         value={accessStore.accessCode} | ||
|  |         type="text" | ||
|  |         placeholder={Locale.Auth.Input} | ||
|  |         onChange={(e) => { | ||
|  |           accessStore.update( | ||
|  |             (access) => (access.accessCode = e.currentTarget.value), | ||
|  |           ); | ||
|  |         }} | ||
|  |       /> | ||
|  | 
 | ||
|  |       {!accessStore.hideUserApiKey ? ( | ||
|  |         <> | ||
|  |           <div className={styles["auth-tips"]}>{Locale.Auth.SubTips}</div> | ||
|  |           <PasswordInput | ||
|  |             style={{ marginTop: "3vh", marginBottom: "3vh" }} | ||
|  |             aria={Locale.Settings.ShowPassword} | ||
|  |             aria-label={Locale.Settings.Access.OpenAI.ApiKey.Placeholder} | ||
|  |             value={accessStore.openaiApiKey} | ||
|  |             type="text" | ||
|  |             placeholder={Locale.Settings.Access.OpenAI.ApiKey.Placeholder} | ||
|  |             onChange={(e) => { | ||
|  |               accessStore.update( | ||
|  |                 (access) => (access.openaiApiKey = e.currentTarget.value), | ||
|  |               ); | ||
|  |             }} | ||
|  |           /> | ||
|  |           <PasswordInput | ||
|  |             style={{ marginTop: "3vh", marginBottom: "3vh" }} | ||
|  |             aria={Locale.Settings.ShowPassword} | ||
|  |             aria-label={Locale.Settings.Access.Google.ApiKey.Placeholder} | ||
|  |             value={accessStore.googleApiKey} | ||
|  |             type="text" | ||
|  |             placeholder={Locale.Settings.Access.Google.ApiKey.Placeholder} | ||
|  |             onChange={(e) => { | ||
|  |               accessStore.update( | ||
|  |                 (access) => (access.googleApiKey = e.currentTarget.value), | ||
|  |               ); | ||
|  |             }} | ||
|  |           /> | ||
|  |         </> | ||
|  |       ) : null} | ||
|  | 
 | ||
|  |       <div className={styles["auth-actions"]}> | ||
|  |         <IconButton | ||
|  |           text={Locale.Auth.Confirm} | ||
|  |           type="primary" | ||
|  |           onClick={goChat} | ||
|  |         /> | ||
|  |         <IconButton | ||
|  |           text={Locale.Auth.SaasTips} | ||
|  |           onClick={() => { | ||
|  |             goSaas(); | ||
|  |           }} | ||
|  |         /> | ||
|  |       </div> | ||
|  |     </div> | ||
|  |   ); | ||
|  | } | ||
|  | 
 | ||
|  | function TopBanner() { | ||
|  |   const [isHovered, setIsHovered] = useState(false); | ||
|  |   const [isVisible, setIsVisible] = useState(true); | ||
|  |   const isMobile = useMobileScreen(); | ||
|  |   useEffect(() => { | ||
|  |     // 检查 localStorage 中是否有标记
 | ||
|  |     const bannerDismissed = storage.getItem("bannerDismissed"); | ||
|  |     // 如果标记不存在,存储默认值并显示横幅
 | ||
|  |     if (!bannerDismissed) { | ||
|  |       storage.setItem("bannerDismissed", "false"); | ||
|  |       setIsVisible(true); // 显示横幅
 | ||
|  |     } else if (bannerDismissed === "true") { | ||
|  |       // 如果标记为 "true",则隐藏横幅
 | ||
|  |       setIsVisible(false); | ||
|  |     } | ||
|  |   }, []); | ||
|  | 
 | ||
|  |   const handleMouseEnter = () => { | ||
|  |     setIsHovered(true); | ||
|  |   }; | ||
|  | 
 | ||
|  |   const handleMouseLeave = () => { | ||
|  |     setIsHovered(false); | ||
|  |   }; | ||
|  | 
 | ||
|  |   const handleClose = () => { | ||
|  |     setIsVisible(false); | ||
|  |     storage.setItem("bannerDismissed", "true"); | ||
|  |   }; | ||
|  | 
 | ||
|  |   if (!isVisible) { | ||
|  |     return null; | ||
|  |   } | ||
|  |   return ( | ||
|  |     <div | ||
|  |       className={styles["top-banner"]} | ||
|  |       onMouseEnter={handleMouseEnter} | ||
|  |       onMouseLeave={handleMouseLeave} | ||
|  |     > | ||
|  |       <div className={clsx(styles["top-banner-inner"], "no-dark")}> | ||
|  |         <Logo className={styles["top-banner-logo"]}></Logo> | ||
|  |         <span> | ||
|  |           {Locale.Auth.TopTips} | ||
|  |           <a | ||
|  |             href={SAAS_CHAT_URL} | ||
|  |             rel="stylesheet" | ||
|  |             onClick={() => { | ||
|  |               trackSettingsPageGuideToCPaymentClick(); | ||
|  |             }} | ||
|  |           > | ||
|  |             {Locale.Settings.Access.SaasStart.ChatNow} | ||
|  |             <Arrow style={{ marginLeft: "4px" }} /> | ||
|  |           </a> | ||
|  |         </span> | ||
|  |       </div> | ||
|  |       {(isHovered || isMobile) && ( | ||
|  |         <Delete className={styles["top-banner-close"]} onClick={handleClose} /> | ||
|  |       )} | ||
|  |     </div> | ||
|  |   ); | ||
|  | } |