summaryrefslogtreecommitdiff
path: root/components/file-manager/FileManager.tsx
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-10-15 12:52:11 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-10-15 12:52:11 +0000
commitb54f6f03150dd78d86db62201b6386bf14b72394 (patch)
treeb3092bb34805fdc65eee5282e86a9fb90ba20d6e /components/file-manager/FileManager.tsx
parentc1bd1a2f499ee2f0742170021b37dab410983ab7 (diff)
(대표님) 커버, 데이터룸, 파일매니저, 담당자할당 등
Diffstat (limited to 'components/file-manager/FileManager.tsx')
-rw-r--r--components/file-manager/FileManager.tsx729
1 files changed, 244 insertions, 485 deletions
diff --git a/components/file-manager/FileManager.tsx b/components/file-manager/FileManager.tsx
index fa2d8c38..f92f6b04 100644
--- a/components/file-manager/FileManager.tsx
+++ b/components/file-manager/FileManager.tsx
@@ -266,10 +266,6 @@ const TreeItem: React.FC<{
{isInternalUser && (
<>
- <DropdownMenuItem onClick={() => onShare(item)}>
- <Share2 className="h-4 w-4 mr-2" />
- Share
- </DropdownMenuItem>
{item.permissions?.canEdit && (
<DropdownMenuItem onClick={() => onRename(item)}>
@@ -624,44 +620,6 @@ export function FileManager({ projectId }: FileManagerProps) {
}
};
- // Share file
- const shareFile = async () => {
- if (!selectedFile) return;
-
- try {
- const response = await fetch(`/api/data-room/${projectId}/share`, {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({
- fileId: selectedFile.id,
- ...shareSettings,
- }),
- });
-
- if (!response.ok) {
- throw new Error('Failed to create share link');
- }
-
- const data = await response.json();
-
- // Copy share link to clipboard
- await navigator.clipboard.writeText(data.shareUrl);
-
- toast({
- title: 'Share Link Created',
- description: 'Link copied to clipboard.',
- });
-
- setShareDialogOpen(false);
- setSelectedFile(null);
- } catch (error) {
- toast({
- title: 'Error',
- description: 'Failed to create share link.',
- variant: 'destructive',
- });
- }
- };
// Download multiple files
const downloadMultipleFiles = async (itemIds: string[]) => {
@@ -974,9 +932,9 @@ export function FileManager({ projectId }: FileManagerProps) {
};
return (
- <div className="flex flex-col h-full">
- {/* Toolbar */}
- <div className="border-b p-4">
+ <div className="h-full flex flex-col min-h-0">
+ {/* Toolbar - 고정 */}
+ <div className="border-b p-4 bg-background shrink-0">
<div className="flex items-center justify-between mb-3">
<div className="flex items-center gap-2">
{isInternalUser && (
@@ -1091,204 +1049,114 @@ export function FileManager({ projectId }: FileManagerProps) {
</Breadcrumb>
</div>
- {/* File List */}
- <ScrollArea className="flex-1 p-4">
- {loading ? (
- <div className="flex justify-center items-center h-64">
- <div className="text-muted-foreground">Loading...</div>
- </div>
- ) : filteredItems.length === 0 ? (
- <div className="flex flex-col items-center justify-center h-64">
- <Folder className="h-12 w-12 text-muted-foreground mb-2" />
- <p className="text-muted-foreground">Empty</p>
- </div>
- ) : viewMode === 'grid' ? (
- <div className="grid grid-cols-6 gap-4">
- {filteredItems.map((item) => {
- const CategoryIcon = categoryConfig[item.category].icon;
- const categoryColor = categoryConfig[item.category].color;
-
- return (
- <ContextMenu key={item.id}>
- <ContextMenuTrigger>
- <div
- className={cn(
- "flex flex-col items-center p-3 rounded-lg cursor-pointer transition-colors",
- "hover:bg-accent",
- selectedItems.has(item.id) && "bg-accent"
- )}
- onClick={() => toggleItemSelection(item.id)}
- onDoubleClick={() => {
- if (item.type === 'folder') {
- handleFolderOpen(item);
- }
- }}
- >
- <div className="relative">
- {item.type === 'folder' ? (
- <Folder className="h-12 w-12 text-blue-500" />
- ) : (
- <File className="h-12 w-12 text-gray-500" />
- )}
- <CategoryIcon className={cn("h-4 w-4 absolute -bottom-1 -right-1", categoryColor)} />
- </div>
-
- <span className="mt-2 text-sm text-center truncate w-full">
- {item.name}
- </span>
+ {/* File List - 스크롤 가능 영역 */}
+ <div className="flex-1 min-h-0">
+ <ScrollArea className="h-full">
+ <div className="p-4">
+ {loading ? (
+ <div className="flex justify-center items-center h-64">
+ <div className="text-muted-foreground">Loading...</div>
+ </div>
+ ) : filteredItems.length === 0 ? (
+ <div className="flex flex-col items-center justify-center h-64">
+ <Folder className="h-12 w-12 text-muted-foreground mb-2" />
+ <p className="text-muted-foreground">Empty</p>
+ </div>
+ ) : viewMode === 'grid' ? (
+ <div className="grid grid-cols-6 gap-4">
+ {filteredItems.map((item) => {
+ const CategoryIcon = categoryConfig[item.category].icon;
+ const categoryColor = categoryConfig[item.category].color;
- {item.viewCount !== undefined && (
- <div className="flex items-center gap-2 mt-1">
- <span className="text-xs text-muted-foreground flex items-center">
- <Eye className="h-3 w-3 mr-1" />
- {item.viewCount}
- </span>
- {item.downloadCount !== undefined && (
- <span className="text-xs text-muted-foreground flex items-center">
- <Download className="h-3 w-3 mr-1" />
- {item.downloadCount}
- </span>
+ return (
+ <ContextMenu key={item.id}>
+ <ContextMenuTrigger>
+ <div
+ className={cn(
+ "flex flex-col items-center p-3 rounded-lg cursor-pointer transition-colors",
+ "hover:bg-accent",
+ selectedItems.has(item.id) && "bg-accent"
)}
- </div>
- )}
- </div>
- </ContextMenuTrigger>
-
- <ContextMenuContent>
- {item.type === 'folder' && (
- <>
- <ContextMenuItem onClick={() => handleFolderOpen(item)}>
- Open
- </ContextMenuItem>
- <ContextMenuItem onClick={() => downloadFolder(item)}>
- <Download className="h-4 w-4 mr-2" />
- Download Folder
- </ContextMenuItem>
- </>
- )}
-
- {item.type === 'file' && (
- <>
- <ContextMenuItem onClick={() => viewFile(item)}>
- <Eye className="h-4 w-4 mr-2" />
- View
- </ContextMenuItem>
- {item.permissions?.canDownload === 'true' && (
- <ContextMenuItem onClick={() => downloadFile(item)}>
- <Download className="h-4 w-4 mr-2" />
- Download
- </ContextMenuItem>
- )}
- </>
- )}
-
- {isInternalUser && (
- <>
- <ContextMenuSeparator />
- <ContextMenuSub>
- <ContextMenuSubTrigger>
- <Shield className="h-4 w-4 mr-2" />
- Change Category
- </ContextMenuSubTrigger>
- <ContextMenuSubContent>
- {Object.entries(categoryConfig).map(([key, config]) => (
- <ContextMenuItem
- key={key}
- onClick={() => {
- if (item.type === 'folder') {
- // Show dialog for folders
- setSelectedFile(item);
- setNewCategory(key);
- setCategoryDialogOpen(true);
- } else {
- // Change immediately for files
- changeCategory(item.id, key, false);
- }
- }}
- >
- <config.icon className={cn("h-4 w-4 mr-2", config.color)} />
- {config.label}
- </ContextMenuItem>
- ))}
- </ContextMenuSubContent>
- </ContextMenuSub>
-
- <ContextMenuItem
- onClick={() => {
- setSelectedFile(item);
- setShareDialogOpen(true);
+ onClick={() => toggleItemSelection(item.id)}
+ onDoubleClick={() => {
+ if (item.type === 'folder') {
+ handleFolderOpen(item);
+ }
}}
>
- <Share2 className="h-4 w-4 mr-2" />
- Share
- </ContextMenuItem>
-
- {item.permissions?.canEdit && (
- <ContextMenuItem onClick={() => {
- setSelectedFile(item);
- setDialogValue(item.name);
- setRenameDialogOpen(true);
- }}>
- <Edit2 className="h-4 w-4 mr-2" />
- Rename
- </ContextMenuItem>
- )}
- </>
- )}
+ <div className="relative">
+ {item.type === 'folder' ? (
+ <Folder className="h-12 w-12 text-blue-500" />
+ ) : (
+ <File className="h-12 w-12 text-gray-500" />
+ )}
+ <CategoryIcon className={cn("h-4 w-4 absolute -bottom-1 -right-1", categoryColor)} />
+ </div>
+
+ <span className="mt-2 text-sm text-center truncate w-full">
+ {item.name}
+ </span>
- {item.permissions?.canDelete && (
- <>
- <ContextMenuSeparator />
- <ContextMenuItem
- className="text-destructive"
- onClick={() => deleteItems([item.id])}
- >
- <Trash2 className="h-4 w-4 mr-2" />
- Delete
- </ContextMenuItem>
- </>
- )}
- </ContextMenuContent>
- </ContextMenu>
- );
- })}
- </div>
- ) : (
- // Tree View
- <div className="space-y-1">
- {filteredTreeItems.map((item) => (
- <TreeItem
- key={item.id}
- item={item}
- level={0}
- expandedFolders={expandedFolders}
- selectedItems={selectedItems}
- onToggleExpand={toggleFolderExpand}
- onSelectItem={toggleItemSelection}
- onDoubleClick={handleFolderOpen}
- onView={viewFile}
- onDownload={downloadFile}
- onDownloadFolder={downloadFolder}
- onDelete={deleteItems}
- onShare={(item) => {
- setSelectedFile(item);
- setShareDialogOpen(true);
- }}
- onRename={(item) => {
- setSelectedFile(item);
- setDialogValue(item.name);
- setRenameDialogOpen(true);
- }}
- isInternalUser={isInternalUser}
- />
- ))}
+ {item.viewCount !== undefined && (
+ <div className="flex items-center gap-2 mt-1">
+ <span className="text-xs text-muted-foreground flex items-center">
+ <Eye className="h-3 w-3 mr-1" />
+ {item.viewCount}
+ </span>
+ {item.downloadCount !== undefined && (
+ <span className="text-xs text-muted-foreground flex items-center">
+ <Download className="h-3 w-3 mr-1" />
+ {item.downloadCount}
+ </span>
+ )}
+ </div>
+ )}
+ </div>
+ </ContextMenuTrigger>
+
+ {/* ... ContextMenuContent는 동일 ... */}
+ </ContextMenu>
+ );
+ })}
+ </div>
+ ) : (
+ // Tree View
+ <div className="space-y-1">
+ {filteredTreeItems.map((item) => (
+ <TreeItem
+ key={item.id}
+ item={item}
+ level={0}
+ expandedFolders={expandedFolders}
+ selectedItems={selectedItems}
+ onToggleExpand={toggleFolderExpand}
+ onSelectItem={toggleItemSelection}
+ onDoubleClick={handleFolderOpen}
+ onView={viewFile}
+ onDownload={downloadFile}
+ onDownloadFolder={downloadFolder}
+ onDelete={deleteItems}
+ onShare={(item) => {
+ setSelectedFile(item);
+ setShareDialogOpen(true);
+ }}
+ onRename={(item) => {
+ setSelectedFile(item);
+ setDialogValue(item.name);
+ setRenameDialogOpen(true);
+ }}
+ isInternalUser={isInternalUser}
+ />
+ ))}
+ </div>
+ )}
</div>
- )}
- </ScrollArea>
+ </ScrollArea>
+ </div>
{/* Upload Dialog */}
<Dialog open={uploadDialogOpen} onOpenChange={setUploadDialogOpen}>
- <DialogContent className="max-w-2xl">
+ <DialogContent className="max-w-2xl max-h-[90vh] flex flex-col">
<DialogHeader>
<DialogTitle>Upload Files</DialogTitle>
<DialogDescription>
@@ -1296,138 +1164,154 @@ export function FileManager({ projectId }: FileManagerProps) {
</DialogDescription>
</DialogHeader>
- <div className="space-y-4">
- {/* Category Selection */}
- <div>
- <Label htmlFor="upload-category">Category</Label>
- <Select value={uploadCategory} onValueChange={setUploadCategory}>
- <SelectTrigger>
- <SelectValue />
- </SelectTrigger>
- <SelectContent>
- {Object.entries(categoryConfig)
- .filter(([key]) => {
- // 현재 폴더가 있는 경우
- if (currentParentId) {
- const currentFolder = items.find(item => item.parentId === currentParentId);
- // 현재 폴더가 public이 아니면 public 옵션 제외
- if (currentFolder && currentFolder.category !== 'public') {
- return key !== 'public';
+ <ScrollArea className="flex-1 pr-4">
+ <div className="space-y-4">
+ {/* Category Selection */}
+ <div>
+ <Label htmlFor="upload-category">Category</Label>
+ <Select value={uploadCategory} onValueChange={setUploadCategory}>
+ <SelectTrigger>
+ <SelectValue />
+ </SelectTrigger>
+ <SelectContent>
+ {Object.entries(categoryConfig)
+ .filter(([key]) => {
+ // 현재 폴더가 있는 경우
+ if (currentParentId) {
+ const currentFolder = items.find(item => item.parentId === currentParentId);
+ // 현재 폴더가 public이 아니면 public 옵션 제외
+ if (currentFolder && currentFolder.category !== 'public') {
+ return key !== 'public';
+ }
}
- }
- // 루트 폴더이거나 현재 폴더가 public인 경우 모든 옵션 표시
- return true;
- })
- .map(([key, config]) => (
- <SelectItem key={key} value={key}>
- <div className="flex items-center">
- <config.icon className={cn("h-4 w-4 mr-2", config.color)} />
- <span>{config.label}</span>
- </div>
- </SelectItem>
- ))}
- </SelectContent>
- </Select>
- {/* 현재 폴더 정보 표시 (선택사항) */}
- {currentParentId && (() => {
- const currentFolder = items.find(item => item.parentId === currentParentId);
- if (currentFolder && currentFolder.category !== 'public') {
- return (
- <p className="text-xs text-muted-foreground mt-1 flex items-center">
- <AlertCircle className="h-3 w-3 mr-1" />
- Current folder is {categoryConfig[currentFolder.category].label}.
- Public uploads are not allowed.
- </p>
- );
- }
- })()}
- </div>
+ // 루트 폴더이거나 현재 폴더가 public인 경우 모든 옵션 표시
+ return true;
+ })
+ .map(([key, config]) => (
+ <SelectItem key={key} value={key}>
+ <div className="flex items-center">
+ <config.icon className={cn("h-4 w-4 mr-2", config.color)} />
+ <span>{config.label}</span>
+ </div>
+ </SelectItem>
+ ))}
+ </SelectContent>
+ </Select>
+ {/* 현재 폴더 정보 표시 (선택사항) */}
+ {currentParentId && (() => {
+ const currentFolder = items.find(item => item.parentId === currentParentId);
+ if (currentFolder && currentFolder.category !== 'public') {
+ return (
+ <p className="text-xs text-muted-foreground mt-1 flex items-center">
+ <AlertCircle className="h-3 w-3 mr-1" />
+ Current folder is {categoryConfig[currentFolder.category].label}.
+ Public uploads are not allowed.
+ </p>
+ );
+ }
+ })()}
+ </div>
- {/* Dropzone */}
- <Dropzone
- onDrop={(acceptedFiles: File[]) => {
- handleFileUpload(acceptedFiles);
- }}
- accept={{
- 'application/pdf': ['.pdf'],
- 'application/msword': ['.doc'],
- 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': ['.docx'],
- 'application/vnd.ms-excel': ['.xls'],
- 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': ['.xlsx'],
- 'application/vnd.ms-powerpoint': ['.ppt'],
- 'application/vnd.openxmlformats-officedocument.presentationml.presentation': ['.pptx'],
- 'text/plain': ['.txt'],
- 'text/csv': ['.csv'],
- 'image/*': ['.png', '.jpg', '.jpeg', '.gif', '.bmp', '.webp'],
- 'application/zip': ['.zip'],
- 'application/x-rar-compressed': ['.rar'],
- 'application/x-7z-compressed': ['.7z'],
- 'application/x-dwg': ['.dwg'],
- 'application/x-dxf': ['.dxf'],
- }}
- multiple={true}
- disabled={false}
- >
- <DropzoneZone className="h-48 border-2 border-dashed border-gray-300 rounded-lg">
- <DropzoneInput />
- <div className="flex flex-col items-center justify-center h-full">
- <DropzoneUploadIcon className="h-12 w-12 text-muted-foreground mb-4" />
- <DropzoneTitle>Drag files or click to upload</DropzoneTitle>
- <DropzoneDescription>Multiple files can be uploaded simultaneously</DropzoneDescription>
- </div>
- </DropzoneZone>
- </Dropzone>
-
- {/* Uploading File List */}
- {uploadingFiles.length > 0 && (
- <FileList>
- <FileListHeader>Uploading Files</FileListHeader>
- {uploadingFiles.map((uploadFile, index) => (
- <FileListItem key={index}>
- <FileListIcon>
- <File className="h-4 w-4" />
- </FileListIcon>
- <FileListInfo>
- <FileListName>{uploadFile.file.name}</FileListName>
- <FileListDescription>
- <div className="flex items-center gap-2">
- <FileListSize>{uploadFile.file.size}</FileListSize>
- {uploadFile.status === 'uploading' && <span>Uploading...</span>}
- {uploadFile.status === 'processing' && <span>Processing...</span>}
- {uploadFile.status === 'completed' && (
- <span className="text-green-600">Complete</span>
- )}
- {uploadFile.status === 'error' && (
- <span className="text-red-600">{uploadFile.error}</span>
+ {/* Dropzone */}
+ <Dropzone
+ onDrop={(acceptedFiles: File[]) => {
+ handleFileUpload(acceptedFiles);
+ }}
+ accept={{
+ 'application/pdf': ['.pdf'],
+ 'application/msword': ['.doc'],
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': ['.docx'],
+ 'application/vnd.ms-excel': ['.xls'],
+ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': ['.xlsx'],
+ 'application/vnd.ms-powerpoint': ['.ppt'],
+ 'application/vnd.openxmlformats-officedocument.presentationml.presentation': ['.pptx'],
+ 'text/plain': ['.txt'],
+ 'text/csv': ['.csv'],
+ 'image/*': ['.png', '.jpg', '.jpeg', '.gif', '.bmp', '.webp'],
+ 'application/zip': ['.zip'],
+ 'application/x-rar-compressed': ['.rar'],
+ 'application/x-7z-compressed': ['.7z'],
+ 'application/x-dwg': ['.dwg'],
+ 'application/x-dxf': ['.dxf'],
+ }}
+ multiple={true}
+ disabled={false}
+ >
+ <DropzoneZone className="h-48 border-2 border-dashed border-gray-300 rounded-lg">
+ <DropzoneInput />
+ <div className="flex flex-col items-center justify-center h-full">
+ <DropzoneUploadIcon className="h-12 w-12 text-muted-foreground mb-4" />
+ <DropzoneTitle>Drag files or click to upload</DropzoneTitle>
+ <DropzoneDescription>Multiple files can be uploaded simultaneously</DropzoneDescription>
+ </div>
+ </DropzoneZone>
+ </Dropzone>
+
+ {/* Uploading File List */}
+ {uploadingFiles.length > 0 && (
+ <div className="border rounded-lg p-4 bg-muted/50">
+ <div className="flex items-center justify-between mb-3">
+ <h4 className="font-medium text-sm">
+ Uploading Files ({uploadingFiles.filter(f => f.status === 'completed').length}/{uploadingFiles.length})
+ </h4>
+ {uploadingFiles.every(f => f.status === 'completed' || f.status === 'error') && (
+ <Button
+ size="sm"
+ variant="ghost"
+ onClick={() => setUploadingFiles([])}
+ >
+ <X className="h-4 w-4" />
+ </Button>
+ )}
+ </div>
+ <div className="space-y-2 max-h-[300px] overflow-y-auto">
+ {uploadingFiles.map((uploadFile, index) => (
+ <div key={index} className="flex items-start gap-3 p-3 bg-background rounded-md">
+ <File className="h-5 w-5 mt-0.5 flex-shrink-0 text-muted-foreground" />
+ <div className="flex-1 min-w-0">
+ <p className="text-sm font-medium truncate">{uploadFile.file.name}</p>
+ <div className="flex items-center gap-2 mt-1">
+ <span className="text-xs text-muted-foreground">
+ {formatFileSize(uploadFile.file.size)}
+ </span>
+ <span className="text-xs">
+ {uploadFile.status === 'pending' && 'Waiting...'}
+ {uploadFile.status === 'uploading' && 'Uploading...'}
+ {uploadFile.status === 'processing' && 'Processing...'}
+ {uploadFile.status === 'completed' && (
+ <span className="text-green-600 font-medium">✓ Complete</span>
+ )}
+ {uploadFile.status === 'error' && (
+ <span className="text-red-600 font-medium">✗ {uploadFile.error}</span>
+ )}
+ </span>
+ </div>
+ {(uploadFile.status === 'uploading' || uploadFile.status === 'processing') && (
+ <Progress value={uploadFile.progress} className="h-1.5 mt-2" />
)}
</div>
- {(uploadFile.status === 'uploading' || uploadFile.status === 'processing') && (
- <Progress value={uploadFile.progress} className="h-1 mt-1" />
+ {uploadFile.status === 'error' && (
+ <Button
+ size="sm"
+ variant="ghost"
+ onClick={() => {
+ setUploadingFiles(prev =>
+ prev.filter((_, i) => i !== index)
+ );
+ }}
+ >
+ <X className="h-4 w-4" />
+ </Button>
)}
- </FileListDescription>
- </FileListInfo>
- <FileListAction>
- {uploadFile.status === 'error' && (
- <Button
- size="sm"
- variant="ghost"
- onClick={() => {
- setUploadingFiles(prev =>
- prev.filter((_, i) => i !== index)
- );
- }}
- >
- <X className="h-4 w-4" />
- </Button>
- )}
- </FileListAction>
- </FileListItem>
- ))}
- </FileList>
- )}
- </div>
+ </div>
+ ))}
+ </div>
+ </div>
+ )}
+ </div>
+ </ScrollArea>
- <DialogFooter>
+ <DialogFooter className="mt-4">
<Button
variant="outline"
onClick={() => {
@@ -1491,131 +1375,6 @@ export function FileManager({ projectId }: FileManagerProps) {
</DialogContent>
</Dialog>
- {/* File Share Dialog */}
- <Dialog open={shareDialogOpen} onOpenChange={setShareDialogOpen}>
- <DialogContent className="max-w-md">
- <DialogHeader>
- <DialogTitle>Share File</DialogTitle>
- <DialogDescription>
- Sharing {selectedFile?.name}.
- </DialogDescription>
- </DialogHeader>
-
- <Tabs defaultValue="link" className="w-full">
- <TabsList className="grid w-full grid-cols-2">
- <TabsTrigger value="link">Link Sharing</TabsTrigger>
- <TabsTrigger value="permission">Permission Settings</TabsTrigger>
- </TabsList>
-
- <TabsContent value="link" className="space-y-4">
- <div>
- <Label htmlFor="access-level">Access Level</Label>
- <Select
- value={shareSettings.accessLevel}
- onValueChange={(value) => setShareSettings({ ...shareSettings, accessLevel: value })}
- >
- <SelectTrigger>
- <SelectValue />
- </SelectTrigger>
- <SelectContent>
- <SelectItem value="view_only">
- <div className="flex items-center">
- <Eye className="h-4 w-4 mr-2" />
- View Only
- </div>
- </SelectItem>
- <SelectItem value="view_download">
- <div className="flex items-center">
- <Download className="h-4 w-4 mr-2" />
- View + Download
- </div>
- </SelectItem>
- </SelectContent>
- </Select>
- </div>
-
- <div>
- <Label htmlFor="password">Password (Optional)</Label>
- <Input
- id="password"
- type="password"
- value={shareSettings.password}
- onChange={(e) => setShareSettings({ ...shareSettings, password: e.target.value })}
- placeholder="Enter password"
- />
- </div>
-
- <div>
- <Label htmlFor="expires">Expiry Date (Optional)</Label>
- <Input
- id="expires"
- type="datetime-local"
- value={shareSettings.expiresAt}
- onChange={(e) => setShareSettings({ ...shareSettings, expiresAt: e.target.value })}
- />
- </div>
-
- <div>
- <Label htmlFor="max-downloads">Max Downloads (Optional)</Label>
- <Input
- id="max-downloads"
- type="number"
- value={shareSettings.maxDownloads}
- onChange={(e) => setShareSettings({ ...shareSettings, maxDownloads: e.target.value })}
- placeholder="Unlimited"
- />
- </div>
- </TabsContent>
-
- <TabsContent value="permission" className="space-y-4">
- <div>
- <Label htmlFor="target-domain">Target Domain</Label>
- <Select>
- <SelectTrigger>
- <SelectValue placeholder="Select domain" />
- </SelectTrigger>
- <SelectContent>
- <SelectItem value="partners">Partners</SelectItem>
- <SelectItem value="internal">Internal</SelectItem>
- </SelectContent>
- </Select>
- </div>
-
- <div className="space-y-2">
- <Label>Permissions</Label>
- <div className="space-y-2">
- <div className="flex items-center justify-between">
- <Label htmlFor="can-view" className="text-sm font-normal">View</Label>
- <Switch id="can-view" defaultChecked />
- </div>
- <div className="flex items-center justify-between">
- <Label htmlFor="can-download" className="text-sm font-normal">Download</Label>
- <Switch id="can-download" />
- </div>
- <div className="flex items-center justify-between">
- <Label htmlFor="can-edit" className="text-sm font-normal">Edit</Label>
- <Switch id="can-edit" />
- </div>
- <div className="flex items-center justify-between">
- <Label htmlFor="can-share" className="text-sm font-normal">Share</Label>
- <Switch id="can-share" />
- </div>
- </div>
- </div>
- </TabsContent>
- </Tabs>
-
- <DialogFooter>
- <Button variant="outline" onClick={() => setShareDialogOpen(false)}>
- Cancel
- </Button>
- <Button onClick={shareFile}>
- <Share2 className="h-4 w-4 mr-2" />
- Create Share Link
- </Button>
- </DialogFooter>
- </DialogContent>
- </Dialog>
{/* Rename Dialog */}
<Dialog open={renameDialogOpen} onOpenChange={setRenameDialogOpen}>