"use client"; import { invoke } from "@tauri-apps/api/core"; import { open } from "@tauri-apps/plugin-dialog"; import { useCallback, useEffect, useState } from "react"; import { FaFolder } from "react-icons/fa"; import { toast } from "sonner"; import { LoadingButton } from "@/components/loading-button"; import { Button } from "@/components/ui/button"; 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 { useBrowserSupport } from "@/hooks/use-browser-support"; import { getBrowserDisplayName, getBrowserIcon } from "@/lib/browser-utils"; import type { DetectedProfile } from "@/types"; import { RippleButton } from "./ui/ripple"; interface ImportProfileDialogProps { isOpen: boolean; onClose: () => void; onImportComplete?: () => void; } export function ImportProfileDialog({ isOpen, onClose, onImportComplete, }: ImportProfileDialogProps) { const [detectedProfiles, setDetectedProfiles] = useState( [], ); const [isLoading, setIsLoading] = useState(false); const [isImporting, setIsImporting] = useState(false); const [importMode, setImportMode] = useState<"auto-detect" | "manual">( "auto-detect", ); // Auto-detect state const [selectedDetectedProfile, setSelectedDetectedProfile] = useState< string | null >(null); const [autoDetectProfileName, setAutoDetectProfileName] = useState(""); // Manual import state const [manualBrowserType, setManualBrowserType] = useState( null, ); const [manualProfilePath, setManualProfilePath] = useState(""); const [manualProfileName, setManualProfileName] = useState(""); const { supportedBrowsers, isLoading: isLoadingSupport } = useBrowserSupport(); const loadDetectedProfiles = useCallback(async () => { setIsLoading(true); try { const profiles = await invoke( "detect_existing_profiles", ); setDetectedProfiles(profiles); // Auto-switch to manual mode if no profiles detected if (profiles.length === 0) { setImportMode("manual"); } else { // Auto-select first profile if available setSelectedDetectedProfile(profiles[0].path); // Generate default name from the detected profile const profile = profiles[0]; const browserName = getBrowserDisplayName(profile.browser); const defaultName = `Imported ${browserName} Profile`; setAutoDetectProfileName(defaultName); } } catch (error) { console.error("Failed to detect existing profiles:", error); toast.error("Failed to detect existing browser profiles"); } finally { setIsLoading(false); } }, []); const handleBrowseFolder = async () => { try { const selected = await open({ directory: true, multiple: false, title: "Select Browser Profile Folder", }); if (selected && typeof selected === "string") { setManualProfilePath(selected); } } catch (error) { console.error("Failed to open folder dialog:", error); toast.error("Failed to open folder dialog"); } }; const handleAutoDetectImport = useCallback(async () => { if (!selectedDetectedProfile || !autoDetectProfileName.trim()) { toast.error("Please select a profile and provide a name"); return; } const profile = detectedProfiles.find( (p) => p.path === selectedDetectedProfile, ); if (!profile) { toast.error("Selected profile not found"); return; } setIsImporting(true); try { await invoke("import_browser_profile", { sourcePath: profile.path, browserType: profile.browser, newProfileName: autoDetectProfileName.trim(), }); toast.success( `Successfully imported profile "${autoDetectProfileName.trim()}"`, ); if (onImportComplete) { onImportComplete(); } onClose(); } catch (error) { console.error("Failed to import profile:", error); const errorMessage = error instanceof Error ? error.message : String(error); // Check if error is about browser not being downloaded if (errorMessage.includes("No downloaded versions found")) { const browserDisplayName = getBrowserDisplayName(profile.browser); toast.error( `${browserDisplayName} is not installed. Please download ${browserDisplayName} first from the main window, then try importing again.`, { duration: 8000, }, ); } else { toast.error(`Failed to import profile: ${errorMessage}`); } } finally { setIsImporting(false); } }, [ selectedDetectedProfile, autoDetectProfileName, detectedProfiles, onImportComplete, onClose, ]); const handleManualImport = useCallback(async () => { if ( !manualBrowserType || !manualProfilePath.trim() || !manualProfileName.trim() ) { toast.error("Please fill in all fields"); return; } setIsImporting(true); try { await invoke("import_browser_profile", { sourcePath: manualProfilePath.trim(), browserType: manualBrowserType, newProfileName: manualProfileName.trim(), }); toast.success( `Successfully imported profile "${manualProfileName.trim()}"`, ); if (onImportComplete) { onImportComplete(); } onClose(); } catch (error) { console.error("Failed to import profile:", error); const errorMessage = error instanceof Error ? error.message : String(error); // Check if error is about browser not being downloaded if (errorMessage.includes("No downloaded versions found")) { const browserDisplayName = getBrowserDisplayName(manualBrowserType); toast.error( `${browserDisplayName} is not installed. Please download ${browserDisplayName} first from the main window, then try importing again.`, { duration: 8000, }, ); } else { toast.error(`Failed to import profile: ${errorMessage}`); } } finally { setIsImporting(false); } }, [ manualBrowserType, manualProfilePath, manualProfileName, onImportComplete, onClose, ]); const handleClose = () => { setSelectedDetectedProfile(null); setAutoDetectProfileName(""); setManualBrowserType(null); setManualProfilePath(""); setManualProfileName(""); // Only reset to auto-detect if there are profiles available if (detectedProfiles.length > 0) { setImportMode("auto-detect"); } else { setImportMode("manual"); } onClose(); }; // Update auto-detect profile name when selection changes useEffect(() => { if (selectedDetectedProfile) { const profile = detectedProfiles.find( (p) => p.path === selectedDetectedProfile, ); if (profile) { const browserName = getBrowserDisplayName(profile.browser); const defaultName = `Old ${browserName}`; setAutoDetectProfileName(defaultName); } } }, [selectedDetectedProfile, detectedProfiles]); const selectedProfile = detectedProfiles.find( (p) => p.path === selectedDetectedProfile, ); useEffect(() => { if (isOpen) { void loadDetectedProfiles(); } }, [isOpen, loadDetectedProfiles]); return ( Import Browser Profile
{/* Mode Selection */}
{ setImportMode("auto-detect"); }} className="flex-1" disabled={isLoading} > Auto-Detect { setImportMode("manual"); }} className="flex-1" disabled={isLoading} > Manual Import
{/* Auto-Detect Mode */} {importMode === "auto-detect" && (

Detected Browser Profiles

{isLoading ? (

Scanning for browser profiles...

) : detectedProfiles.length === 0 ? (

No browser profiles found on your system.

Try the manual import option if you have profiles in custom locations.

) : (
{selectedProfile && (

Path:{" "} {selectedProfile.path}

Browser:{" "} {getBrowserDisplayName(selectedProfile.browser)}

)}
{ setAutoDetectProfileName(e.target.value); }} placeholder="Enter a name for the imported profile" />
)}
)} {/* Manual Import Mode */} {importMode === "manual" && (

Manual Profile Import

{ setManualProfilePath(e.target.value); }} placeholder="Enter the full path to the profile folder" />

Example paths:
macOS: ~/Library/Application Support/Firefox/Profiles/xxx.default
Windows: %APPDATA%\Mozilla\Firefox\Profiles\xxx.default
Linux: ~/.mozilla/firefox/xxx.default

{ setManualProfileName(e.target.value); }} placeholder="Enter a name for the imported profile" />
)}
Cancel {importMode === "auto-detect" ? ( { void handleAutoDetectImport(); }} disabled={ !selectedDetectedProfile || !autoDetectProfileName.trim() || isLoading } > Import ) : ( { void handleManualImport(); }} disabled={ !manualBrowserType || !manualProfilePath.trim() || !manualProfileName.trim() } > Import )}
); }