import React, { useState, useEffect } from "react"; import { Search, Download, Trash2, Package, CheckCircle2, XCircle, X, } from "lucide-react"; import { getInstalledMods, discoverMods, toggleMod, installMod, } from "@/lib/saturn"; import { clsx, type ClassValue } from "clsx"; import { twMerge } from "tailwind-merge"; import { motion, AnimatePresence } from "framer-motion"; import { GameVersion, Mod } from "@/lib/types"; import { versions } from "@/lib/launcher"; function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); } interface ModsSectionProps { version: GameVersion; } const ModsSection: React.FC = ({ version }) => { const [activeTab, setActiveTab] = useState<"installed" | "discover">( "installed", ); const [searchQuery, setSearchQuery] = useState(""); const [mods, setMods] = useState([]); const [isInstallDialogOpen, setIsInstallDialogOpen] = useState(false); const [selectedModForInstall, setSelectedModForInstall] = useState(null); const [selectedVersionsForInstall, setSelectedVersionsForInstall] = useState< string[] >([]); useEffect(() => { const loadMods = async () => { if (activeTab === "installed") { const m = await getInstalledMods(version.id); setMods(m); } else { const m = await discoverMods(searchQuery); if (activeTab === "discover") { // Fix: If discover mods takes too long and the user switches tabs it glitches setMods(m); } } }; const id = setTimeout(loadMods, 800); return () => clearTimeout(id); }, [activeTab, version.id, searchQuery]); const handleToggleMod = async (modId: string) => { await toggleMod(modId); const m = await getInstalledMods(version.id); setMods(m); }; const openInstallDialog = (mod: Mod) => { setSelectedModForInstall(mod); setSelectedVersionsForInstall([version.id]); setIsInstallDialogOpen(true); }; const handleInstall = async () => { if (selectedModForInstall && selectedVersionsForInstall.length > 0) { await installMod(selectedModForInstall, selectedVersionsForInstall); setIsInstallDialogOpen(false); if (activeTab === "installed") { const m = await getInstalledMods(version.id); setMods(m); } } }; const toggleVersionSelection = (versionId: string) => { setSelectedVersionsForInstall((prev) => prev.includes(versionId) ? prev.filter((v) => v !== versionId) : [...prev, versionId], ); }; return (
setSearchQuery(e.target.value)} className="bg-saturn-panel border border-saturn-border rounded-lg pl-10 pr-4 py-2 text-sm w-64 focus:outline-none focus:border-saturn-accent/50 focus:ring-1 focus:ring-saturn-accent/50 transition-all" />
{mods.map((mod) => (

{mod.name}

v{mod.version} by {mod.author}

{mod.description}

{activeTab === "installed" ? ( <> ) : ( )}
))} {mods.length === 0 && (

No mods found.

)}
{/* Install Dialog */} {isInstallDialogOpen && selectedModForInstall && (

Install {selectedModForInstall.name}

Select versions to install this mod to.

{versions.map((v) => { const isSupported = selectedModForInstall.supported_versions.includes(v.id); const isSelected = selectedVersionsForInstall.includes(v.id); return (
isSupported && toggleVersionSelection(v.id) } className={cn( "flex items-center justify-between p-3 rounded-lg border transition-all cursor-pointer", isSelected ? "bg-saturn-accent/10 border-saturn-accent/50" : "bg-white/5 border-transparent hover:border-white/10", !isSupported && "opacity-40 cursor-not-allowed grayscale", )} >
{isSelected && ( )}
{v.name}
{!isSupported && ( Unsupported )}
); })}
)}
); }; export default ModsSection;