import React, {useRef, useMemo, useCallback, useState, useEffect} from "react"; import { useLockFn } from "ahooks"; import { useTranslation } from "react-i18next"; import { toast } from "sonner"; import { useProfiles } from "@/hooks/use-profiles"; import { ProfileViewer, ProfileViewerRef, } from "@/components/profile/profile-viewer"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { Button } from "@/components/ui/button"; import { ChevronsUpDown, Check, PlusCircle, Wrench, AlertTriangle, Loader2, Globe, Send, ExternalLink, RefreshCw, } from "lucide-react"; import { useVerge } from "@/hooks/use-verge"; import { useSystemState } from "@/hooks/use-system-state"; import { useServiceInstaller } from "@/hooks/useServiceInstaller"; import { Switch } from "@/components/ui/switch"; import { ProxySelectors } from "@/components/home/proxy-selectors"; import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; import { closeAllConnections } from "@/services/api"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"; import { updateProfile } from "@/services/cmds"; import { SidebarTrigger } from "@/components/ui/sidebar"; const MinimalHomePage: React.FC = () => { const { t } = useTranslation(); const [isToggling, setIsToggling] = useState(false); const [isUpdating, setIsUpdating] = useState(false); const { profiles, patchProfiles, activateSelected, mutateProfiles } = useProfiles(); const viewerRef = useRef(null); const [uidToActivate, setUidToActivate] = useState(null); const profileItems = useMemo(() => { const items = profiles && Array.isArray(profiles.items) ? profiles.items : []; const allowedTypes = ["local", "remote"]; return items.filter((i: any) => i && allowedTypes.includes(i.type!)); }, [profiles]); const currentProfile = useMemo(() => { return profileItems.find(p => p.uid === profiles?.current); }, [profileItems, profiles?.current]); console.log("Current profile", currentProfile); const currentProfileName = currentProfile?.name || profiles?.current; const activateProfile = useCallback( async (uid: string, notifySuccess: boolean) => { try { await patchProfiles({ current: uid }); await closeAllConnections(); await activateSelected(); if (notifySuccess) { toast.success(t("Profile Switched")); } } catch (err: any) { toast.error(err.message || err.toString()); mutateProfiles(); } }, [patchProfiles, activateSelected, mutateProfiles, t], ); useEffect(() => { const uidToActivate = sessionStorage.getItem('activateProfile'); if (uidToActivate && profileItems.some(p => p.uid === uidToActivate)) { activateProfile(uidToActivate, false); sessionStorage.removeItem('activateProfile'); } }, [profileItems, activateProfile]); const handleProfileChange = useLockFn(async (uid: string) => { if (profiles?.current === uid) return; await activateProfile(uid, true); }); const { verge, patchVerge, mutateVerge } = useVerge(); const { isAdminMode, isServiceMode } = useSystemState(); const { installServiceAndRestartCore } = useServiceInstaller(); const isTunAvailable = isServiceMode || isAdminMode; const isProxyEnabled = verge?.enable_system_proxy || verge?.enable_tun_mode; const showTunAlert = (verge?.primary_action ?? "tun-mode") === "tun-mode" && !isTunAvailable; const handleToggleProxy = useLockFn(async () => { const turningOn = !isProxyEnabled; const primaryAction = verge?.primary_action || "tun-mode"; setIsToggling(true); try { if (turningOn) { if (primaryAction === "tun-mode") { if (!isTunAvailable) { toast.error(t("TUN requires Service Mode or Admin Mode")); setIsToggling(false); return; } await patchVerge({ enable_tun_mode: true, enable_system_proxy: false, }); } else { await patchVerge({ enable_system_proxy: true, enable_tun_mode: false, }); } toast.success(t("Proxy enabled")); } else { await patchVerge({ enable_tun_mode: false, enable_system_proxy: false, }); toast.success(t("Proxy disabled")); } mutateVerge(); } catch (error: any) { toast.error(t("Failed to toggle proxy"), { description: error.message }); } finally { setIsToggling(false); } }); const handleUpdateProfile = useLockFn(async () => { if (!currentProfile?.uid || currentProfile.type !== 'remote') return; setIsUpdating(true); try { await updateProfile(currentProfile.uid); toast.success(t("Profile Updated Successfully")); mutateProfiles(); // Обновляем данные в UI } catch (err: any) { toast.error(t("Failed to update profile"), { description: err.message }); } finally { setIsUpdating(false); } }); return (
{profileItems.length > 0 && (
{t("Profiles")} {profileItems.map((p) => ( handleProfileChange(p.uid)} > {p.name} {profiles?.current === p.uid && ( )} ))} viewerRef.current?.create()}> {t("Add Profile")}
)} {currentProfile?.type === 'remote' && (

{t("Update Profile")}

)}
{currentProfile?.announce && (
{currentProfile.announce_url ? ( {currentProfile.announce.replace(/\\n/g, '\n')} ) : (

{currentProfile.announce}

)}
)}

{isProxyEnabled ? t("Connected") : t("Disconnected")}

{isToggling && (isProxyEnabled ? t("Disconnecting...") : t("Connecting..."))}

{showTunAlert && (
{t("Attention Required")} {t("TUN requires Service Mode or Admin Mode")} {!isServiceMode && !isAdminMode && ( )}
)}
{profileItems.length > 0 ? ( ) : ( {t("Get Started")} {t( "You don't have any profiles yet. Add your first one to begin.", )} )}
mutateProfiles()} />
); }; export default MinimalHomePage;