"use client"; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Loader2, Plus, RefreshCw, X } from "@/components/icons/platform-icons"; import { useCurrentUser } from "@/hooks/useCurrentUser"; import { useCreateNetworkShare, useDiscoverNetworkServers, useDiscoverNetworkShares, useMountNetworkShare, useNetworkShares, useRemoveNetworkShare, useUnmountNetworkShare, } from "@/modules/files/hooks/useNetworkShares"; import { AddNetworkShareDialog, type AddNetworkShareDraft, } from "@/modules/files/components/dialogs/network-storage/add-network-share-dialog"; import { NetworkStorageGrid } from "@/modules/files/components/dialogs/network-storage/network-storage-grid"; import { useEffect, useMemo, useRef, useState } from "react"; type NetworkStorageDialogProps = { isOpen: boolean; onClose: () => void; onNavigateToNetwork: () => void; }; const EMPTY_DRAFT: AddNetworkShareDraft = { host: "", share: "", username: "", password: "", }; export function NetworkStorageDialog({ isOpen, onClose, onNavigateToNetwork, }: NetworkStorageDialogProps) { const currentUserQuery = useCurrentUser(); const autoDiscoverRanRef = useRef(false); const [isAddFormOpen, setIsAddFormOpen] = useState(false); const [draft, setDraft] = useState(EMPTY_DRAFT); const [localError, setLocalError] = useState(null); const [discoveredServers, setDiscoveredServers] = useState([]); const [discoveredShares, setDiscoveredShares] = useState([]); const sharesQuery = useNetworkShares(); const discoverServers = useDiscoverNetworkServers(); const discoverShares = useDiscoverNetworkShares(); const createShare = useCreateNetworkShare(); const removeShare = useRemoveNetworkShare(); const mountShare = useMountNetworkShare(); const unmountShare = useUnmountNetworkShare(); const isDemoMode = currentUserQuery.data?.isDemoMode ?? false; const isBusy = discoverServers.isPending || discoverShares.isPending || createShare.isPending || removeShare.isPending || mountShare.isPending || unmountShare.isPending; const apiError = useMemo(() => { return ( localError || (sharesQuery.error instanceof Error ? sharesQuery.error.message : null) || (discoverServers.error instanceof Error ? discoverServers.error.message : null) || (discoverShares.error instanceof Error ? discoverShares.error.message : null) || (createShare.error instanceof Error ? createShare.error.message : null) || (removeShare.error instanceof Error ? removeShare.error.message : null) || (mountShare.error instanceof Error ? mountShare.error.message : null) || (unmountShare.error instanceof Error ? unmountShare.error.message : null) ); }, [ createShare.error, discoverServers.error, discoverShares.error, localError, mountShare.error, removeShare.error, sharesQuery.error, unmountShare.error, ]); useEffect(() => { if (isOpen) return; autoDiscoverRanRef.current = false; setIsAddFormOpen(false); setDraft(EMPTY_DRAFT); setLocalError(null); setDiscoveredServers([]); setDiscoveredShares([]); }, [isOpen]); const discoverServersMutate = discoverServers.mutateAsync; useEffect(() => { if (!isOpen || autoDiscoverRanRef.current) return; autoDiscoverRanRef.current = true; setLocalError(null); void discoverServersMutate() .then((result) => { setDiscoveredServers(result.servers); }) .catch(() => { // Errors surface through the mutation state. }); }, [discoverServersMutate, isOpen]); if (isDemoMode) return null; async function handleDiscoverServers() { setLocalError(null); const result = await discoverServers.mutateAsync(); setDiscoveredServers(result.servers); } async function handleDiscoverShares() { setLocalError(null); if (!draft.host.trim() || !draft.username.trim() || !draft.password) { setLocalError("Host, username, and password are required to discover shares."); return; } const result = await discoverShares.mutateAsync({ host: draft.host.trim(), username: draft.username.trim(), password: draft.password, }); setDiscoveredShares(result.shares); } async function handleAddShare() { setLocalError(null); if (!draft.host.trim() || !draft.share.trim() || !draft.username.trim() || !draft.password) { setLocalError("Host, share, username, and password are required."); return; } await createShare.mutateAsync({ host: draft.host.trim(), share: draft.share.trim(), username: draft.username.trim(), password: draft.password, }); setIsAddFormOpen(false); onNavigateToNetwork(); } return ( <> !open && onClose()}> Network Storage Discover, mount, and manage SMB shares. {/* Window chrome title bar */}
{/* Traffic lights */}
{/* Centered title */}
Network Storage
{/* Right actions */}
{/* Grid + floating add button */}
void mountShare.mutateAsync(id)} onRemove={(id) => void removeShare.mutateAsync(id)} onSelectServer={(host) => { setDraft((current) => ({ ...current, host })); setIsAddFormOpen(true); }} onUnmount={(id) => void unmountShare.mutateAsync(id)} />
{apiError ? (
{apiError}
) : null}
setIsAddFormOpen(false)} onDiscoverServers={() => void handleDiscoverServers()} onDiscoverShares={() => void handleDiscoverShares()} onDraftChange={setDraft} onSelectShare={(share) => setDraft((current) => ({ ...current, share }))} onSubmit={() => void handleAddShare()} /> ); }