import { Copy, Edit2, Plus, Trash2 } from "lucide-react"; import { useEffect, useState } from "react"; import InstanceEditorModal from "@/components/instance-editor-modal"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { toNumber } from "@/lib/tsrs-utils"; import { useInstancesStore } from "@/stores/instances-store"; import type { Instance } from "../types/bindings/instance"; export function InstancesView() { const instancesStore = useInstancesStore(); // Modal / UI state const [showCreateModal, setShowCreateModal] = useState(false); const [showEditModal, setShowEditModal] = useState(false); const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); const [showDuplicateModal, setShowDuplicateModal] = useState(false); // Selected / editing instance state const [selectedInstance, setSelectedInstance] = useState( null, ); const [editingInstance, setEditingInstance] = useState(null); // Form fields const [newInstanceName, setNewInstanceName] = useState(""); const [duplicateName, setDuplicateName] = useState(""); // Load instances on mount (matches Svelte onMount behavior) useEffect(() => { instancesStore.loadInstances(); // instancesStore methods are stable (Zustand); do not add to deps to avoid spurious runs // eslint-disable-next-line react-hooks/exhaustive-deps }, [instancesStore.loadInstances]); // Handlers to open modals const openCreate = () => { setNewInstanceName(""); setShowCreateModal(true); }; const openEdit = (instance: Instance) => { setEditingInstance({ ...instance }); setShowEditModal(true); }; const openDelete = (instance: Instance) => { setSelectedInstance(instance); setShowDeleteConfirm(true); }; const openDuplicate = (instance: Instance) => { setSelectedInstance(instance); setDuplicateName(`${instance.name} (Copy)`); setShowDuplicateModal(true); }; // Confirm actions const confirmCreate = async () => { const name = newInstanceName.trim(); if (!name) return; await instancesStore.createInstance(name); setShowCreateModal(false); setNewInstanceName(""); }; const confirmEdit = async () => { if (!editingInstance) return; await instancesStore.updateInstance(editingInstance); setEditingInstance(null); setShowEditModal(false); }; const confirmDelete = async () => { if (!selectedInstance) return; await instancesStore.deleteInstance(selectedInstance.id); setSelectedInstance(null); setShowDeleteConfirm(false); }; const confirmDuplicate = async () => { if (!selectedInstance) return; const name = duplicateName.trim(); if (!name) return; await instancesStore.duplicateInstance(selectedInstance.id, name); setSelectedInstance(null); setDuplicateName(""); setShowDuplicateModal(false); }; const setActiveInstance = async (id: string) => { await instancesStore.setActiveInstance(id); }; const formatDate = (timestamp: number): string => new Date(timestamp * 1000).toLocaleDateString(); const formatLastPlayed = (timestamp: number): string => { const date = new Date(timestamp * 1000); const now = new Date(); const diff = now.getTime() - date.getTime(); const days = Math.floor(diff / (1000 * 60 * 60 * 24)); if (days === 0) return "Today"; if (days === 1) return "Yesterday"; if (days < 7) return `${days} days ago`; return date.toLocaleDateString(); }; return (

Instances

{instancesStore.instances.length === 0 ? (

No instances yet

Create your first instance to get started

) : (
    {instancesStore.instances.map((instance) => { const isActive = instancesStore.activeInstanceId === instance.id; return (
  • setActiveInstance(instance.id)} onKeyDown={(e) => e.key === "Enter" && setActiveInstance(instance.id) } className={`relative p-4 text-left rounded-lg border-2 transition-all cursor-pointer hover:border-blue-500 ${ isActive ? "border-blue-500" : "border-transparent" } bg-gray-100 dark:bg-gray-800`} > {/* Instance Icon */} {instance.iconPath ? (
    {instance.name}
    ) : (
    {instance.name.charAt(0).toUpperCase()}
    )}

    {instance.name}

    {instance.versionId ? (

    Version: {instance.versionId}

    ) : (

    No version selected

    )} {instance.modLoader && (

    Mod Loader:{" "} {instance.modLoader}

    )}

    Created: {formatDate(toNumber(instance.createdAt))}

    {instance.lastPlayed && (

    Last played:{" "} {formatLastPlayed(toNumber(instance.lastPlayed))}

    )}
    {/* Action Buttons */}
  • ); })}
)} {/* Create Modal */} Create Instance Enter a name for the new instance.
setNewInstanceName(e.target.value)} placeholder="Instance name" />
{ setShowEditModal(open); if (!open) setEditingInstance(null); }} /> {/* Delete Confirmation */} Delete Instance Are you sure you want to delete "{selectedInstance?.name}"? This action cannot be undone. {/* Duplicate Modal */} Duplicate Instance Provide a name for the duplicated instance.
setDuplicateName(e.target.value)} placeholder="New instance name" onKeyDown={(e) => e.key === "Enter" && confirmDuplicate()} />
); }