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>
);
}
|