|
|
@ -4,19 +4,11 @@ import React, { useEffect, useState } from 'react' |
|
|
|
import DocumentService from '../services/DocumentService' |
|
|
|
import { mutate } from 'swr' |
|
|
|
import FileViewer from './modals/FileViewer' |
|
|
|
import { ActionIcon, Anchor, Breadcrumbs, Button, Divider, FileButton, Flex, Loader, MantineStyleProp, RingProgress, ScrollAreaAutosize, Table, Text } from '@mantine/core' |
|
|
|
import { ActionIcon, Anchor, Breadcrumbs, Button, Divider, FileButton, Flex, Loader, MantineStyleProp, RingProgress, ScrollAreaAutosize, Stack, Table, Text } from '@mantine/core' |
|
|
|
import { IconCancel, IconDownload, IconFile, IconFileFilled, IconFilePlus, IconFileUpload, IconFolderFilled, IconX } from '@tabler/icons-react' |
|
|
|
|
|
|
|
interface FolderProps { |
|
|
|
folder: IDocumentFolder; |
|
|
|
index: number; |
|
|
|
handleFolderClick: (folder: IDocumentFolder) => void; |
|
|
|
} |
|
|
|
|
|
|
|
interface DocumentProps { |
|
|
|
doc: IDocument; |
|
|
|
index: number; |
|
|
|
handleDocumentClick: (index: number) => void; |
|
|
|
} |
|
|
|
|
|
|
|
const FileItemStyle: MantineStyleProp = { |
|
|
@ -29,22 +21,6 @@ const FileItemStyle: MantineStyleProp = { |
|
|
|
padding: '8px' |
|
|
|
} |
|
|
|
|
|
|
|
function ItemFolder({ folder, handleFolderClick, ...props }: FolderProps) { |
|
|
|
return ( |
|
|
|
<Flex |
|
|
|
onClick={() => handleFolderClick(folder)} |
|
|
|
> |
|
|
|
<Flex |
|
|
|
style={FileItemStyle} |
|
|
|
{...props} |
|
|
|
> |
|
|
|
<IconFolderFilled /> |
|
|
|
{folder.name} |
|
|
|
</Flex> |
|
|
|
</Flex> |
|
|
|
) |
|
|
|
} |
|
|
|
|
|
|
|
const handleSave = async (file: Blob, filename: string) => { |
|
|
|
const link = document.createElement('a') |
|
|
|
link.href = window.URL.createObjectURL(file) |
|
|
@ -54,7 +30,7 @@ const handleSave = async (file: Blob, filename: string) => { |
|
|
|
window.URL.revokeObjectURL(link.href) |
|
|
|
} |
|
|
|
|
|
|
|
function ItemDocument({ doc, index, handleDocumentClick, ...props }: DocumentProps) { |
|
|
|
function ItemDocument({ doc }: DocumentProps) { |
|
|
|
const [shouldFetch, setShouldFetch] = useState(false) |
|
|
|
|
|
|
|
const { file, isLoading } = useDownload(shouldFetch ? doc?.document_folder_id : null, shouldFetch ? doc?.id : null) |
|
|
@ -66,33 +42,24 @@ function ItemDocument({ doc, index, handleDocumentClick, ...props }: DocumentPro |
|
|
|
setShouldFetch(false) |
|
|
|
} |
|
|
|
} |
|
|
|
}, [shouldFetch, file]) |
|
|
|
}, [shouldFetch, file, doc.name]) |
|
|
|
|
|
|
|
return ( |
|
|
|
<Flex align='center'> |
|
|
|
<Flex |
|
|
|
style={FileItemStyle} |
|
|
|
onClick={() => handleDocumentClick(index)} |
|
|
|
{...props} |
|
|
|
> |
|
|
|
<IconFileFilled /> |
|
|
|
{doc.name} |
|
|
|
</Flex> |
|
|
|
<Flex> |
|
|
|
<ActionIcon |
|
|
|
onClick={() => { |
|
|
|
if (!isLoading) { |
|
|
|
setShouldFetch(true) |
|
|
|
} |
|
|
|
}} |
|
|
|
variant='subtle'> |
|
|
|
{isLoading ? |
|
|
|
<Loader size='sm' /> |
|
|
|
: |
|
|
|
<IconDownload /> |
|
|
|
<Flex> |
|
|
|
<ActionIcon |
|
|
|
onClick={(e) => { |
|
|
|
e.stopPropagation() |
|
|
|
if (!isLoading) { |
|
|
|
setShouldFetch(true) |
|
|
|
} |
|
|
|
</ActionIcon> |
|
|
|
</Flex> |
|
|
|
}} |
|
|
|
variant='subtle'> |
|
|
|
{isLoading ? |
|
|
|
<Loader size='sm' /> |
|
|
|
: |
|
|
|
<IconDownload /> |
|
|
|
} |
|
|
|
</ActionIcon> |
|
|
|
</Flex> |
|
|
|
) |
|
|
|
} |
|
|
@ -175,133 +142,151 @@ export default function FolderViewer() { |
|
|
|
|
|
|
|
return ( |
|
|
|
<ScrollAreaAutosize w={'100%'} h={'100%'} p={'sm'}> |
|
|
|
<FileViewer |
|
|
|
open={fileViewerModal} |
|
|
|
setOpen={setFileViewerModal} |
|
|
|
currentFileNo={currentFileNo} |
|
|
|
setCurrentFileNo={setCurrentFileNo} |
|
|
|
docs={documents} |
|
|
|
/> |
|
|
|
{fileViewerModal && |
|
|
|
<FileViewer |
|
|
|
open={fileViewerModal} |
|
|
|
setOpen={setFileViewerModal} |
|
|
|
currentFileNo={currentFileNo} |
|
|
|
setCurrentFileNo={setCurrentFileNo} |
|
|
|
docs={documents} |
|
|
|
/> |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
<Breadcrumbs> |
|
|
|
<Anchor |
|
|
|
onClick={() => { |
|
|
|
setCurrentFolder(null) |
|
|
|
setBreadcrumbs([]) |
|
|
|
}} |
|
|
|
> |
|
|
|
Главная |
|
|
|
</Anchor> |
|
|
|
{breadcrumbs.map((breadcrumb, index) => ( |
|
|
|
<Stack> |
|
|
|
<Breadcrumbs> |
|
|
|
<Anchor |
|
|
|
key={breadcrumb.id} |
|
|
|
onClick={() => handleBreadcrumbClick(index)} |
|
|
|
onClick={() => { |
|
|
|
setCurrentFolder(null) |
|
|
|
setBreadcrumbs([]) |
|
|
|
}} |
|
|
|
> |
|
|
|
{breadcrumb.name} |
|
|
|
Главная |
|
|
|
</Anchor> |
|
|
|
))} |
|
|
|
</Breadcrumbs> |
|
|
|
{breadcrumbs.map((breadcrumb, index) => ( |
|
|
|
<Anchor |
|
|
|
key={breadcrumb.id} |
|
|
|
onClick={() => handleBreadcrumbClick(index)} |
|
|
|
> |
|
|
|
{breadcrumb.name} |
|
|
|
</Anchor> |
|
|
|
))} |
|
|
|
</Breadcrumbs> |
|
|
|
|
|
|
|
{currentFolder && |
|
|
|
<Flex direction='column' gap='sm'> |
|
|
|
<Flex direction='column' gap='sm' p='sm' style={{ |
|
|
|
border: filesToUpload.length > 0 ? '1px dashed gray' : 'none', |
|
|
|
borderRadius: '8px', |
|
|
|
}}> |
|
|
|
<Flex gap='sm'> |
|
|
|
<FileButton multiple onChange={handleFileInput}> |
|
|
|
{(props) => <Button variant='filled' leftSection={isUploading ? <Loader /> : <IconFilePlus />} {...props}>Добавить</Button>} |
|
|
|
</FileButton> |
|
|
|
{currentFolder && |
|
|
|
<Flex direction='column' gap='sm'> |
|
|
|
<Flex direction='column' gap='sm' p='sm' style={{ |
|
|
|
border: filesToUpload.length > 0 ? '1px dashed gray' : 'none', |
|
|
|
borderRadius: '8px', |
|
|
|
}}> |
|
|
|
<Flex gap='sm'> |
|
|
|
<FileButton multiple onChange={handleFileInput}> |
|
|
|
{(props) => <Button variant='filled' leftSection={isUploading ? <Loader /> : <IconFilePlus />} {...props}>Добавить</Button>} |
|
|
|
</FileButton> |
|
|
|
|
|
|
|
{filesToUpload.length > 0 && |
|
|
|
<> |
|
|
|
<Button |
|
|
|
variant='filled' |
|
|
|
leftSection={isUploading ? <RingProgress sections={[{ value: uploadProgress, color: 'blue' }]} /> : <IconFileUpload />} |
|
|
|
onClick={uploadFiles} |
|
|
|
> |
|
|
|
Загрузить все |
|
|
|
</Button> |
|
|
|
{filesToUpload.length > 0 && |
|
|
|
<> |
|
|
|
<Button |
|
|
|
variant='filled' |
|
|
|
leftSection={isUploading ? <RingProgress sections={[{ value: uploadProgress, color: 'blue' }]} /> : <IconFileUpload />} |
|
|
|
onClick={uploadFiles} |
|
|
|
> |
|
|
|
Загрузить все |
|
|
|
</Button> |
|
|
|
|
|
|
|
<Button |
|
|
|
variant='outline' |
|
|
|
leftSection={<IconCancel />} |
|
|
|
onClick={() => { |
|
|
|
setFilesToUpload([]) |
|
|
|
}} |
|
|
|
> |
|
|
|
Отмена |
|
|
|
</Button> |
|
|
|
</> |
|
|
|
} |
|
|
|
</Flex> |
|
|
|
<Button |
|
|
|
variant='outline' |
|
|
|
leftSection={<IconCancel />} |
|
|
|
onClick={() => { |
|
|
|
setFilesToUpload([]) |
|
|
|
}} |
|
|
|
> |
|
|
|
Отмена |
|
|
|
</Button> |
|
|
|
</> |
|
|
|
} |
|
|
|
</Flex> |
|
|
|
|
|
|
|
<Divider /> |
|
|
|
<Divider /> |
|
|
|
|
|
|
|
{filesToUpload.length > 0 && |
|
|
|
<Flex direction='column'> |
|
|
|
{filesToUpload.map((file, index) => ( |
|
|
|
<Flex key={index} p='8px'> |
|
|
|
<Flex gap='sm' direction='row' align='center'> |
|
|
|
<IconFile /> |
|
|
|
<Text>{file.name}</Text> |
|
|
|
</Flex> |
|
|
|
{filesToUpload.length > 0 && |
|
|
|
<Flex direction='column'> |
|
|
|
{filesToUpload.map((file, index) => ( |
|
|
|
<Flex key={index} p='8px'> |
|
|
|
<Flex gap='sm' direction='row' align='center'> |
|
|
|
<IconFile /> |
|
|
|
<Text>{file.name}</Text> |
|
|
|
</Flex> |
|
|
|
|
|
|
|
<ActionIcon onClick={() => { |
|
|
|
setFilesToUpload(prev => { |
|
|
|
return prev.filter((_, i) => i != index) |
|
|
|
}) |
|
|
|
}} ml='auto' variant='subtle'> |
|
|
|
<IconX /> |
|
|
|
</ActionIcon> |
|
|
|
</Flex> |
|
|
|
))} |
|
|
|
</Flex> |
|
|
|
} |
|
|
|
<ActionIcon onClick={() => { |
|
|
|
setFilesToUpload(prev => { |
|
|
|
return prev.filter((_, i) => i != index) |
|
|
|
}) |
|
|
|
}} ml='auto' variant='subtle'> |
|
|
|
<IconX /> |
|
|
|
</ActionIcon> |
|
|
|
</Flex> |
|
|
|
))} |
|
|
|
</Flex> |
|
|
|
} |
|
|
|
</Flex> |
|
|
|
</Flex> |
|
|
|
</Flex> |
|
|
|
} |
|
|
|
|
|
|
|
<Table |
|
|
|
onDragOver={handleDragOver} |
|
|
|
onDragLeave={handleDragLeave} |
|
|
|
onDrop={handleDrop} |
|
|
|
bg={dragOver ? 'rgba(0, 0, 0, 0.1)' : 'inherit'} |
|
|
|
highlightOnHover> |
|
|
|
<Table.Thead> |
|
|
|
<Table.Tr> |
|
|
|
} |
|
|
|
|
|
|
|
</Table.Tr> |
|
|
|
</Table.Thead> |
|
|
|
<Table |
|
|
|
onDragOver={handleDragOver} |
|
|
|
onDragLeave={handleDragLeave} |
|
|
|
onDrop={handleDrop} |
|
|
|
bg={dragOver ? 'rgba(0, 0, 0, 0.1)' : 'inherit'} |
|
|
|
highlightOnHover> |
|
|
|
<Table.Thead> |
|
|
|
<Table.Tr> |
|
|
|
<Table.Th>Название</Table.Th> |
|
|
|
<Table.Th p={0}>Дата создания</Table.Th> |
|
|
|
<Table.Th p={0}></Table.Th> |
|
|
|
</Table.Tr> |
|
|
|
</Table.Thead> |
|
|
|
|
|
|
|
<Table.Tbody> |
|
|
|
{currentFolder ? ( |
|
|
|
documents?.map((doc: IDocument, index: number) => ( |
|
|
|
<Table.Tr key={doc.id}> |
|
|
|
<Table.Td> |
|
|
|
<ItemDocument |
|
|
|
doc={doc} |
|
|
|
index={index} |
|
|
|
handleDocumentClick={handleDocumentClick} |
|
|
|
/> |
|
|
|
</Table.Td> |
|
|
|
</Table.Tr> |
|
|
|
)) |
|
|
|
) : ( |
|
|
|
folders?.map((folder: IDocumentFolder, index: number) => ( |
|
|
|
<Table.Tr key={folder.id}> |
|
|
|
<Table.Td> |
|
|
|
<ItemFolder |
|
|
|
folder={folder} |
|
|
|
index={index} |
|
|
|
handleFolderClick={handleFolderClick} |
|
|
|
/> |
|
|
|
</Table.Td> |
|
|
|
</Table.Tr> |
|
|
|
)) |
|
|
|
)} |
|
|
|
</Table.Tbody> |
|
|
|
</Table> |
|
|
|
<Table.Tbody> |
|
|
|
{currentFolder ? ( |
|
|
|
documents?.map((doc: IDocument, index: number) => ( |
|
|
|
<Table.Tr key={doc.id} onClick={() => handleDocumentClick(index)} style={{ cursor: 'pointer' }}> |
|
|
|
<Table.Td p={0}> |
|
|
|
<Flex style={FileItemStyle}> |
|
|
|
<IconFileFilled /> |
|
|
|
{doc.name} |
|
|
|
</Flex> |
|
|
|
</Table.Td> |
|
|
|
<Table.Td p={0}> |
|
|
|
{new Date(doc.create_date).toLocaleDateString()} |
|
|
|
</Table.Td> |
|
|
|
<Table.Td p={0}> |
|
|
|
<ItemDocument |
|
|
|
doc={doc} |
|
|
|
/> |
|
|
|
</Table.Td> |
|
|
|
</Table.Tr> |
|
|
|
)) |
|
|
|
) : ( |
|
|
|
folders?.map((folder: IDocumentFolder) => ( |
|
|
|
<Table.Tr key={folder.id} onClick={() => handleFolderClick(folder)} style={{ cursor: 'pointer' }}> |
|
|
|
<Table.Td p={0}> |
|
|
|
<Flex style={FileItemStyle}> |
|
|
|
<IconFolderFilled /> |
|
|
|
{folder.name} |
|
|
|
</Flex> |
|
|
|
</Table.Td> |
|
|
|
<Table.Td p={0} align='left'> |
|
|
|
{new Date(folder.create_date).toLocaleDateString()} |
|
|
|
</Table.Td> |
|
|
|
<Table.Td p={0}> |
|
|
|
</Table.Td> |
|
|
|
</Table.Tr> |
|
|
|
)) |
|
|
|
)} |
|
|
|
</Table.Tbody> |
|
|
|
</Table> |
|
|
|
</Stack> |
|
|
|
</ScrollAreaAutosize> |
|
|
|
) |
|
|
|
} |