"use client"; import { invoke } from "@tauri-apps/api/core"; import { useCallback, useEffect, useState } from "react"; import { LuCopy } from "react-icons/lu"; import { toast } from "sonner"; import { LoadingButton } from "@/components/loading-button"; import { Badge } from "@/components/ui/badge"; import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Tooltip, TooltipContent, TooltipTrigger, } from "@/components/ui/tooltip"; import { useBrowserState } from "@/hooks/use-browser-state"; import { getBrowserDisplayName, getBrowserIcon } from "@/lib/browser-utils"; import type { BrowserProfile, StoredProxy } from "@/types"; import { RippleButton } from "./ui/ripple"; interface ProfileSelectorDialogProps { isOpen: boolean; onClose: () => void; isUpdating: (browser: string) => boolean; url?: string; runningProfiles?: Set; } export function ProfileSelectorDialog({ isOpen, onClose, url, runningProfiles = new Set(), isUpdating, }: ProfileSelectorDialogProps) { const [profiles, setProfiles] = useState([]); const [selectedProfile, setSelectedProfile] = useState(null); const [isLoading, setIsLoading] = useState(false); const [isLaunching, setIsLaunching] = useState(false); const [storedProxies, setStoredProxies] = useState([]); const [launchingProfiles, setLaunchingProfiles] = useState>( new Set(), ); const [stoppingProfiles, _setStoppingProfiles] = useState>( new Set(), ); // Use shared browser state hook const browserState = useBrowserState( profiles, runningProfiles, isUpdating, launchingProfiles, stoppingProfiles, ); // Helper function to check if a profile has a proxy const hasProxy = useCallback( (profile: BrowserProfile): boolean => { if (!profile.proxy_id) return false; const proxy = storedProxies.find((p) => p.id === profile.proxy_id); return proxy !== undefined; }, [storedProxies], ); const loadProfiles = useCallback(async () => { setIsLoading(true); try { // Load both profiles and stored proxies const [profileList, proxiesList] = await Promise.all([ invoke("list_browser_profiles"), invoke("get_stored_proxies"), ]); // Sort profiles by name profileList.sort((a, b) => a.name.localeCompare(b.name)); // Set both profiles and proxies setProfiles(profileList); setStoredProxies(proxiesList); // Auto-select first available profile for link opening if (profileList.length > 0) { // First, try to find a running profile that can be used for opening links const runningAvailableProfile = profileList.find((profile) => { const isRunning = runningProfiles.has(profile.name); // Simple check without browserState dependency return ( isRunning && profile.browser !== "tor-browser" && profile.browser !== "mullvad-browser" ); }); if (runningAvailableProfile) { setSelectedProfile(runningAvailableProfile.name); } else { setSelectedProfile(profileList[0].name); } } } catch (err) { console.error("Failed to load profiles:", err); } finally { setIsLoading(false); } }, [runningProfiles]); // Helper function to get tooltip content for profiles - now uses shared hook const getProfileTooltipContent = (profile: BrowserProfile): string | null => { return browserState.getProfileTooltipContent(profile); }; const handleOpenUrl = useCallback(async () => { if (!selectedProfile || !url) return; setIsLaunching(true); setLaunchingProfiles((prev) => new Set(prev).add(selectedProfile)); try { await invoke("open_url_with_profile", { profileName: selectedProfile, url, }); onClose(); } catch (error) { console.error("Failed to open URL with profile:", error); } finally { setIsLaunching(false); setLaunchingProfiles((prev) => { const next = new Set(prev); next.delete(selectedProfile); return next; }); } }, [selectedProfile, url, onClose]); const handleCancel = useCallback(() => { setSelectedProfile(null); onClose(); }, [onClose]); const handleCopyUrl = useCallback(async () => { if (!url) return; try { await navigator.clipboard.writeText(url); toast.success("URL copied to clipboard!"); } catch (error) { console.error("Failed to copy URL:", error); toast.error("Failed to copy URL to clipboard"); } }, [url]); const selectedProfileData = profiles.find((p) => p.name === selectedProfile); // Check if the selected profile can be used for opening links const canOpenWithSelectedProfile = () => { if (!selectedProfileData) return false; return browserState.canUseProfileForLinks(selectedProfileData); }; // Get tooltip content for disabled profiles const getTooltipContent = () => { if (!selectedProfileData) return null; return getProfileTooltipContent(selectedProfileData); }; useEffect(() => { if (isOpen) { void loadProfiles(); } }, [isOpen, loadProfiles]); return ( Choose Profile
{url && (
void handleCopyUrl()} className="flex gap-2 items-center" > Copy
{url}
)}
{isLoading ? (
Loading profiles...
) : profiles.length === 0 ? (
No profiles available. Please create a profile first.
Close this dialog and create a profile from the main window to get started.
) : ( )}
Cancel void handleOpenUrl()} disabled={ !selectedProfile || profiles.length === 0 || !canOpenWithSelectedProfile() } > Open {getTooltipContent() && ( {getTooltipContent()} )}
); }