All files / pages/collections CollectionsWorkspaceLayout.tsx

43.75% Statements 7/16
75% Branches 3/4
33.33% Functions 2/6
43.75% Lines 7/16

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102                                                  82x 82x 82x   82x   82x                                     82x                                                                                         26x            
/**
 * Collections workspace shell: browser rail + main outlet.
 */
 
import { useState } from 'react';
import { Outlet } from 'react-router';
import { Download, Upload } from 'lucide-react';
import { Button } from '@/components/ui/button';
import ImportCollectionsDialog from '@/components/collections/ImportCollectionsDialog';
import { exportCollections } from '@/services/collections.service';
import { handleApiError } from '@/lib/api';
import { useToast } from '@/hooks/use-toast';
import { useCollectionsWorkspaceShortcuts } from '@/hooks/useCollectionsWorkspaceShortcuts';
import {
  CollectionsWorkspaceProvider,
  useCollectionsWorkspace,
} from './CollectionsWorkspaceContext';
import CollectionBrowserRail from './CollectionBrowserRail';
 
function WorkspaceChrome() {
  const {
    isSuperadmin,
    importDialogOpen,
    setImportDialogOpen,
    refreshCollections,
  } = useCollectionsWorkspace();
  const { toast } = useToast();
  const [isExporting, setIsExporting] = useState(false);
 
  useCollectionsWorkspaceShortcuts({ enabled: true });
 
  const handleExport = async () => {
    setIsExporting(true);
    try {
      await exportCollections();
      toast({
        title: 'Export successful',
        description: 'Collections exported to JSON file',
      });
    } catch (err) {
      toast({
        variant: 'destructive',
        title: 'Export failed',
        description: handleApiError(err),
      });
    } finally {
      setIsExporting(false);
    }
  };
 
  return (
    <div
      className="flex h-full min-h-0 flex-1 overflow-hidden"
      data-testid="collections-workspace"
    >
      <CollectionBrowserRail />
      <div className="flex min-w-0 flex-1 flex-col overflow-hidden">
        {isSuperadmin && (
          <div className="flex shrink-0 items-center justify-end gap-2 border-b bg-background px-4 py-2">
            <Button
              variant="outline"
              size="sm"
              className="gap-1.5"
              onClick={() => void handleExport()}
              disabled={isExporting}
            >
              <Download className="h-3.5 w-3.5" />
              {isExporting ? 'Exporting…' : 'Export JSON'}
            </Button>
            <Button
              variant="outline"
              size="sm"
              className="gap-1.5"
              onClick={() => setImportDialogOpen(true)}
            >
              <Upload className="h-3.5 w-3.5" />
              Import JSON
            </Button>
          </div>
        )}
        <div className="min-h-0 flex-1 overflow-y-auto">
          <Outlet />
        </div>
      </div>
 
      <ImportCollectionsDialog
        open={importDialogOpen}
        onOpenChange={setImportDialogOpen}
        onSuccess={() => void refreshCollections()}
      />
    </div>
  );
}
 
export default function CollectionsWorkspaceLayout() {
  return (
    <CollectionsWorkspaceProvider>
      <WorkspaceChrome />
    </CollectionsWorkspaceProvider>
  );
}