"use client"; import { LoadingButton } from "@/components/loading-button"; import { ReleaseTypeSelector } from "@/components/release-type-selector"; import { Button } from "@/components/ui/button"; import { Checkbox } from "@/components/ui/checkbox"; import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; 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 { useBrowserDownload } from "@/hooks/use-browser-download"; import { useBrowserSupport } from "@/hooks/use-browser-support"; import { getBrowserDisplayName } from "@/lib/browser-utils"; import type { BrowserProfile, BrowserReleaseTypes, ProxySettings, } from "@/types"; import { invoke } from "@tauri-apps/api/core"; import { useEffect, useState } from "react"; import { toast } from "sonner"; type BrowserTypeString = | "mullvad-browser" | "firefox" | "firefox-developer" | "chromium" | "brave" | "zen" | "tor-browser"; interface CreateProfileDialogProps { isOpen: boolean; onClose: () => void; onCreateProfile: (profileData: { name: string; browserStr: BrowserTypeString; version: string; releaseType: string; proxy?: ProxySettings; }) => Promise; } export function CreateProfileDialog({ isOpen, onClose, onCreateProfile, }: CreateProfileDialogProps) { const [profileName, setProfileName] = useState(""); const [selectedBrowser, setSelectedBrowser] = useState("mullvad-browser"); const [selectedReleaseType, setSelectedReleaseType] = useState< "stable" | "nightly" | null >(null); const [releaseTypes, setReleaseTypes] = useState({ stable: undefined, nightly: undefined, }); const [isCreating, setIsCreating] = useState(false); const [existingProfiles, setExistingProfiles] = useState( [], ); const [isLoadingReleaseTypes, setIsLoadingReleaseTypes] = useState(false); // Proxy settings const [proxyEnabled, setProxyEnabled] = useState(false); const [proxyType, setProxyType] = useState("http"); const [proxyHost, setProxyHost] = useState(""); const [proxyPort, setProxyPort] = useState(8080); const [proxyUsername, setProxyUsername] = useState(""); const [proxyPassword, setProxyPassword] = useState(""); const { downloadBrowser, isDownloading, downloadedVersions, loadDownloadedVersions, } = useBrowserDownload(); const { supportedBrowsers, isLoading: isLoadingSupport, isBrowserSupported, } = useBrowserSupport(); useEffect(() => { if (isOpen) { void loadExistingProfiles(); } }, [isOpen]); useEffect(() => { if (supportedBrowsers.length > 0) { // Set default browser to first supported browser if (supportedBrowsers.includes("mullvad-browser")) { setSelectedBrowser("mullvad-browser"); } else if (supportedBrowsers.length > 0) { setSelectedBrowser(supportedBrowsers[0] as BrowserTypeString); } } }, [supportedBrowsers]); useEffect(() => { if (isOpen && selectedBrowser) { // Reset selected release type when browser changes setSelectedReleaseType(null); void loadReleaseTypes(selectedBrowser); void loadDownloadedVersions(selectedBrowser); } }, [isOpen, selectedBrowser, loadDownloadedVersions]); // Set default release type when release types are loaded useEffect(() => { if (!selectedReleaseType && Object.keys(releaseTypes).length > 0) { // First try to set stable if it exists if (releaseTypes.stable) { setSelectedReleaseType("stable"); } // If stable doesn't exist but nightly does, set nightly as default else if (releaseTypes.nightly && selectedBrowser !== "chromium") { setSelectedReleaseType("nightly"); } } }, [releaseTypes, selectedReleaseType, selectedBrowser]); const loadExistingProfiles = async () => { try { const profiles = await invoke("list_browser_profiles"); setExistingProfiles(profiles); } catch (error) { console.error("Failed to load existing profiles:", error); } }; const loadReleaseTypes = async (browser: string) => { try { setIsLoadingReleaseTypes(true); const types = await invoke( "get_browser_release_types", { browserStr: browser, }, ); setReleaseTypes(types); } catch (error) { console.error("Failed to load release types:", error); toast.error("Failed to load available versions"); } finally { setIsLoadingReleaseTypes(false); } }; const handleDownload = async () => { if (!selectedBrowser || !selectedReleaseType) return; const version = selectedReleaseType === "stable" ? releaseTypes.stable : releaseTypes.nightly; if (!version) return; await downloadBrowser(selectedBrowser, version); }; const validateProfileName = (name: string): string | null => { const trimmedName = name.trim(); if (!trimmedName) { return "Profile name cannot be empty"; } // Check for duplicate names (case insensitive) const isDuplicate = existingProfiles.some( (profile) => profile.name.toLowerCase() === trimmedName.toLowerCase(), ); if (isDuplicate) { return "A profile with this name already exists"; } return null; }; // Helper to determine if proxy should be disabled for the selected browser const isProxyDisabled = selectedBrowser === "tor-browser"; // Update proxy enabled state when browser changes to tor-browser useEffect(() => { if (selectedBrowser === "tor-browser" && proxyEnabled) { setProxyEnabled(false); } }, [selectedBrowser, proxyEnabled]); const handleCreate = async () => { if (!profileName.trim() || !selectedBrowser || !selectedReleaseType) return; // Validate profile name const nameError = validateProfileName(profileName); if (nameError) { toast.error(nameError); return; } const version = selectedReleaseType === "stable" ? releaseTypes.stable : releaseTypes.nightly; if (!version) { toast.error("Selected release type is not available"); return; } setIsCreating(true); try { const proxy = proxyEnabled && !isProxyDisabled ? { enabled: true, proxy_type: proxyType, host: proxyHost, port: proxyPort, username: proxyUsername || undefined, password: proxyPassword || undefined, } : undefined; await onCreateProfile({ name: profileName.trim(), browserStr: selectedBrowser, version, releaseType: selectedReleaseType, proxy, }); // Reset form setProfileName(""); setSelectedReleaseType(null); setProxyEnabled(false); setProxyHost(""); setProxyPort(8080); setProxyUsername(""); setProxyPassword(""); onClose(); } catch (error) { console.error("Failed to create profile:", error); } finally { setIsCreating(false); } }; const nameError = profileName.trim() ? validateProfileName(profileName) : null; const selectedVersion = selectedReleaseType === "stable" ? releaseTypes.stable : releaseTypes.nightly; const canCreate = profileName.trim() && selectedBrowser && selectedReleaseType && selectedVersion && (!proxyEnabled || isProxyDisabled || (proxyHost && proxyPort)) && !nameError; return ( Create New Profile
{/* Profile Name */}
{ setProfileName(e.target.value); }} placeholder="Enter profile name" className={nameError ? "border-red-500" : ""} /> {nameError &&

{nameError}

}
{/* Browser Selection */}
{/* Release Type Selection */}
{isLoadingReleaseTypes ? (
Loading release types...
) : ( { void handleDownload(); }} placeholder="Select release type..." downloadedVersions={downloadedVersions} /> )}
{/* Proxy Settings */}
{isProxyDisabled ? (

Tor Browser has its own built-in proxy system and doesn't support additional proxy configuration

) : ( <> { setProxyEnabled(checked as boolean); }} /> )}
{proxyEnabled && !isProxyDisabled && ( <>
{ setProxyHost(e.target.value); }} placeholder="e.g. 127.0.0.1" />
{ setProxyPort(Number.parseInt(e.target.value, 10) || 0); }} placeholder="e.g. 8080" min="1" max="65535" />
{ setProxyUsername(e.target.value); }} placeholder="Proxy username" />
{ setProxyPassword(e.target.value); }} placeholder="Proxy password" />
)}
void handleCreate()} disabled={!canCreate} > Create Profile
); }