forked from VinokurovVE/tests
Disable dev pages; FolderViewer table view; CustomTable type safety;
This commit is contained in:
@ -32,7 +32,7 @@ const CustomTable = () => {
|
|||||||
{ id: 2, name: 'Jane Smith', age: 30 },
|
{ id: 2, name: 'Jane Smith', age: 30 },
|
||||||
{ id: 3, name: 'Sam Green', age: 22 },
|
{ id: 3, name: 'Sam Green', age: 22 },
|
||||||
]);
|
]);
|
||||||
const [editingCell, setEditingCell] = useState({ rowIndex: null, columnId: null });
|
const [editingCell, setEditingCell] = useState<{ rowIndex: string | number | null, columnId: string | number | null }>({ rowIndex: null, columnId: null });
|
||||||
|
|
||||||
const tableColumns = useMemo<ColumnDef<typeof data[0]>[]>(() => columns, []);
|
const tableColumns = useMemo<ColumnDef<typeof data[0]>[]>(() => columns, []);
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ const CustomTable = () => {
|
|||||||
value: DataType[keyof DataType]
|
value: DataType[keyof DataType]
|
||||||
) => {
|
) => {
|
||||||
const updatedData = [...data];
|
const updatedData = [...data];
|
||||||
updatedData[rowIndex][columnId] = value;
|
(updatedData[rowIndex][columnId] as DataType[keyof DataType]) = value;
|
||||||
setData(updatedData);
|
setData(updatedData);
|
||||||
//setEditingCell({ rowIndex: null, columnId: null });
|
//setEditingCell({ rowIndex: null, columnId: null });
|
||||||
};
|
};
|
||||||
@ -90,8 +90,8 @@ const CustomTable = () => {
|
|||||||
{isEditing ? (
|
{isEditing ? (
|
||||||
<Input
|
<Input
|
||||||
type='text'
|
type='text'
|
||||||
value={data[rowIndex][cell.column.id]}
|
value={data[rowIndex][cell.column.id as keyof DataType]}
|
||||||
onChange={(e) => handleEditCell(rowIndex, cell.column.id, e.target.value)}
|
onChange={(e) => handleEditCell(rowIndex, (cell.column.id as keyof DataType), e.target.value)}
|
||||||
onBlur={() => setEditingCell({ rowIndex: null, columnId: null })}
|
onBlur={() => setEditingCell({ rowIndex: null, columnId: null })}
|
||||||
autoFocus
|
autoFocus
|
||||||
/>
|
/>
|
||||||
|
@ -4,19 +4,11 @@ import React, { useEffect, useState } from 'react'
|
|||||||
import DocumentService from '../services/DocumentService'
|
import DocumentService from '../services/DocumentService'
|
||||||
import { mutate } from 'swr'
|
import { mutate } from 'swr'
|
||||||
import FileViewer from './modals/FileViewer'
|
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'
|
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 {
|
interface DocumentProps {
|
||||||
doc: IDocument;
|
doc: IDocument;
|
||||||
index: number;
|
|
||||||
handleDocumentClick: (index: number) => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const FileItemStyle: MantineStyleProp = {
|
const FileItemStyle: MantineStyleProp = {
|
||||||
@ -29,22 +21,6 @@ const FileItemStyle: MantineStyleProp = {
|
|||||||
padding: '8px'
|
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 handleSave = async (file: Blob, filename: string) => {
|
||||||
const link = document.createElement('a')
|
const link = document.createElement('a')
|
||||||
link.href = window.URL.createObjectURL(file)
|
link.href = window.URL.createObjectURL(file)
|
||||||
@ -54,7 +30,7 @@ const handleSave = async (file: Blob, filename: string) => {
|
|||||||
window.URL.revokeObjectURL(link.href)
|
window.URL.revokeObjectURL(link.href)
|
||||||
}
|
}
|
||||||
|
|
||||||
function ItemDocument({ doc, index, handleDocumentClick, ...props }: DocumentProps) {
|
function ItemDocument({ doc }: DocumentProps) {
|
||||||
const [shouldFetch, setShouldFetch] = useState(false)
|
const [shouldFetch, setShouldFetch] = useState(false)
|
||||||
|
|
||||||
const { file, isLoading } = useDownload(shouldFetch ? doc?.document_folder_id : null, shouldFetch ? doc?.id : null)
|
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)
|
setShouldFetch(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [shouldFetch, file])
|
}, [shouldFetch, file, doc.name])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex align='center'>
|
<Flex>
|
||||||
<Flex
|
<ActionIcon
|
||||||
style={FileItemStyle}
|
onClick={(e) => {
|
||||||
onClick={() => handleDocumentClick(index)}
|
e.stopPropagation()
|
||||||
{...props}
|
if (!isLoading) {
|
||||||
>
|
setShouldFetch(true)
|
||||||
<IconFileFilled />
|
|
||||||
{doc.name}
|
|
||||||
</Flex>
|
|
||||||
<Flex>
|
|
||||||
<ActionIcon
|
|
||||||
onClick={() => {
|
|
||||||
if (!isLoading) {
|
|
||||||
setShouldFetch(true)
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
variant='subtle'>
|
|
||||||
{isLoading ?
|
|
||||||
<Loader size='sm' />
|
|
||||||
:
|
|
||||||
<IconDownload />
|
|
||||||
}
|
}
|
||||||
</ActionIcon>
|
}}
|
||||||
</Flex>
|
variant='subtle'>
|
||||||
|
{isLoading ?
|
||||||
|
<Loader size='sm' />
|
||||||
|
:
|
||||||
|
<IconDownload />
|
||||||
|
}
|
||||||
|
</ActionIcon>
|
||||||
</Flex>
|
</Flex>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -175,133 +142,151 @@ export default function FolderViewer() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollAreaAutosize w={'100%'} h={'100%'} p={'sm'}>
|
<ScrollAreaAutosize w={'100%'} h={'100%'} p={'sm'}>
|
||||||
<FileViewer
|
{fileViewerModal &&
|
||||||
open={fileViewerModal}
|
<FileViewer
|
||||||
setOpen={setFileViewerModal}
|
open={fileViewerModal}
|
||||||
currentFileNo={currentFileNo}
|
setOpen={setFileViewerModal}
|
||||||
setCurrentFileNo={setCurrentFileNo}
|
currentFileNo={currentFileNo}
|
||||||
docs={documents}
|
setCurrentFileNo={setCurrentFileNo}
|
||||||
/>
|
docs={documents}
|
||||||
|
/>
|
||||||
<Breadcrumbs>
|
|
||||||
<Anchor
|
|
||||||
onClick={() => {
|
|
||||||
setCurrentFolder(null)
|
|
||||||
setBreadcrumbs([])
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Главная
|
|
||||||
</Anchor>
|
|
||||||
{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>
|
|
||||||
|
|
||||||
{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>
|
|
||||||
|
|
||||||
<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>
|
|
||||||
|
|
||||||
<ActionIcon onClick={() => {
|
|
||||||
setFilesToUpload(prev => {
|
|
||||||
return prev.filter((_, i) => i != index)
|
|
||||||
})
|
|
||||||
}} ml='auto' variant='subtle'>
|
|
||||||
<IconX />
|
|
||||||
</ActionIcon>
|
|
||||||
</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>
|
<Stack>
|
||||||
</Table.Thead>
|
<Breadcrumbs>
|
||||||
|
<Anchor
|
||||||
|
onClick={() => {
|
||||||
|
setCurrentFolder(null)
|
||||||
|
setBreadcrumbs([])
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Главная
|
||||||
|
</Anchor>
|
||||||
|
{breadcrumbs.map((breadcrumb, index) => (
|
||||||
|
<Anchor
|
||||||
|
key={breadcrumb.id}
|
||||||
|
onClick={() => handleBreadcrumbClick(index)}
|
||||||
|
>
|
||||||
|
{breadcrumb.name}
|
||||||
|
</Anchor>
|
||||||
|
))}
|
||||||
|
</Breadcrumbs>
|
||||||
|
|
||||||
<Table.Tbody>
|
{currentFolder &&
|
||||||
{currentFolder ? (
|
<Flex direction='column' gap='sm'>
|
||||||
documents?.map((doc: IDocument, index: number) => (
|
<Flex direction='column' gap='sm' p='sm' style={{
|
||||||
<Table.Tr key={doc.id}>
|
border: filesToUpload.length > 0 ? '1px dashed gray' : 'none',
|
||||||
<Table.Td>
|
borderRadius: '8px',
|
||||||
<ItemDocument
|
}}>
|
||||||
doc={doc}
|
<Flex gap='sm'>
|
||||||
index={index}
|
<FileButton multiple onChange={handleFileInput}>
|
||||||
handleDocumentClick={handleDocumentClick}
|
{(props) => <Button variant='filled' leftSection={isUploading ? <Loader /> : <IconFilePlus />} {...props}>Добавить</Button>}
|
||||||
/>
|
</FileButton>
|
||||||
</Table.Td>
|
|
||||||
</Table.Tr>
|
{filesToUpload.length > 0 &&
|
||||||
))
|
<>
|
||||||
) : (
|
<Button
|
||||||
folders?.map((folder: IDocumentFolder, index: number) => (
|
variant='filled'
|
||||||
<Table.Tr key={folder.id}>
|
leftSection={isUploading ? <RingProgress sections={[{ value: uploadProgress, color: 'blue' }]} /> : <IconFileUpload />}
|
||||||
<Table.Td>
|
onClick={uploadFiles}
|
||||||
<ItemFolder
|
>
|
||||||
folder={folder}
|
Загрузить все
|
||||||
index={index}
|
</Button>
|
||||||
handleFolderClick={handleFolderClick}
|
|
||||||
/>
|
<Button
|
||||||
</Table.Td>
|
variant='outline'
|
||||||
</Table.Tr>
|
leftSection={<IconCancel />}
|
||||||
))
|
onClick={() => {
|
||||||
)}
|
setFilesToUpload([])
|
||||||
</Table.Tbody>
|
}}
|
||||||
</Table>
|
>
|
||||||
|
Отмена
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
|
||||||
|
<ActionIcon onClick={() => {
|
||||||
|
setFilesToUpload(prev => {
|
||||||
|
return prev.filter((_, i) => i != index)
|
||||||
|
})
|
||||||
|
}} ml='auto' variant='subtle'>
|
||||||
|
<IconX />
|
||||||
|
</ActionIcon>
|
||||||
|
</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.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} 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>
|
</ScrollAreaAutosize>
|
||||||
)
|
)
|
||||||
}
|
}
|
@ -133,7 +133,7 @@ const pages = [
|
|||||||
component: <MonitorPage />,
|
component: <MonitorPage />,
|
||||||
drawer: true,
|
drawer: true,
|
||||||
dashboard: true,
|
dashboard: true,
|
||||||
enabled: true,
|
enabled: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Table test",
|
label: "Table test",
|
||||||
@ -142,7 +142,7 @@ const pages = [
|
|||||||
component: <TableTest />,
|
component: <TableTest />,
|
||||||
drawer: true,
|
drawer: true,
|
||||||
dashboard: true,
|
dashboard: true,
|
||||||
enabled: true,
|
enabled: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Component test",
|
label: "Component test",
|
||||||
@ -151,7 +151,7 @@ const pages = [
|
|||||||
component: <ComponentTest />,
|
component: <ComponentTest />,
|
||||||
drawer: true,
|
drawer: true,
|
||||||
dashboard: true,
|
dashboard: true,
|
||||||
enabled: true,
|
enabled: false,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user