import { useCallback, useEffect, useState } from "react"; import { Download, Copy, ExternalLink, Info, Loader2, RefreshCw, Terminal, CheckCircle2, AlertCircle, Sparkles, } from "lucide-react"; import { Button } from "@/components/ui/button"; import { useTranslation } from "react-i18next"; import { toast } from "sonner"; import { getVersion } from "@tauri-apps/api/app"; import { settingsApi } from "@/lib/api"; import { useUpdate } from "@/contexts/UpdateContext"; import { relaunchApp } from "@/lib/updater"; import { Badge } from "@/components/ui/badge"; import { motion } from "framer-motion"; interface AboutSectionProps { isPortable: boolean; } interface ToolVersion { name: string; version: string | null; latest_version: string | null; error: string | null; } const ONE_CLICK_INSTALL_COMMANDS = `npm i -g @anthropic-ai/claude-code@latest npm i -g @openai/codex@latest npm i -g @google/gemini-cli@latest`; export function AboutSection({ isPortable }: AboutSectionProps) { // ... (use hooks as before) ... const { t } = useTranslation(); const [version, setVersion] = useState(null); const [isLoadingVersion, setIsLoadingVersion] = useState(true); const [isDownloading, setIsDownloading] = useState(false); const [toolVersions, setToolVersions] = useState([]); const [isLoadingTools, setIsLoadingTools] = useState(true); const { hasUpdate, updateInfo, updateHandle, checkUpdate, resetDismiss, isChecking, } = useUpdate(); const loadToolVersions = useCallback(async () => { setIsLoadingTools(true); try { const tools = await settingsApi.getToolVersions(); setToolVersions(tools); } catch (error) { console.error("[AboutSection] Failed to load tool versions", error); } finally { setIsLoadingTools(false); } }, []); useEffect(() => { let active = true; const load = async () => { try { const [appVersion, tools] = await Promise.all([ getVersion(), settingsApi.getToolVersions(), ]); if (active) { setVersion(appVersion); setToolVersions(tools); } } catch (error) { console.error("[AboutSection] Failed to load info", error); if (active) { setVersion(null); } } finally { if (active) { setIsLoadingVersion(false); setIsLoadingTools(false); } } }; void load(); return () => { active = false; }; }, []); // ... (handlers like handleOpenReleaseNotes, handleCheckUpdate) ... const handleOpenReleaseNotes = useCallback(async () => { try { const targetVersion = updateInfo?.availableVersion ?? version ?? ""; const displayVersion = targetVersion.startsWith("v") ? targetVersion : targetVersion ? `v${targetVersion}` : ""; if (!displayVersion) { await settingsApi.openExternal( "https://github.com/farion1231/cc-switch/releases", ); return; } await settingsApi.openExternal( `https://github.com/farion1231/cc-switch/releases/tag/${displayVersion}`, ); } catch (error) { console.error("[AboutSection] Failed to open release notes", error); toast.error(t("settings.openReleaseNotesFailed")); } }, [t, updateInfo?.availableVersion, version]); const handleCheckUpdate = useCallback(async () => { if (hasUpdate && updateHandle) { if (isPortable) { try { await settingsApi.checkUpdates(); } catch (error) { console.error("[AboutSection] Portable update failed", error); } return; } setIsDownloading(true); try { resetDismiss(); await updateHandle.downloadAndInstall(); await relaunchApp(); } catch (error) { console.error("[AboutSection] Update failed", error); toast.error(t("settings.updateFailed")); try { await settingsApi.checkUpdates(); } catch (fallbackError) { console.error( "[AboutSection] Failed to open fallback updater", fallbackError, ); } } finally { setIsDownloading(false); } return; } try { const available = await checkUpdate(); if (!available) { toast.success(t("settings.upToDate"), { closeButton: true }); } } catch (error) { console.error("[AboutSection] Check update failed", error); toast.error(t("settings.checkUpdateFailed")); } }, [checkUpdate, hasUpdate, isPortable, resetDismiss, t, updateHandle]); const handleCopyInstallCommands = useCallback(async () => { try { await navigator.clipboard.writeText(ONE_CLICK_INSTALL_COMMANDS); toast.success(t("settings.installCommandsCopied"), { closeButton: true }); } catch (error) { console.error("[AboutSection] Failed to copy install commands", error); toast.error(t("settings.installCommandsCopyFailed")); } }, [t]); const displayVersion = version ?? t("common.unknown"); return (

{t("common.about")}

{t("settings.aboutHint")}

CC Switch

{t("common.version")} {isLoadingVersion ? ( ) : ( {`v${displayVersion}`} )} {isPortable && ( {t("settings.portableMode")} )}
{hasUpdate && updateInfo && (

{t("settings.updateAvailable", { version: updateInfo.availableVersion, })}

{updateInfo.notes && (

{updateInfo.notes}

)}
)}

{t("settings.localEnvCheck")}

{["claude", "codex", "gemini"].map((toolName, index) => { const tool = toolVersions.find((item) => item.name === toolName); const displayName = tool?.name ?? toolName; const title = tool?.version || tool?.error || t("common.unknown"); return (
{displayName}
{isLoadingTools ? ( ) : tool?.version ? (
{tool.latest_version && tool.version !== tool.latest_version && ( {tool.latest_version} )}
) : ( )}
{isLoadingTools ? t("common.loading") : tool?.version ? tool.version : tool?.error || t("common.notInstalled")}
); })}

{t("settings.oneClickInstall")}

{t("settings.oneClickInstallHint")}

            {ONE_CLICK_INSTALL_COMMANDS}
          
); }